4 * This file implements the Macintosh specific portion of the
7 * Copyright (c) 1996 by Sun Microsystems, Inc.
8 * Copyright (c) 1998-2000 by Scriptics Corporation.
9 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
10 * Copyright 2008-2009, Apple Inc.
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 #include "tkMacOSXPrivate.h"
19 #ifdef MAC_OSX_TK_TODO
22 #define TK_MAC_DEBUG_SCALE
27 * Defines used in this file.
36 * Declaration of Macintosh specific scale structure.
39 typedef struct MacScale {
40 TkScale info; /* Generic scale info. */
41 int flags; /* Flags. */
42 ControlRef scaleHandle; /* Handle to the Scale control struct. */
46 * Globals uses locally in this file.
48 static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */
51 * Forward declarations for procedures defined later in this file:
54 static void MacScaleEventProc(ClientData clientData,
56 static pascal void ScaleActionProc(ControlRef theControl,
57 ControlPartCode partCode);
60 *----------------------------------------------------------------------
64 * Allocate a new TkScale structure.
67 * Returns a newly allocated TkScale structure.
72 *----------------------------------------------------------------------
79 MacScale *macScalePtr = (MacScale *)ckalloc(sizeof(MacScale));
81 macScalePtr->scaleHandle = NULL;
82 if (scaleActionProc == NULL) {
83 scaleActionProc = NewControlActionUPP(ScaleActionProc);
86 Tk_CreateEventHandler(tkwin, ButtonPressMask,
87 MacScaleEventProc, macScalePtr);
89 return (TkScale *) macScalePtr;
93 *----------------------------------------------------------------------
97 * Free Macintosh specific resources.
103 * The slider control is destroyed.
105 *----------------------------------------------------------------------
112 MacScale *macScalePtr = (MacScale *) scalePtr;
115 * Free Macintosh control.
118 if (macScalePtr->scaleHandle != NULL) {
119 DisposeControl(macScalePtr->scaleHandle);
124 *----------------------------------------------------------------------
128 * This procedure is invoked as an idle handler to redisplay the contents
135 * The scale gets redisplayed.
137 *----------------------------------------------------------------------
142 ClientData clientData) /* Widget record for scale. */
144 TkScale *scalePtr = clientData;
145 Tk_Window tkwin = scalePtr->tkwin;
146 Tcl_Interp *interp = scalePtr->interp;
148 char string[TCL_DOUBLE_SPACE];
149 MacScale *macScalePtr = clientData;
152 MacDrawable *macDraw;
153 SInt32 initialValue, minValue, maxValue;
157 #ifdef TK_MAC_DEBUG_SCALE
158 TkMacOSXDbgMsg("TkpDisplayScale");
160 scalePtr->flags &= ~REDRAW_PENDING;
161 if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) {
166 * Invoke the scale's command if needed.
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';
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);
188 scalePtr->flags &= ~INVOKE_COMMAND;
189 if (scalePtr->flags & SCALE_DELETED) {
190 Tcl_Release(scalePtr);
193 Tcl_Release(scalePtr);
196 * Now handle the part of redisplay that is the same for horizontal and
197 * vertical scales: border and traversal highlight.
200 if (scalePtr->highlightWidth != 0) {
201 GC gc = Tk_GCForColor(scalePtr->highlightColorPtr, Tk_WindowId(tkwin));
203 Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth,
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);
213 * Set up port for drawing Macintosh control.
216 macDraw = (MacDrawable *)Tk_WindowId(tkwin);
217 windowRef = TkMacOSXGetNSWindowForDrawable(Tk_WindowId(tkwin));
220 * Create Macintosh control.
223 #define MAC_OSX_SCROLL_WIDTH 10
225 if (scalePtr->orient == ORIENT_HORIZONTAL) {
226 int offset = (Tk_Height(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2;
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;
237 int offset = (Tk_Width(tkwin) - MAC_OSX_SCROLL_WIDTH) / 2;
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;
249 if (macScalePtr->scaleHandle == NULL) {
250 #ifdef TK_MAC_DEBUG_SCALE
251 TkMacOSXDbgMsg("Initialising scale");
253 initialValue = scalePtr->value;
254 if (scalePtr->orient == ORIENT_HORIZONTAL) {
255 minValue = scalePtr->fromValue;
256 maxValue = scalePtr->toValue;
258 minValue = scalePtr->fromValue;
259 maxValue = scalePtr->toValue;
262 if (scalePtr->tickInterval == 0) {
265 numTicks = (maxValue - minValue)/scalePtr->tickInterval;
268 CreateSliderControl(windowRef, &r, initialValue, minValue, maxValue,
269 kControlSliderPointsDownOrRight, numTicks, 1, scaleActionProc,
270 &macScalePtr->scaleHandle);
271 SetControlReference(macScalePtr->scaleHandle, (UInt32) scalePtr);
273 if (IsWindowActive(windowRef)) {
274 macScalePtr->flags |= ACTIVE;
277 SetControlBounds(macScalePtr->scaleHandle, &r);
278 SetControl32BitValue(macScalePtr->scaleHandle, scalePtr->value);
279 SetControl32BitMinimum(macScalePtr->scaleHandle, scalePtr->fromValue);
280 SetControl32BitMaximum(macScalePtr->scaleHandle, scalePtr->toValue);
284 * Finally draw the control.
287 SetControlVisibility(macScalePtr->scaleHandle, true, true);
288 HiliteControl(macScalePtr->scaleHandle, 0);
289 Draw1Control(macScalePtr->scaleHandle);
291 scalePtr->flags &= ~REDRAW_ALL;
295 *----------------------------------------------------------------------
299 * Determine which part of a scale widget lies under a given point.
302 * The return value is either TROUGH1, SLIDER, TROUGH2, or OTHER,
303 * depending on which of the scale's active elements (if any) is under the
309 *----------------------------------------------------------------------
314 TkScale *scalePtr, /* Widget record for scale. */
315 int x, int y) /* Coordinates within scalePtr's window. */
317 MacScale *macScalePtr = (MacScale *) scalePtr;
318 ControlPartCode part;
322 #ifdef TK_MAC_DEBUG_SCALE
323 TkMacOSXDbgMsg("TkpScaleElement");
327 * All of the calculations in this procedure mirror those in
328 * DisplayScrollbar. Be sure to keep the two consistent.
331 TkMacOSXWinBounds((TkWindow *) scalePtr->tkwin, &bounds);
332 where.h = x + bounds.left;
333 where.v = y + bounds.top;
334 part = TestControl(macScalePtr->scaleHandle, where);
336 #ifdef TK_MAC_DEBUG_SCALE
337 fprintf (stderr,"ScalePart %d, pos ( %d %d )\n", part, where.h, where.v );
344 if (scalePtr->orient == ORIENT_VERTICAL) {
350 if (scalePtr->orient == ORIENT_VERTICAL) {
361 *--------------------------------------------------------------
363 * MacScaleEventProc --
365 * This procedure is invoked by the Tk dispatcher for ButtonPress events
372 * When the window gets deleted, internal structures get cleaned up. When
373 * it gets exposed, it is redisplayed.
375 *--------------------------------------------------------------
380 ClientData clientData, /* Information about window. */
381 XEvent *eventPtr) /* Information about event. */
383 MacScale *macScalePtr = (MacScale *) clientData;
388 #ifdef TK_MAC_DEBUG_SCALE
389 fprintf(stderr,"MacScaleEventProc\n" );
392 TkMacOSXWinBounds((TkWindow *) macScalePtr->info.tkwin, &bounds);
393 where.h = eventPtr->xbutton.x + bounds.left;
394 where.v = eventPtr->xbutton.y + bounds.top;
395 #ifdef TK_MAC_DEBUG_SCALE
396 TkMacOSXDbgMsg("calling TestControl");
398 part = TestControl(macScalePtr->scaleHandle, where);
403 TkMacOSXTrackingLoop(1);
404 part = HandleControlClick(macScalePtr->scaleHandle, where,
405 TkMacOSXModifierState(), scaleActionProc);
406 TkMacOSXTrackingLoop(0);
409 * Update the value for the widget.
412 macScalePtr->info.value = GetControlValue(macScalePtr->scaleHandle);
413 /* TkScaleSetValue(&macScalePtr->info, macScalePtr->info.value, 1, 0); */
416 * The HandleControlClick call will "eat" the ButtonUp event. We now
417 * generate a ButtonUp event so Tk will unset implicit grabs etc.
420 TkGenerateButtonEventForXPointer(Tk_WindowId(macScalePtr->info.tkwin));
424 *--------------------------------------------------------------
428 * Callback procedure used by the Macintosh toolbox call
429 * HandleControlClick. This call will update the display while the
430 * scrollbar is being manipulated by the user.
436 * May change the display.
438 *--------------------------------------------------------------
443 ControlRef theControl, /* Handle to scrollbat control */
444 ControlPartCode partCode) /* Part of scrollbar that was "hit" */
447 TkScale *scalePtr = (TkScale *) GetControlReference(theControl);
449 #ifdef TK_MAC_DEBUG_SCALE
450 TkMacOSXDbgMsg("ScaleActionProc");
452 value = GetControlValue(theControl);
453 TkScaleSetValue(scalePtr, value, 1, 1);
454 Tcl_Preserve(scalePtr);
455 TkMacOSXRunTclEventLoop();
456 Tcl_Release(scalePtr);