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