1 /*
2 * tkMacOSXScale.c --
3 *
4 * This file implements the Macintosh specific portion of the
5 * scale widget.
6 *
7 * Copyright © 1996 Sun Microsystems, Inc.
8 * Copyright © 1998-2000 Scriptics Corporation.
9 * Copyright © 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
10 * Copyright © 2008-2009 Apple Inc.
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 */
15
16 #include "tkMacOSXPrivate.h"
17 #include "tkScale.h"
18
19 #ifdef MAC_OSX_TK_TODO
20 /*
21 #ifdef TK_MAC_DEBUG
22 #define TK_MAC_DEBUG_SCALE
23 #endif
24 */
25
26 /*
27 * Defines used in this file.
28 */
29
30 #define slider 1110
31 #define inSlider 1
32 #define inInc 2
33 #define inDecr 3
34
35 /*
36 * Declaration of Macintosh specific scale structure.
37 */
38
39 typedef struct MacScale {
40 TkScale info; /* Generic scale info. */
41 int flags; /* Flags. */
42 ControlRef scaleHandle; /* Handle to the Scale control struct. */
43 } MacScale;
44
45 /*
46 * Globals uses locally in this file.
47 */
48 static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */
49
50 /*
51 * Forward declarations for procedures defined later in this file:
52 */
53
54 static void MacScaleEventProc(ClientData clientData,
55 XEvent *eventPtr);
56 static pascal void ScaleActionProc(ControlRef theControl,
57 ControlPartCode partCode);
58
59 /*
60 *----------------------------------------------------------------------
61 *
62 * TkpCreateScale --
63 *
64 * Allocate a new TkScale structure.
65 *
66 * Results:
67 * Returns a newly allocated TkScale structure.
68 *
69 * Side effects:
70 * None.
71 *
72 *----------------------------------------------------------------------
73 */
74
75 TkScale *
TkpCreateScale(Tk_Window tkwin)76 TkpCreateScale(
77 Tk_Window tkwin)
78 {
79 MacScale *macScalePtr = (MacScale *)ckalloc(sizeof(MacScale));
80
81 macScalePtr->scaleHandle = NULL;
82 if (scaleActionProc == NULL) {
83 scaleActionProc = NewControlActionUPP(ScaleActionProc);
84 }
85
86 Tk_CreateEventHandler(tkwin, ButtonPressMask,
87 MacScaleEventProc, macScalePtr);
88
89 return (TkScale *) macScalePtr;
90 }
91
92 /*
93 *----------------------------------------------------------------------
94 *
95 * TkpDestroyScale --
96 *
97 * Free Macintosh specific resources.
98 *
99 * Results:
100 * None
101 *
102 * Side effects:
103 * The slider control is destroyed.
104 *
105 *----------------------------------------------------------------------
106 */
107
108 void
TkpDestroyScale(TkScale * scalePtr)109 TkpDestroyScale(
110 TkScale *scalePtr)
111 {
112 MacScale *macScalePtr = (MacScale *) scalePtr;
113
114 /*
115 * Free Macintosh control.
116 */
117
118 if (macScalePtr->scaleHandle != NULL) {
119 DisposeControl(macScalePtr->scaleHandle);
120 }
121 }
122
123 /*
124 *----------------------------------------------------------------------
125 *
126 * TkpDisplayScale --
127 *
128 * This procedure is invoked as an idle handler to redisplay the contents
129 * of a scale widget.
130 *
131 * Results:
132 * None.
133 *
134 * Side effects:
135 * The scale gets redisplayed.
136 *
137 *----------------------------------------------------------------------
138 */
139
140 void
TkpDisplayScale(ClientData clientData)141 TkpDisplayScale(
142 ClientData clientData) /* Widget record for scale. */
143 {
144 TkScale *scalePtr = clientData;
145 Tk_Window tkwin = scalePtr->tkwin;
146 Tcl_Interp *interp = scalePtr->interp;
147 int result;
148 char string[TCL_DOUBLE_SPACE];
149 MacScale *macScalePtr = clientData;
150 Rect r;
151 WindowRef windowRef;
152 MacDrawable *macDraw;
153 SInt32 initialValue, minValue, maxValue;
154 UInt16 numTicks;
155 Tcl_DString buf;
156
157 #ifdef TK_MAC_DEBUG_SCALE
158 TkMacOSXDbgMsg("TkpDisplayScale");
159 #endif
160 scalePtr->flags &= ~REDRAW_PENDING;
161 if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) {
162 goto done;
163 }
164
165 /*
166 * Invoke the scale's command if needed.
167 */
168
169 Tcl_Preserve(scalePtr);
170 if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
171 Tcl_Preserve(interp);
172 if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format,
173 scalePtr->value) < 0) {
174 string[TCL_DOUBLE_SPACE - 1] = '\0';
175 }
176 Tcl_DStringInit(&buf);
177 Tcl_DStringAppend(&buf, scalePtr->command, -1);
178 Tcl_DStringAppend(&buf, " ", -1);
179 Tcl_DStringAppend(&buf, string, -1);
180 result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL);
181 Tcl_DStringFree(&buf);
182 if (result != TCL_OK) {
183 Tcl_AddErrorInfo(interp, "\n (command executed by scale)");
184 Tcl_BackgroundException(interp, result);
185 }
186 Tcl_Release(interp);
187 }
188 scalePtr->flags &= ~INVOKE_COMMAND;
189 if (scalePtr->flags & SCALE_DELETED) {
190 Tcl_Release(scalePtr);
191 return;
192 }
193 Tcl_Release(scalePtr);
194
195 /*
196 * Now handle the part of redisplay that is the same for horizontal and
197 * vertical scales: border and traversal highlight.
198 */
199
200 if (scalePtr->highlightWidth != 0) {
201 GC gc = Tk_GCForColor(scalePtr->highlightColorPtr, Tk_WindowId(tkwin));
202
203 Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth,
204 Tk_WindowId(tkwin));
205 }
206 Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scalePtr->bgBorder,
207 scalePtr->highlightWidth, scalePtr->highlightWidth,
208 Tk_Width(tkwin) - 2*scalePtr->highlightWidth,
209 Tk_Height(tkwin) - 2*scalePtr->highlightWidth,
210 scalePtr->borderWidth, scalePtr->relief);
211
212 /*
213 * Set up port for drawing Macintosh control.
214 */
215
216 macDraw = (MacDrawable *)Tk_WindowId(tkwin);
217 windowRef = TkMacOSXGetNSWindowForDrawable(Tk_WindowId(tkwin));
218
219 /*
220 * Create Macintosh control.
221 */
222
223 #define MAC_OSX_SCROLL_WIDTH 10
224
225 if (scalePtr->orient == ORIENT_HORIZONTAL) {
226 int offset = (Tk_Height(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2;
227
228 if (offset < 0) {
229 offset = 0;
230 }
231
232 r.left = macDraw->xOff + scalePtr->inset;
233 r.top = macDraw->yOff + offset;
234 r.right = macDraw->xOff+Tk_Width(tkwin) - scalePtr->inset;
235 r.bottom = macDraw->yOff + offset + MAC_OSX_SCROLL_WIDTH/2;
236 } else {
237 int offset = (Tk_Width(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2;
238
239 if (offset < 0) {
240 offset = 0;
241 }
242
243 r.left = macDraw->xOff + offset;
244 r.top = macDraw->yOff + scalePtr->inset;
245 r.right = macDraw->xOff + offset + MAC_OSX_SCROLL_WIDTH/2;
246 r.bottom = macDraw->yOff + Tk_Height(tkwin) - scalePtr->inset;
247 }
248
249 if (macScalePtr->scaleHandle == NULL) {
250 #ifdef TK_MAC_DEBUG_SCALE
251 TkMacOSXDbgMsg("Initialising scale");
252 #endif
253 initialValue = scalePtr->value;
254 if (scalePtr->orient == ORIENT_HORIZONTAL) {
255 minValue = scalePtr->fromValue;
256 maxValue = scalePtr->toValue;
257 } else {
258 minValue = scalePtr->fromValue;
259 maxValue = scalePtr->toValue;
260 }
261
262 if (scalePtr->tickInterval == 0) {
263 numTicks = 0;
264 } else {
265 numTicks = (maxValue - minValue)/scalePtr->tickInterval;
266 }
267
268 CreateSliderControl(windowRef, &r, initialValue, minValue, maxValue,
269 kControlSliderPointsDownOrRight, numTicks, 1, scaleActionProc,
270 &macScalePtr->scaleHandle);
271 SetControlReference(macScalePtr->scaleHandle, (UInt32) scalePtr);
272
273 if (IsWindowActive(windowRef)) {
274 macScalePtr->flags |= ACTIVE;
275 }
276 } else {
277 SetControlBounds(macScalePtr->scaleHandle, &r);
278 SetControl32BitValue(macScalePtr->scaleHandle, scalePtr->value);
279 SetControl32BitMinimum(macScalePtr->scaleHandle, scalePtr->fromValue);
280 SetControl32BitMaximum(macScalePtr->scaleHandle, scalePtr->toValue);
281 }
282
283 /*
284 * Finally draw the control.
285 */
286
287 SetControlVisibility(macScalePtr->scaleHandle, true, true);
288 HiliteControl(macScalePtr->scaleHandle, 0);
289 Draw1Control(macScalePtr->scaleHandle);
290
291 done:
292 scalePtr->flags &= ~REDRAW_ALL;
293 }
294
295 /*
296 *----------------------------------------------------------------------
297 *
298 * TkpScaleElement --
299 *
300 * Determine which part of a scale widget lies under a given point.
301 *
302 * Results:
303 * The return value is either TROUGH1, SLIDER, TROUGH2, or OTHER,
304 * depending on which of the scale's active elements (if any) is under the
305 * point at (x,y).
306 *
307 * Side effects:
308 * None.
309 *
310 *----------------------------------------------------------------------
311 */
312
313 int
TkpScaleElement(TkScale * scalePtr,int x,int y)314 TkpScaleElement(
315 TkScale *scalePtr, /* Widget record for scale. */
316 int x, int y) /* Coordinates within scalePtr's window. */
317 {
318 MacScale *macScalePtr = (MacScale *) scalePtr;
319 ControlPartCode part;
320 Point where;
321 Rect bounds;
322
323 #ifdef TK_MAC_DEBUG_SCALE
324 TkMacOSXDbgMsg("TkpScaleElement");
325 #endif
326
327 /*
328 * All of the calculations in this procedure mirror those in
329 * DisplayScrollbar. Be sure to keep the two consistent.
330 */
331
332 TkMacOSXWinBounds((TkWindow *) scalePtr->tkwin, &bounds);
333 where.h = x + bounds.left;
334 where.v = y + bounds.top;
335 part = TestControl(macScalePtr->scaleHandle, where);
336
337 #ifdef TK_MAC_DEBUG_SCALE
338 fprintf (stderr,"ScalePart %d, pos ( %d %d )\n", part, where.h, where.v );
339 #endif
340
341 switch (part) {
342 case inSlider:
343 return SLIDER;
344 case inInc:
345 if (scalePtr->orient == ORIENT_VERTICAL) {
346 return TROUGH1;
347 } else {
348 return TROUGH2;
349 }
350 case inDecr:
351 if (scalePtr->orient == ORIENT_VERTICAL) {
352 return TROUGH2;
353 } else {
354 return TROUGH1;
355 }
356 default:
357 return OTHER;
358 }
359 }
360
361 /*
362 *--------------------------------------------------------------
363 *
364 * MacScaleEventProc --
365 *
366 * This procedure is invoked by the Tk dispatcher for ButtonPress events
367 * on scales.
368 *
369 * Results:
370 * None.
371 *
372 * Side effects:
373 * When the window gets deleted, internal structures get cleaned up. When
374 * it gets exposed, it is redisplayed.
375 *
376 *--------------------------------------------------------------
377 */
378
379 static void
MacScaleEventProc(ClientData clientData,XEvent * eventPtr)380 MacScaleEventProc(
381 ClientData clientData, /* Information about window. */
382 XEvent *eventPtr) /* Information about event. */
383 {
384 MacScale *macScalePtr = (MacScale *) clientData;
385 Point where;
386 Rect bounds;
387 int part;
388
389 #ifdef TK_MAC_DEBUG_SCALE
390 fprintf(stderr,"MacScaleEventProc\n" );
391 #endif
392
393 /*
394 * To call Macintosh control routines we must have the port set to the
395 * window containing the control. We will then test which part of the
396 * control was hit and act accordingly.
397 */
398
399 TkMacOSXDbgMsg("calling TestControl");
400 #endif
401 part = TestControl(macScalePtr->scaleHandle, where);
402 if (part == 0) {
403 return;
404 }
405
406 TkMacOSXTrackingLoop(1);
407 part = HandleControlClick(macScalePtr->scaleHandle, where,
408 TkMacOSXModifierState(), scaleActionProc);
409 TkMacOSXTrackingLoop(0);
410
411 /*
412 * Update the value for the widget.
413 */
414
415 macScalePtr->info.value = GetControlValue(macScalePtr->scaleHandle);
416 /* TkScaleSetValue(&macScalePtr->info, macScalePtr->info.value, 1, 0); */
417
418 /*
419 * The HandleControlClick call will "eat" the ButtonUp event. We now
420 * generate a ButtonUp event so Tk will unset implicit grabs etc.
421 */
422
423 TkGenerateButtonEventForXPointer(Tk_WindowId(macScalePtr->info.tkwin));
424 }
425
426 /*
427 *--------------------------------------------------------------
428 *
429 * ScaleActionProc --
430 *
431 * Callback procedure used by the Macintosh toolbox call
432 * HandleControlClick. This call will update the display while the
433 * scrollbar is being manipulated by the user.
434 *
435 * Results:
436 * None.
437 *
438 * Side effects:
439 * May change the display.
440 *
441 *--------------------------------------------------------------
442 */
443
444 static pascal void
ScaleActionProc(ControlRef theControl,ControlPartCode partCode)445 ScaleActionProc(
446 ControlRef theControl, /* Handle to scrollbat control */
447 ControlPartCode partCode) /* Part of scrollbar that was "hit" */
448 {
449 int value;
450 TkScale *scalePtr = (TkScale *) GetControlReference(theControl);
451
452 #ifdef TK_MAC_DEBUG_SCALE
453 TkMacOSXDbgMsg("ScaleActionProc");
454 #endif
455 value = GetControlValue(theControl);
456 TkScaleSetValue(scalePtr, value, 1, 1);
457 Tcl_Preserve(scalePtr);
458 TkMacOSXRunTclEventLoop();
459 Tcl_Release(scalePtr);
460 }
461 #endif
462
463 /*
464 * Local Variables:
465 * mode: objc
466 * c-basic-offset: 4
467 * fill-column: 79
468 * coding: utf-8
469 * End:
470 */
471