1/*
2   GormViewKnobs.m
3
4   Copyright (C) 1999 Free Software Foundation, Inc.
5
6   Author:  Gerrit van Dyk <gerritvd@decimax.com>
7   Date: 1999
8   Modified and extended by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
9
10   This file is part of the GNUstep Interface Modeller Application.
11
12   This library is free software; you can redistribute it and/or
13   modify it under the terms of the GNU Library General Public
14   License as published by the Free Software Foundation; either
15   version 3 of the License, or (at your option) any later version.
16
17   This library is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20   Library General Public License for more details.
21
22   You should have received a copy of the GNU Library General Public
23   License along with this library; see the file COPYING.LIB.
24   If not, write to the Free Software Foundation,
25   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26*/
27
28#include "GormViewKnobs.h"
29#include <math.h>
30
31static NSInteger KNOB_WIDTH = 0.0;
32static NSInteger KNOB_HEIGHT = 0.0;
33
34#define MINSIZE 5.0
35
36static NSRect	*blackRectList	= NULL;
37static int	blackRectSize	= 0;
38static int	blackRectCount	= 0;
39static NSRect	*fgcolorRectList= NULL;
40static int	fgcolorRectSize	= 0;
41static int	fgcolorRectCount= 0;
42
43static void _fastKnobFill(NSRect aRect,BOOL isBlack);
44static void _drawKnobsForRect(NSRect aRect,BOOL isBlack);
45
46static void
47calcKnobSize(void)
48{
49  NSString	*value;
50  float		w = 2.0;
51  float		h = 2.0;
52
53  value = [[NSUserDefaults standardUserDefaults] objectForKey: @"KnobWidth"];
54  if (value != nil)
55    {
56      w = floor([value floatValue] / 2.0);
57    }
58  value = [[NSUserDefaults standardUserDefaults] objectForKey: @"KnobHeight"];
59  if (value != nil)
60    {
61      h = floor([value floatValue] / 2.0);
62    }
63  w = MAX(w, 1.0);
64  h = MAX(h, 1.0);
65  KNOB_WIDTH = w * 2.0 + 1.0; // Size must be odd */
66  KNOB_HEIGHT = h * 2.0 + 1.0;
67}
68
69void
70GormShowFastKnobFills(void)
71{
72  if (blackRectCount)
73    {
74      [[NSColor blackColor] set];
75      NSRectFillList(blackRectList, blackRectCount);
76    }
77  if (fgcolorRectCount)
78    {
79      [[NSColor redColor] set];
80      NSRectFillList(fgcolorRectList, fgcolorRectCount);
81    }
82  blackRectCount = 0;
83  fgcolorRectCount = 0;
84}
85
86static void
87_showLitKnobForRect(NSRect frame, IBKnobPosition aKnob)
88{
89  float		dx, dy;
90  BOOL		oddx, oddy;
91  NSRect	r;
92
93  if (!KNOB_WIDTH)
94    {
95      calcKnobSize();
96    }
97  dx = NSWidth(frame) / 2.0;
98  dy = NSHeight(frame) / 2.0;
99  oddx = (floor(dx) != dx);
100  oddy = (floor(dy) != dy);
101  frame.size.width = KNOB_WIDTH;
102  frame.size.height = KNOB_HEIGHT;
103  frame.origin.x -= ((KNOB_WIDTH - 1.0) / 2.0);
104  frame.origin.y -= ((KNOB_HEIGHT - 1.0) / 2.0);
105
106  // Initialize r to keep the compiler happy
107  r = frame;
108
109  if (aKnob == IBBottomLeftKnobPosition)
110    r = frame;
111  frame.origin.y += dy;
112  if (oddy)
113    frame.origin.y -= 0.5;
114  if (aKnob == IBMiddleLeftKnobPosition)
115    r = frame;
116  frame.origin.y += dy;
117  if (oddy)
118    frame.origin.y += 0.5;
119  if (aKnob == IBTopLeftKnobPosition)
120    r = frame;
121  frame.origin.x += dx;
122  if (oddx)
123   frame.origin.x -= 0.5;
124  if (aKnob == IBTopMiddleKnobPosition)
125    r = frame;
126  frame.origin.x += dx;
127  if (oddx)
128    frame.origin.x += 0.5;
129  if (aKnob == IBTopRightKnobPosition)
130    r = frame;
131  frame.origin.y -= dy;
132  if (oddy)
133    frame.origin.y -= 0.5;
134  if (aKnob == IBMiddleRightKnobPosition)
135    r = frame;
136  frame.origin.y -= dy;
137  if (oddy)
138    frame.origin.y += 0.5;
139  if (aKnob == IBBottomRightKnobPosition)
140    r = frame;
141  frame.origin.x -= dx;
142  if (oddx)
143    frame.origin.x += 0.5;
144  if (aKnob == IBBottomMiddleKnobPosition)
145    r = frame;
146
147  r.origin.x += 1.0;
148  r.origin.y -= 1.0;
149  [[NSColor blackColor] set];
150  [NSBezierPath fillRect: r];
151  r.origin.x -= 1.0;
152  r.origin.y += 1.0;
153  [[NSColor whiteColor] set];
154  [NSBezierPath fillRect: r];
155}
156
157void
158GormShowFrameWithKnob(NSRect aRect, IBKnobPosition aKnob)
159{
160  NSRect		 r = aRect;
161
162  /*
163   * We draw a wire-frame around the rectangle.
164   */
165  r.origin.x -= 0.5;
166  r.origin.y -= 0.5;
167  r.size.width += 1.0;
168  r.size.height += 1.0;
169  [[NSColor blackColor] set];
170  [NSBezierPath strokeRect: r];
171
172  if (aKnob != IBNoneKnobPosition)
173    {
174      /*
175       * NB. we use the internal rectangle for calculating the knob position.
176       */
177      _showLitKnobForRect(aRect, aKnob);
178    }
179}
180
181void
182GormDrawKnobsForRect(NSRect aRect)
183{
184  NSRect	r;
185
186  r.origin.x = floor(NSMinX(aRect));
187  r.origin.y = floor(NSMinY(aRect));
188  r.size.width = floor(NSMaxX(aRect) + 0.99) - NSMinX(r);
189  r.size.height = floor(NSMaxY(aRect) + 0.99) - NSMinY(r);
190  r.origin.x += 1.0;
191  r.origin.y -= 1.0;
192  _drawKnobsForRect(r, YES);
193  r.origin.x = floor(NSMinX(aRect));
194  r.origin.y = floor(NSMinY(aRect));
195  r.size.width = floor(NSMaxX(aRect) + 0.99) - NSMinX(r);
196  r.size.height = floor(NSMaxY(aRect) + 0.99) - NSMinY(r);
197  _drawKnobsForRect(r, NO);
198}
199
200/* Draw these around an NSBox whose contents are being edited.
201*/
202void
203GormDrawOpenKnobsForRect(NSRect aRect)
204{
205  NSRect	r;
206
207  r.origin.x = floor(NSMinX(aRect));
208  r.origin.y = floor(NSMinY(aRect));
209  r.size.width = floor(NSMaxX(aRect) + 0.99) - NSMinX(r);
210  r.size.height = floor(NSMaxY(aRect) + 0.99) - NSMinY(r);
211  _drawKnobsForRect(r, YES);
212}
213
214IBKnobPosition
215GormKnobHitInRect(NSRect aFrame, NSPoint p)
216{
217  NSRect	eb;
218  NSRect	knob;
219  float		dx, dy;
220  BOOL		oddx, oddy;
221
222  eb = GormExtBoundsForRect(aFrame);
223
224  if (!NSMouseInRect(p, eb, NO))
225    {
226      return IBNoneKnobPosition;
227    }
228  knob = aFrame;
229  dx = NSWidth(knob) / 2.0;
230  dy = NSHeight(knob) / 2.0;
231  oddx = (floor(dx) != dx);
232  oddy = (floor(dy) != dy);
233  knob.size.width = KNOB_WIDTH;
234  knob.size.height = KNOB_HEIGHT;
235  knob.origin.x -= ((KNOB_WIDTH - 1.0) / 2.0);
236  knob.origin.y -= ((KNOB_HEIGHT - 1.0) / 2.0);
237
238  if (NSMouseInRect(p, knob, NO))
239    {
240      return(IBBottomLeftKnobPosition);
241    }
242  knob.origin.y += dy;
243  if (oddy)
244    {
245      knob.origin.y -= 0.5;
246    }
247  if (NSMouseInRect(p, knob, NO))
248    {
249      return(IBMiddleLeftKnobPosition);
250    }
251  knob.origin.y += dy;
252  if (oddy)
253    {
254      knob.origin.y += 0.5;
255    }
256  if (NSMouseInRect(p, knob, NO))
257    {
258      return(IBTopLeftKnobPosition);
259    }
260  knob.origin.x += dx;
261  if (oddx)
262    {
263      knob.origin.x -= 0.5;
264    }
265  if (NSMouseInRect(p, knob, NO))
266    {
267      return(IBTopMiddleKnobPosition);
268    }
269  knob.origin.x += dx;
270  if (oddx)
271    {
272      knob.origin.x += 0.5;
273    }
274  if (NSMouseInRect(p, knob, NO))
275    {
276      return(IBTopRightKnobPosition);
277    }
278  knob.origin.y -= dy;
279  if (oddy)
280    {
281      knob.origin.y -= 0.5;
282    }
283  if (NSMouseInRect(p, knob, NO))
284    {
285      return(IBMiddleRightKnobPosition);
286    }
287  knob.origin.y -= dy;
288  if (oddy)
289    {
290      knob.origin.y += 0.5;
291    }
292  if (NSMouseInRect(p, knob, NO))
293    {
294      return(IBBottomRightKnobPosition);
295    }
296  knob.origin.x -= dx;
297  if (oddx)
298    {
299      knob.origin.x += 0.5;
300    }
301  if (NSMouseInRect(p, knob, NO))
302    {
303      return(IBBottomMiddleKnobPosition);
304    }
305
306  return IBNoneKnobPosition;
307}
308
309NSRect
310GormExtBoundsForRect(NSRect aRect)
311{
312  NSRect returnRect;
313
314  if (NSWidth(aRect) < 0.0)
315    {
316      returnRect.origin.x = NSMaxX(aRect);
317      returnRect.size.width = - NSWidth(aRect);
318    }
319   else
320    {
321      returnRect.origin.x = NSMinX(aRect);
322      returnRect.size.width = NSWidth(aRect);
323    }
324   if (aRect.size.height < 0.0)
325    {
326      returnRect.origin.y = NSMaxY(aRect);
327      returnRect.size.height = - NSHeight(aRect);
328    }
329   else
330    {
331      returnRect.origin.y = NSMinY(aRect);
332      returnRect.size.height = NSHeight(aRect);
333    }
334
335  returnRect.size.width = MAX(1.0, NSWidth(returnRect));
336  returnRect.size.height = MAX(1.0, NSHeight(returnRect));
337
338  returnRect = NSInsetRect(returnRect,
339    - ((KNOB_WIDTH - 1.0) + 1.0), - ((KNOB_HEIGHT - 1.0) + 1.0));
340
341  return NSIntegralRect(returnRect);
342}
343
344static void
345_fastKnobFill(NSRect aRect, BOOL isBlack)
346{
347  if (isBlack)
348    {
349      if (!blackRectList)
350	{
351	   blackRectSize = 16;
352	   blackRectList = NSZoneMalloc(NSDefaultMallocZone(),
353	     blackRectSize * sizeof(NSRect));
354	}
355      else
356	{
357          if (blackRectCount >= blackRectSize)
358            {
359              while (blackRectCount >= blackRectSize)
360                {
361                  blackRectSize <<= 1;
362                }
363              blackRectList = NSZoneRealloc(NSDefaultMallocZone(), blackRectList,
364                                            blackRectSize * sizeof(NSRect));
365            }
366        }
367      blackRectList[blackRectCount++] = aRect;
368    }
369  else
370    {
371      if (!fgcolorRectList)
372	{
373	  fgcolorRectSize = 16;
374	  fgcolorRectList = NSZoneMalloc(NSDefaultMallocZone(),
375	    fgcolorRectSize * sizeof(NSRect));
376	}
377      else
378	{
379	  if (fgcolorRectCount >= fgcolorRectSize)
380	    {
381              while (fgcolorRectCount >= fgcolorRectSize)
382                {
383                  fgcolorRectSize <<= 1;
384                }
385              fgcolorRectList = NSZoneRealloc(NSDefaultMallocZone(), fgcolorRectList,
386                                              fgcolorRectSize * sizeof(NSRect));
387            }
388	}
389      fgcolorRectList[fgcolorRectCount++] = aRect;
390    }
391}
392
393static void
394_drawKnobsForRect(NSRect knob, BOOL isBlack)
395{
396  float		dx, dy;
397  BOOL		oddx, oddy;
398
399  if (!KNOB_WIDTH)
400    {
401      calcKnobSize();
402    }
403  dx = NSWidth(knob) / 2.0;
404  dy = NSHeight(knob) / 2.0;
405  oddx = (floor(dx) != dx);
406  oddy = (floor(dy) != dy);
407  knob.size.width = KNOB_WIDTH;
408  knob.size.height = KNOB_HEIGHT;
409  knob.origin.x -= ((KNOB_WIDTH - 1.0) / 2.0);
410  knob.origin.y -= ((KNOB_HEIGHT - 1.0) / 2.0);
411
412  _fastKnobFill(knob, isBlack);
413  knob.origin.y += dy;
414  if (oddy)
415    {
416      knob.origin.y -= 0.5;
417    }
418  _fastKnobFill(knob, isBlack);
419  knob.origin.y += dy;
420  if (oddy)
421    {
422      knob.origin.y += 0.5;
423    }
424  _fastKnobFill(knob, isBlack);
425  knob.origin.x += dx;
426  if (oddx)
427    {
428     knob.origin.x -= 0.5;
429    }
430  _fastKnobFill(knob, isBlack);
431  knob.origin.x += dx;
432  if (oddx)
433    {
434      knob.origin.x += 0.5;
435    }
436  _fastKnobFill(knob, isBlack);
437  knob.origin.y -= dy;
438  if (oddy)
439    {
440      knob.origin.y -= 0.5;
441    }
442  _fastKnobFill(knob, isBlack);
443  knob.origin.y -= dy;
444  if (oddy)
445    {
446      knob.origin.y += 0.5;
447    }
448  _fastKnobFill(knob, isBlack);
449  knob.origin.x -= dx;
450  if (oddx)
451    {
452      knob.origin.x += 0.5;
453    }
454  _fastKnobFill(knob, isBlack);
455}
456
457