|
|
1.1 ! root 1: /* ! 2: * tkScale.c -- ! 3: * ! 4: * This module implements a scale widgets for the Tk toolkit. ! 5: * A scale displays a slider that can be adjusted to change a ! 6: * value; it also displays numeric labels and a textual label, ! 7: * if desired. ! 8: * ! 9: * Copyright 1990 Regents of the University of California. ! 10: * Permission to use, copy, modify, and distribute this ! 11: * software and its documentation for any purpose and without ! 12: * fee is hereby granted, provided that the above copyright ! 13: * notice appear in all copies. The University of California ! 14: * makes no representations about the suitability of this ! 15: * software for any purpose. It is provided "as is" without ! 16: * express or implied warranty. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkScale.c,v 1.28 92/08/21 11:45:25 ouster Exp $ SPRITE (Berkeley)"; ! 21: #endif ! 22: ! 23: #include "tkconfig.h" ! 24: #include "default.h" ! 25: #include "tkint.h" ! 26: ! 27: /* ! 28: * A data structure of the following type is kept for each scale ! 29: * widget managed by this file: ! 30: */ ! 31: ! 32: typedef struct { ! 33: Tk_Window tkwin; /* Window that embodies the scale. NULL ! 34: * means that the window has been destroyed ! 35: * but the data structures haven't yet been ! 36: * cleaned up.*/ ! 37: Tcl_Interp *interp; /* Interpreter associated with scale. */ ! 38: Tk_Uid orientUid; /* Orientation for window ("vertical" or ! 39: * "horizontal"). */ ! 40: int vertical; /* Non-zero means vertical orientation, ! 41: * zero means horizontal. */ ! 42: int value; /* Current value of scale. */ ! 43: int fromValue; /* Value corresponding to left or top of ! 44: * scale. */ ! 45: int toValue; /* Value corresponding to right or bottom ! 46: * of scale. */ ! 47: int tickInterval; /* Distance between tick marks; 0 means ! 48: * don't display any tick marks. */ ! 49: char *command; /* Command prefix to use when invoking Tcl ! 50: * commands because the scale value changed. ! 51: * NULL means don't invoke commands. ! 52: * Malloc'ed. */ ! 53: int commandLength; /* Number of non-NULL bytes in command. */ ! 54: char *label; /* Label to display above or to right of ! 55: * scale; NULL means don't display a ! 56: * label. Malloc'ed. */ ! 57: int labelLength; /* Number of non-NULL chars. in label. */ ! 58: Tk_Uid state; /* Normal or disabled. Value cannot be ! 59: * changed when scale is disabled. */ ! 60: ! 61: /* ! 62: * Information used when displaying widget: ! 63: */ ! 64: ! 65: int borderWidth; /* Width of 3-D border around window. */ ! 66: Tk_3DBorder bgBorder; /* Used for drawing background. */ ! 67: Tk_3DBorder sliderBorder; /* Used for drawing slider in normal mode. */ ! 68: Tk_3DBorder activeBorder; /* Used for drawing slider when active (i.e. ! 69: * when mouse is in window). */ ! 70: XFontStruct *fontPtr; /* Information about text font, or NULL. */ ! 71: XColor *textColorPtr; /* Color for drawing text. */ ! 72: GC textGC; /* GC for drawing text in normal mode. */ ! 73: int width; /* Desired narrow dimension of scale, ! 74: * in pixels. */ ! 75: int length; /* Desired long dimension of scale, ! 76: * in pixels. */ ! 77: int relief; /* Indicates whether window as a whole is ! 78: * raised, sunken, or flat. */ ! 79: int offset; /* Zero if relief is TK_RELIEF_FLAT, ! 80: * borderWidth otherwise. Indicates how ! 81: * much interior stuff must be offset from ! 82: * outside edges to leave room for border. */ ! 83: int sliderLength; /* Length of slider, measured in pixels along ! 84: * long dimension of scale. */ ! 85: int showValue; /* Non-zero means to display the scale value ! 86: * below or to the left of the slider; zero ! 87: * means don't display the value. */ ! 88: int tickPixels; /* Number of pixels required for widest tick ! 89: * mark. 0 means don't display ticks.*/ ! 90: int valuePixels; /* Number of pixels required for value text. */ ! 91: int labelPixels; /* Number of pixels required for label. 0 ! 92: * means don't display label. */ ! 93: ! 94: /* ! 95: * Miscellaneous information: ! 96: */ ! 97: ! 98: Cursor cursor; /* Current cursor for window, or None. */ ! 99: int flags; /* Various flags; see below for ! 100: * definitions. */ ! 101: } Scale; ! 102: ! 103: /* ! 104: * Flag bits for scales: ! 105: * ! 106: * REDRAW_SLIDER - 1 means slider (and numerical readout) need ! 107: * to be redrawn. ! 108: * REDRAW_OTHER - 1 means other stuff besides slider and value ! 109: * need to be redrawn. ! 110: * REDRAW_ALL - 1 means the entire widget needs to be redrawn. ! 111: * ACTIVE - 1 means the widget is active (the mouse is ! 112: * in its window). ! 113: * BUTTON_PRESSED - 1 means a button press is in progress, so ! 114: * slider should appear depressed and should be ! 115: * draggable. ! 116: */ ! 117: ! 118: #define REDRAW_SLIDER 1 ! 119: #define REDRAW_OTHER 2 ! 120: #define REDRAW_ALL 3 ! 121: #define ACTIVE 4 ! 122: #define BUTTON_PRESSED 8 ! 123: ! 124: /* ! 125: * Space to leave between scale area and text. ! 126: */ ! 127: ! 128: #define SPACING 2 ! 129: ! 130: /* ! 131: * Information used for argv parsing. ! 132: */ ! 133: ! 134: ! 135: static Tk_ConfigSpec configSpecs[] = { ! 136: {TK_CONFIG_BORDER, "-activeforeground", "activeForeground", "Background", ! 137: DEF_SCALE_ACTIVE_FG_COLOR, Tk_Offset(Scale, activeBorder), ! 138: TK_CONFIG_COLOR_ONLY}, ! 139: {TK_CONFIG_BORDER, "-activeforeground", "activeForeground", "Background", ! 140: DEF_SCALE_ACTIVE_FG_MONO, Tk_Offset(Scale, activeBorder), ! 141: TK_CONFIG_MONO_ONLY}, ! 142: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 143: DEF_SCALE_BG_COLOR, Tk_Offset(Scale, bgBorder), ! 144: TK_CONFIG_COLOR_ONLY}, ! 145: {TK_CONFIG_BORDER, "-background", "background", "Background", ! 146: DEF_SCALE_BG_MONO, Tk_Offset(Scale, bgBorder), ! 147: TK_CONFIG_MONO_ONLY}, ! 148: {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, ! 149: (char *) NULL, 0, 0}, ! 150: {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, ! 151: (char *) NULL, 0, 0}, ! 152: {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", ! 153: DEF_SCALE_BORDER_WIDTH, Tk_Offset(Scale, borderWidth), 0}, ! 154: {TK_CONFIG_STRING, "-command", "command", "Command", ! 155: (char *) NULL, Tk_Offset(Scale, command), 0}, ! 156: {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", ! 157: DEF_SCALE_CURSOR, Tk_Offset(Scale, cursor), TK_CONFIG_NULL_OK}, ! 158: {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, ! 159: (char *) NULL, 0, 0}, ! 160: {TK_CONFIG_FONT, "-font", "font", "Font", ! 161: DEF_SCALE_FONT, Tk_Offset(Scale, fontPtr), ! 162: 0}, ! 163: {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", ! 164: DEF_SCALE_FG_COLOR, Tk_Offset(Scale, textColorPtr), ! 165: TK_CONFIG_COLOR_ONLY}, ! 166: {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", ! 167: DEF_SCALE_FG_MONO, Tk_Offset(Scale, textColorPtr), ! 168: TK_CONFIG_MONO_ONLY}, ! 169: {TK_CONFIG_INT, "-from", "from", "From", ! 170: DEF_SCALE_FROM, Tk_Offset(Scale, fromValue), 0}, ! 171: {TK_CONFIG_STRING, "-label", "label", "Label", ! 172: DEF_SCALE_LABEL, Tk_Offset(Scale, label), 0}, ! 173: {TK_CONFIG_PIXELS, "-length", "length", "Length", ! 174: DEF_SCALE_LENGTH, Tk_Offset(Scale, length), 0}, ! 175: {TK_CONFIG_UID, "-orient", "orient", "Orient", ! 176: DEF_SCALE_ORIENT, Tk_Offset(Scale, orientUid), 0}, ! 177: {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", ! 178: DEF_SCALE_RELIEF, Tk_Offset(Scale, relief), 0}, ! 179: {TK_CONFIG_BOOLEAN, "-showvalue", "showValue", "ShowValue", ! 180: DEF_SCALE_SHOW_VALUE, Tk_Offset(Scale, showValue), 0}, ! 181: {TK_CONFIG_BORDER, "-sliderforeground", "sliderForeground", "Background", ! 182: DEF_SCALE_SLIDER_FG_COLOR, Tk_Offset(Scale, sliderBorder), ! 183: TK_CONFIG_COLOR_ONLY}, ! 184: {TK_CONFIG_BORDER, "-sliderforeground", "sliderForeground", "Background", ! 185: DEF_SCALE_SLIDER_FG_MONO, Tk_Offset(Scale, sliderBorder), ! 186: TK_CONFIG_MONO_ONLY}, ! 187: {TK_CONFIG_PIXELS, "-sliderlength", "sliderLength", "SliderLength", ! 188: DEF_SCALE_SLIDER_LENGTH, Tk_Offset(Scale, sliderLength), 0}, ! 189: {TK_CONFIG_UID, "-state", "state", "State", ! 190: DEF_SCALE_STATE, Tk_Offset(Scale, state), 0}, ! 191: {TK_CONFIG_INT, "-tickinterval", "tickInterval", "TickInterval", ! 192: DEF_SCALE_TICK_INTERVAL, Tk_Offset(Scale, tickInterval), 0}, ! 193: {TK_CONFIG_INT, "-to", "to", "To", ! 194: DEF_SCALE_TO, Tk_Offset(Scale, toValue), 0}, ! 195: {TK_CONFIG_PIXELS, "-width", "width", "Width", ! 196: DEF_SCALE_WIDTH, Tk_Offset(Scale, width), 0}, ! 197: {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, ! 198: (char *) NULL, 0, 0} ! 199: }; ! 200: ! 201: /* ! 202: * Forward declarations for procedures defined later in this file: ! 203: */ ! 204: ! 205: static void ComputeScaleGeometry _ANSI_ARGS_((Scale *scalePtr)); ! 206: static int ConfigureScale _ANSI_ARGS_((Tcl_Interp *interp, ! 207: Scale *scalePtr, int argc, char **argv, ! 208: int flags)); ! 209: static void DestroyScale _ANSI_ARGS_((ClientData clientData)); ! 210: static void DisplayHorizontalScale _ANSI_ARGS_(( ! 211: ClientData clientData)); ! 212: static void DisplayHorizontalValue _ANSI_ARGS_((Scale *scalePtr, ! 213: int value, int bottom)); ! 214: static void DisplayVerticalScale _ANSI_ARGS_(( ! 215: ClientData clientData)); ! 216: static void DisplayVerticalValue _ANSI_ARGS_((Scale *scalePtr, ! 217: int value, int rightEdge)); ! 218: static void EventuallyRedrawScale _ANSI_ARGS_((Scale *scalePtr, ! 219: int what)); ! 220: static int PixelToValue _ANSI_ARGS_((Scale *scalePtr, int x, ! 221: int y)); ! 222: static void ScaleEventProc _ANSI_ARGS_((ClientData clientData, ! 223: XEvent *eventPtr)); ! 224: static void ScaleMouseProc _ANSI_ARGS_((ClientData clientData, ! 225: XEvent *eventPtr)); ! 226: static int ScaleWidgetCmd _ANSI_ARGS_((ClientData clientData, ! 227: Tcl_Interp *interp, int argc, char **argv)); ! 228: static void SetScaleValue _ANSI_ARGS_((Scale *scalePtr, ! 229: int value)); ! 230: static int ValueToPixel _ANSI_ARGS_((Scale *scalePtr, int value)); ! 231: ! 232: /* ! 233: *-------------------------------------------------------------- ! 234: * ! 235: * Tk_ScaleCmd -- ! 236: * ! 237: * This procedure is invoked to process the "scale" Tcl ! 238: * command. See the user documentation for details on what ! 239: * it does. ! 240: * ! 241: * Results: ! 242: * A standard Tcl result. ! 243: * ! 244: * Side effects: ! 245: * See the user documentation. ! 246: * ! 247: *-------------------------------------------------------------- ! 248: */ ! 249: ! 250: int ! 251: Tk_ScaleCmd(clientData, interp, argc, argv) ! 252: ClientData clientData; /* Main window associated with ! 253: * interpreter. */ ! 254: Tcl_Interp *interp; /* Current interpreter. */ ! 255: int argc; /* Number of arguments. */ ! 256: char **argv; /* Argument strings. */ ! 257: { ! 258: Tk_Window tkwin = (Tk_Window) clientData; ! 259: register Scale *scalePtr; ! 260: Tk_Window new; ! 261: ! 262: if (argc < 2) { ! 263: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 264: argv[0], " pathName ?options?\"", (char *) NULL); ! 265: return TCL_ERROR; ! 266: } ! 267: ! 268: new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL); ! 269: if (new == NULL) { ! 270: return TCL_ERROR; ! 271: } ! 272: ! 273: /* ! 274: * Initialize fields that won't be initialized by ConfigureScale, ! 275: * or which ConfigureScale expects to have reasonable values ! 276: * (e.g. resource pointers). ! 277: */ ! 278: ! 279: scalePtr = (Scale *) ckalloc(sizeof(Scale)); ! 280: scalePtr->tkwin = new; ! 281: scalePtr->interp = interp; ! 282: scalePtr->value = 0; ! 283: scalePtr->command = NULL; ! 284: scalePtr->label = NULL; ! 285: scalePtr->state = tkNormalUid; ! 286: scalePtr->bgBorder = NULL; ! 287: scalePtr->sliderBorder = NULL; ! 288: scalePtr->activeBorder = NULL; ! 289: scalePtr->fontPtr = NULL; ! 290: scalePtr->textColorPtr = NULL; ! 291: scalePtr->textGC = None; ! 292: scalePtr->cursor = None; ! 293: scalePtr->flags = 0; ! 294: ! 295: Tk_SetClass(scalePtr->tkwin, "Scale"); ! 296: Tk_CreateEventHandler(scalePtr->tkwin, ExposureMask|StructureNotifyMask, ! 297: ScaleEventProc, (ClientData) scalePtr); ! 298: Tk_CreateEventHandler(scalePtr->tkwin, EnterWindowMask|LeaveWindowMask ! 299: |PointerMotionMask|ButtonPressMask|ButtonReleaseMask, ! 300: ScaleMouseProc, (ClientData) scalePtr); ! 301: Tcl_CreateCommand(interp, Tk_PathName(scalePtr->tkwin), ScaleWidgetCmd, ! 302: (ClientData) scalePtr, (void (*)()) NULL); ! 303: if (ConfigureScale(interp, scalePtr, argc-2, argv+2, 0) != TCL_OK) { ! 304: goto error; ! 305: } ! 306: ! 307: interp->result = Tk_PathName(scalePtr->tkwin); ! 308: return TCL_OK; ! 309: ! 310: error: ! 311: Tk_DestroyWindow(scalePtr->tkwin); ! 312: return TCL_ERROR; ! 313: } ! 314: ! 315: /* ! 316: *-------------------------------------------------------------- ! 317: * ! 318: * ScaleWidgetCmd -- ! 319: * ! 320: * This procedure is invoked to process the Tcl command ! 321: * that corresponds to a widget managed by this module. ! 322: * See the user documentation for details on what it does. ! 323: * ! 324: * Results: ! 325: * A standard Tcl result. ! 326: * ! 327: * Side effects: ! 328: * See the user documentation. ! 329: * ! 330: *-------------------------------------------------------------- ! 331: */ ! 332: ! 333: static int ! 334: ScaleWidgetCmd(clientData, interp, argc, argv) ! 335: ClientData clientData; /* Information about scale ! 336: * widget. */ ! 337: Tcl_Interp *interp; /* Current interpreter. */ ! 338: int argc; /* Number of arguments. */ ! 339: char **argv; /* Argument strings. */ ! 340: { ! 341: register Scale *scalePtr = (Scale *) clientData; ! 342: int result = TCL_OK; ! 343: int length; ! 344: char c; ! 345: ! 346: if (argc < 2) { ! 347: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 348: argv[0], " option ?arg arg ...?\"", (char *) NULL); ! 349: return TCL_ERROR; ! 350: } ! 351: Tk_Preserve((ClientData) scalePtr); ! 352: c = argv[1][0]; ! 353: length = strlen(argv[1]); ! 354: if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { ! 355: if (argc == 2) { ! 356: result = Tk_ConfigureInfo(interp, scalePtr->tkwin, configSpecs, ! 357: (char *) scalePtr, (char *) NULL, 0); ! 358: } else if (argc == 3) { ! 359: result = Tk_ConfigureInfo(interp, scalePtr->tkwin, configSpecs, ! 360: (char *) scalePtr, argv[2], 0); ! 361: } else { ! 362: result = ConfigureScale(interp, scalePtr, argc-2, argv+2, ! 363: TK_CONFIG_ARGV_ONLY); ! 364: } ! 365: } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) { ! 366: if (argc != 2) { ! 367: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 368: argv[0], " get\"", (char *) NULL); ! 369: goto error; ! 370: } ! 371: sprintf(interp->result, "%d", scalePtr->value); ! 372: } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) { ! 373: int value; ! 374: ! 375: if (argc != 3) { ! 376: Tcl_AppendResult(interp, "wrong # args: should be \"", ! 377: argv[0], " set value\"", (char *) NULL); ! 378: goto error; ! 379: } ! 380: if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) { ! 381: goto error; ! 382: } ! 383: if (scalePtr->state == tkNormalUid) { ! 384: if ((value < scalePtr->fromValue) ! 385: ^ (scalePtr->toValue < scalePtr->fromValue)) { ! 386: value = scalePtr->fromValue; ! 387: } ! 388: if ((value > scalePtr->toValue) ! 389: ^ (scalePtr->toValue < scalePtr->fromValue)) { ! 390: value = scalePtr->toValue; ! 391: } ! 392: SetScaleValue(scalePtr, value); ! 393: } ! 394: } else { ! 395: Tcl_AppendResult(interp, "bad option \"", argv[1], ! 396: "\": must be configure, get, or set", (char *) NULL); ! 397: goto error; ! 398: } ! 399: Tk_Release((ClientData) scalePtr); ! 400: return result; ! 401: ! 402: error: ! 403: Tk_Release((ClientData) scalePtr); ! 404: return TCL_ERROR; ! 405: } ! 406: ! 407: /* ! 408: *---------------------------------------------------------------------- ! 409: * ! 410: * DestroyScale -- ! 411: * ! 412: * This procedure is invoked by Tk_EventuallyFree or Tk_Release ! 413: * to clean up the internal structure of a button at a safe time ! 414: * (when no-one is using it anymore). ! 415: * ! 416: * Results: ! 417: * None. ! 418: * ! 419: * Side effects: ! 420: * Everything associated with the scale is freed up. ! 421: * ! 422: *---------------------------------------------------------------------- ! 423: */ ! 424: ! 425: static void ! 426: DestroyScale(clientData) ! 427: ClientData clientData; /* Info about scale widget. */ ! 428: { ! 429: register Scale *scalePtr = (Scale *) clientData; ! 430: ! 431: if (scalePtr->command != NULL) { ! 432: ckfree(scalePtr->command); ! 433: } ! 434: if (scalePtr->label != NULL) { ! 435: ckfree(scalePtr->label); ! 436: } ! 437: if (scalePtr->bgBorder != NULL) { ! 438: Tk_Free3DBorder(scalePtr->bgBorder); ! 439: } ! 440: if (scalePtr->sliderBorder != NULL) { ! 441: Tk_Free3DBorder(scalePtr->sliderBorder); ! 442: } ! 443: if (scalePtr->activeBorder != NULL) { ! 444: Tk_Free3DBorder(scalePtr->activeBorder); ! 445: } ! 446: if (scalePtr->fontPtr != NULL) { ! 447: Tk_FreeFontStruct(scalePtr->fontPtr); ! 448: } ! 449: if (scalePtr->textColorPtr != NULL) { ! 450: Tk_FreeColor(scalePtr->textColorPtr); ! 451: } ! 452: if (scalePtr->textGC != None) { ! 453: Tk_FreeGC(scalePtr->textGC); ! 454: } ! 455: if (scalePtr->cursor != None) { ! 456: Tk_FreeCursor(scalePtr->cursor); ! 457: } ! 458: ckfree((char *) scalePtr); ! 459: } ! 460: ! 461: /* ! 462: *---------------------------------------------------------------------- ! 463: * ! 464: * ConfigureScale -- ! 465: * ! 466: * This procedure is called to process an argv/argc list, plus ! 467: * the Tk option database, in order to configure (or ! 468: * reconfigure) a scale widget. ! 469: * ! 470: * Results: ! 471: * The return value is a standard Tcl result. If TCL_ERROR is ! 472: * returned, then interp->result contains an error message. ! 473: * ! 474: * Side effects: ! 475: * Configuration information, such as colors, border width, ! 476: * etc. get set for scalePtr; old resources get freed, ! 477: * if there were any. ! 478: * ! 479: *---------------------------------------------------------------------- ! 480: */ ! 481: ! 482: static int ! 483: ConfigureScale(interp, scalePtr, argc, argv, flags) ! 484: Tcl_Interp *interp; /* Used for error reporting. */ ! 485: register Scale *scalePtr; /* Information about widget; may or may ! 486: * not already have values for some fields. */ ! 487: int argc; /* Number of valid entries in argv. */ ! 488: char **argv; /* Arguments. */ ! 489: int flags; /* Flags to pass to Tk_ConfigureWidget. */ ! 490: { ! 491: XGCValues gcValues; ! 492: GC newGC; ! 493: int length; ! 494: ! 495: if (Tk_ConfigureWidget(interp, scalePtr->tkwin, configSpecs, ! 496: argc, argv, (char *) scalePtr, flags) != TCL_OK) { ! 497: return TCL_ERROR; ! 498: } ! 499: ! 500: /* ! 501: * A few options need special processing, such as parsing the ! 502: * orientation or setting the background from a 3-D border. ! 503: */ ! 504: ! 505: length = strlen(scalePtr->orientUid); ! 506: if (strncmp(scalePtr->orientUid, "vertical", length) == 0) { ! 507: scalePtr->vertical = 1; ! 508: } else if (strncmp(scalePtr->orientUid, "horizontal", length) == 0) { ! 509: scalePtr->vertical = 0; ! 510: } else { ! 511: Tcl_AppendResult(interp, "bad orientation \"", scalePtr->orientUid, ! 512: "\": must be vertical or horizontal", (char *) NULL); ! 513: return TCL_ERROR; ! 514: } ! 515: ! 516: if ((scalePtr->state != tkNormalUid) ! 517: && (scalePtr->state != tkDisabledUid)) { ! 518: Tcl_AppendResult(interp, "bad state value \"", scalePtr->state, ! 519: "\": must be normal or disabled", (char *) NULL); ! 520: scalePtr->state = tkNormalUid; ! 521: return TCL_ERROR; ! 522: } ! 523: ! 524: /* ! 525: * Make sure that the tick interval has the right sign so that ! 526: * addition moves from fromValue to toValue. ! 527: */ ! 528: ! 529: if ((scalePtr->tickInterval < 0) ! 530: ^ ((scalePtr->toValue - scalePtr->fromValue) < 0)) { ! 531: scalePtr->tickInterval = -scalePtr->tickInterval; ! 532: } ! 533: ! 534: /* ! 535: * Set the scale value to itself; all this does is to make sure ! 536: * that the scale's value is within the new acceptable range for ! 537: * the scale. ! 538: */ ! 539: ! 540: SetScaleValue(scalePtr, scalePtr->value); ! 541: ! 542: if (scalePtr->command != NULL) { ! 543: scalePtr->commandLength = strlen(scalePtr->command); ! 544: } else { ! 545: scalePtr->commandLength = 0; ! 546: } ! 547: ! 548: if (scalePtr->label != NULL) { ! 549: scalePtr->labelLength = strlen(scalePtr->label); ! 550: } else { ! 551: scalePtr->labelLength = 0; ! 552: } ! 553: ! 554: Tk_SetBackgroundFromBorder(scalePtr->tkwin, scalePtr->bgBorder); ! 555: ! 556: gcValues.font = scalePtr->fontPtr->fid; ! 557: gcValues.foreground = scalePtr->textColorPtr->pixel; ! 558: newGC = Tk_GetGC(scalePtr->tkwin, GCForeground|GCFont, &gcValues); ! 559: if (scalePtr->textGC != None) { ! 560: Tk_FreeGC(scalePtr->textGC); ! 561: } ! 562: scalePtr->textGC = newGC; ! 563: ! 564: if (scalePtr->relief != TK_RELIEF_FLAT) { ! 565: scalePtr->offset = scalePtr->borderWidth; ! 566: } else { ! 567: scalePtr->offset = 0; ! 568: } ! 569: ! 570: /* ! 571: * Recompute display-related information, and let the geometry ! 572: * manager know how much space is needed now. ! 573: */ ! 574: ! 575: ComputeScaleGeometry(scalePtr); ! 576: ! 577: EventuallyRedrawScale(scalePtr, REDRAW_ALL); ! 578: return TCL_OK; ! 579: } ! 580: ! 581: /* ! 582: *---------------------------------------------------------------------- ! 583: * ! 584: * ComputeScaleGeometry -- ! 585: * ! 586: * This procedure is called to compute various geometrical ! 587: * information for a scale, such as where various things get ! 588: * displayed. It's called when the window is reconfigured. ! 589: * ! 590: * Results: ! 591: * None. ! 592: * ! 593: * Side effects: ! 594: * Display-related numbers get changed in *scrollPtr. The ! 595: * geometry manager gets told about the window's preferred size. ! 596: * ! 597: *---------------------------------------------------------------------- ! 598: */ ! 599: ! 600: static void ! 601: ComputeScaleGeometry(scalePtr) ! 602: register Scale *scalePtr; /* Information about widget. */ ! 603: { ! 604: XCharStruct bbox; ! 605: char valueString[30]; ! 606: int dummy, lineHeight; ! 607: ! 608: /* ! 609: * Horizontal scales are simpler than vertical ones because ! 610: * all sizes are the same (the height of a line of text); ! 611: * handle them first and then quit. ! 612: */ ! 613: ! 614: if (!scalePtr->vertical) { ! 615: lineHeight = scalePtr->fontPtr->ascent + scalePtr->fontPtr->descent; ! 616: if (scalePtr->tickInterval != 0) { ! 617: scalePtr->tickPixels = lineHeight; ! 618: } else { ! 619: scalePtr->tickPixels = 0; ! 620: } ! 621: if (scalePtr->showValue) { ! 622: scalePtr->valuePixels = lineHeight + SPACING; ! 623: } else { ! 624: scalePtr->valuePixels = 0; ! 625: } ! 626: if (scalePtr->labelLength != 0) { ! 627: scalePtr->labelPixels = lineHeight; ! 628: } else { ! 629: scalePtr->labelPixels = 0; ! 630: } ! 631: ! 632: Tk_GeometryRequest(scalePtr->tkwin, ! 633: scalePtr->length + 2*scalePtr->offset, ! 634: scalePtr->tickPixels + scalePtr->valuePixels ! 635: + scalePtr->width + 2*scalePtr->borderWidth ! 636: + scalePtr->labelPixels + 2*scalePtr->offset); ! 637: Tk_SetInternalBorder(scalePtr->tkwin, scalePtr->borderWidth); ! 638: return; ! 639: } ! 640: ! 641: /* ! 642: * Vertical scale: compute the amount of space needed for tick marks ! 643: * and current value by formatting strings for the two end points; ! 644: * use whichever length is longer. ! 645: */ ! 646: ! 647: sprintf(valueString, "%d", scalePtr->fromValue); ! 648: XTextExtents(scalePtr->fontPtr, valueString, strlen(valueString), ! 649: &dummy, &dummy, &dummy, &bbox); ! 650: scalePtr->tickPixels = bbox.rbearing + bbox.lbearing; ! 651: sprintf(valueString, "%d", scalePtr->toValue); ! 652: XTextExtents(scalePtr->fontPtr, valueString, strlen(valueString), ! 653: &dummy, &dummy, &dummy, &bbox); ! 654: if (scalePtr->tickPixels < bbox.rbearing + bbox.lbearing) { ! 655: scalePtr->tickPixels = bbox.rbearing + bbox.lbearing; ! 656: } ! 657: ! 658: /* ! 659: * Pad the value with a bit of extra space for prettier printing. ! 660: */ ! 661: ! 662: scalePtr->tickPixels += scalePtr->fontPtr->ascent/2; ! 663: scalePtr->valuePixels = scalePtr->tickPixels; ! 664: if (scalePtr->tickInterval == 0) { ! 665: scalePtr->tickPixels = 0; ! 666: } ! 667: if (!scalePtr->showValue) { ! 668: scalePtr->valuePixels = 0; ! 669: } ! 670: ! 671: if (scalePtr->labelLength == 0) { ! 672: scalePtr->labelPixels = 0; ! 673: } else { ! 674: XTextExtents(scalePtr->fontPtr, scalePtr->label, ! 675: scalePtr->labelLength, &dummy, &dummy, &dummy, &bbox); ! 676: scalePtr->labelPixels = bbox.rbearing + bbox.lbearing ! 677: + scalePtr->fontPtr->ascent; ! 678: } ! 679: Tk_GeometryRequest(scalePtr->tkwin, 4*scalePtr->borderWidth ! 680: + scalePtr->tickPixels + scalePtr->valuePixels + SPACING ! 681: + scalePtr->width + scalePtr->labelPixels, ! 682: scalePtr->length); ! 683: Tk_SetInternalBorder(scalePtr->tkwin, scalePtr->borderWidth); ! 684: } ! 685: ! 686: /* ! 687: *-------------------------------------------------------------- ! 688: * ! 689: * DisplayVerticalScale -- ! 690: * ! 691: * This procedure redraws the contents of a vertical scale ! 692: * window. It is invoked as a do-when-idle handler, so it only ! 693: * runs when there's nothing else for the application to do. ! 694: * ! 695: * Results: ! 696: * None. ! 697: * ! 698: * Side effects: ! 699: * Information appears on the screen. ! 700: * ! 701: *-------------------------------------------------------------- ! 702: */ ! 703: ! 704: static void ! 705: DisplayVerticalScale(clientData) ! 706: ClientData clientData; /* Information about widget. */ ! 707: { ! 708: register Scale *scalePtr = (Scale *) clientData; ! 709: register Tk_Window tkwin = scalePtr->tkwin; ! 710: int tickRightEdge, valueRightEdge, labelLeftEdge, scaleLeftEdge; ! 711: int totalPixels, x, y, width, height, shadowWidth, tickValue; ! 712: int relief; ! 713: Tk_3DBorder sliderBorder; ! 714: ! 715: if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { ! 716: goto done; ! 717: } ! 718: ! 719: /* ! 720: * Scanning from left to right across the window, the window ! 721: * will contain four columns: ticks, value, scale, and label. ! 722: * Compute the x-coordinate for each of the columns. ! 723: */ ! 724: ! 725: totalPixels = scalePtr->tickPixels + scalePtr->valuePixels ! 726: + 2*scalePtr->borderWidth + scalePtr->width ! 727: + 2*SPACING + scalePtr->labelPixels; ! 728: tickRightEdge = (Tk_Width(tkwin) - totalPixels)/2 + scalePtr->tickPixels; ! 729: valueRightEdge = tickRightEdge + scalePtr->valuePixels; ! 730: scaleLeftEdge = valueRightEdge + SPACING; ! 731: labelLeftEdge = scaleLeftEdge + 2*scalePtr->borderWidth ! 732: + scalePtr->width + scalePtr->fontPtr->ascent/2; ! 733: ! 734: /* ! 735: * Display the information from left to right across the window. ! 736: */ ! 737: ! 738: if (scalePtr->flags & REDRAW_OTHER) { ! 739: XClearWindow(Tk_Display(tkwin), Tk_WindowId(tkwin)); ! 740: ! 741: /* ! 742: * Display the tick marks. ! 743: */ ! 744: ! 745: if (scalePtr->tickPixels != 0) { ! 746: for (tickValue = scalePtr->fromValue; ; ! 747: tickValue += scalePtr->tickInterval) { ! 748: if (scalePtr->toValue > scalePtr->fromValue) { ! 749: if (tickValue > scalePtr->toValue) { ! 750: break; ! 751: } ! 752: } else { ! 753: if (tickValue < scalePtr->toValue) { ! 754: break; ! 755: } ! 756: } ! 757: DisplayVerticalValue(scalePtr, tickValue, tickRightEdge); ! 758: } ! 759: } ! 760: } ! 761: ! 762: /* ! 763: * Display the value, if it is desired. If not redisplaying the ! 764: * entire window, clear the area of the value to get rid of the ! 765: * old value displayed there. ! 766: */ ! 767: ! 768: if (scalePtr->showValue) { ! 769: if (!(scalePtr->flags & REDRAW_OTHER)) { ! 770: XClearArea(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 771: valueRightEdge-scalePtr->valuePixels, scalePtr->offset, ! 772: scalePtr->valuePixels, ! 773: Tk_Height(tkwin) - 2*scalePtr->offset, False); ! 774: } ! 775: DisplayVerticalValue(scalePtr, scalePtr->value, valueRightEdge); ! 776: } ! 777: ! 778: /* ! 779: * Display the scale and the slider. If not redisplaying the ! 780: * entire window, must clear the trench area to erase the old ! 781: * slider, but don't need to redraw the border. ! 782: */ ! 783: ! 784: if (scalePtr->flags & REDRAW_OTHER) { ! 785: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 786: scalePtr->bgBorder, scaleLeftEdge, scalePtr->offset, ! 787: scalePtr->width + 2*scalePtr->borderWidth, ! 788: Tk_Height(tkwin) - 2*scalePtr->offset, scalePtr->borderWidth, ! 789: TK_RELIEF_SUNKEN); ! 790: } else { ! 791: XClearArea(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 792: scaleLeftEdge + scalePtr->borderWidth, ! 793: scalePtr->offset + scalePtr->borderWidth, ! 794: scalePtr->width, ! 795: Tk_Height(tkwin) - 2*scalePtr->offset ! 796: - 2*scalePtr->borderWidth, False); ! 797: } ! 798: if (scalePtr->flags & ACTIVE) { ! 799: sliderBorder = scalePtr->activeBorder; ! 800: } else { ! 801: sliderBorder = scalePtr->sliderBorder; ! 802: } ! 803: width = scalePtr->width; ! 804: height = scalePtr->sliderLength/2; ! 805: x = scaleLeftEdge + scalePtr->borderWidth; ! 806: y = ValueToPixel(scalePtr, scalePtr->value) - height; ! 807: shadowWidth = scalePtr->borderWidth/2; ! 808: if (shadowWidth == 0) { ! 809: shadowWidth = 1; ! 810: } ! 811: relief = (scalePtr->flags & BUTTON_PRESSED) ? TK_RELIEF_SUNKEN ! 812: : TK_RELIEF_RAISED; ! 813: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), sliderBorder, ! 814: x, y, width, 2*height, shadowWidth, relief); ! 815: x += shadowWidth; ! 816: y += shadowWidth; ! 817: width -= 2*shadowWidth; ! 818: height -= shadowWidth; ! 819: Tk_Fill3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), sliderBorder, ! 820: x, y, width, height, shadowWidth, relief); ! 821: Tk_Fill3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), sliderBorder, ! 822: x, y+height, width, height, shadowWidth, relief); ! 823: ! 824: /* ! 825: * Draw the label to the right of the scale. ! 826: */ ! 827: ! 828: if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelPixels != 0)) { ! 829: XDrawString(Tk_Display(scalePtr->tkwin), Tk_WindowId(scalePtr->tkwin), ! 830: scalePtr->textGC, labelLeftEdge, ! 831: scalePtr->offset + (3*scalePtr->fontPtr->ascent)/2, ! 832: scalePtr->label, scalePtr->labelLength); ! 833: } ! 834: ! 835: /* ! 836: * Draw the window border. ! 837: */ ! 838: ! 839: if ((scalePtr->flags & REDRAW_OTHER) ! 840: && (scalePtr->relief != TK_RELIEF_FLAT)) { ! 841: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 842: scalePtr->bgBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), ! 843: scalePtr->borderWidth, scalePtr->relief); ! 844: } ! 845: ! 846: done: ! 847: scalePtr->flags &= ~REDRAW_ALL; ! 848: } ! 849: ! 850: /* ! 851: *---------------------------------------------------------------------- ! 852: * ! 853: * DisplayVerticalValue -- ! 854: * ! 855: * This procedure is called to display values (scale readings) ! 856: * for vertically-oriented scales. ! 857: * ! 858: * Results: ! 859: * None. ! 860: * ! 861: * Side effects: ! 862: * The numerical value corresponding to value is displayed with ! 863: * its right edge at "rightEdge", and at a vertical position in ! 864: * the scale that corresponds to "value". ! 865: * ! 866: *---------------------------------------------------------------------- ! 867: */ ! 868: ! 869: static void ! 870: DisplayVerticalValue(scalePtr, value, rightEdge) ! 871: register Scale *scalePtr; /* Information about widget in which to ! 872: * display value. */ ! 873: int value; /* Y-coordinate of number to display, ! 874: * specified in application coords, not ! 875: * in pixels (we'll compute pixels). */ ! 876: int rightEdge; /* X-coordinate of right edge of text, ! 877: * specified in pixels. */ ! 878: { ! 879: register Tk_Window tkwin = scalePtr->tkwin; ! 880: int y, dummy, length; ! 881: char valueString[30]; ! 882: XCharStruct bbox; ! 883: ! 884: y = ValueToPixel(scalePtr, value) + scalePtr->fontPtr->ascent/2; ! 885: sprintf(valueString, "%d", value); ! 886: length = strlen(valueString); ! 887: XTextExtents(scalePtr->fontPtr, valueString, length, ! 888: &dummy, &dummy, &dummy, &bbox); ! 889: ! 890: /* ! 891: * Adjust the y-coordinate if necessary to keep the text entirely ! 892: * inside the window. ! 893: */ ! 894: ! 895: if ((y - bbox.ascent) < scalePtr->offset) { ! 896: y = scalePtr->offset + bbox.ascent; ! 897: } ! 898: if ((y + bbox.descent) > (Tk_Height(tkwin) - scalePtr->offset)) { ! 899: y = Tk_Height(tkwin) - scalePtr->offset - bbox.descent; ! 900: } ! 901: XDrawString(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 902: scalePtr->textGC, rightEdge - bbox.rbearing, ! 903: y, valueString, length); ! 904: } ! 905: ! 906: /* ! 907: *-------------------------------------------------------------- ! 908: * ! 909: * DisplayHorizontalScale -- ! 910: * ! 911: * This procedure redraws the contents of a horizontal scale ! 912: * window. It is invoked as a do-when-idle handler, so it only ! 913: * runs when there's nothing else for the application to do. ! 914: * ! 915: * Results: ! 916: * None. ! 917: * ! 918: * Side effects: ! 919: * Information appears on the screen. ! 920: * ! 921: *-------------------------------------------------------------- ! 922: */ ! 923: ! 924: static void ! 925: DisplayHorizontalScale(clientData) ! 926: ClientData clientData; /* Information about widget. */ ! 927: { ! 928: register Scale *scalePtr = (Scale *) clientData; ! 929: register Tk_Window tkwin = scalePtr->tkwin; ! 930: int tickBottom, valueBottom, labelBottom, scaleBottom; ! 931: int totalPixels, x, y, width, height, shadowWidth, tickValue; ! 932: int relief; ! 933: Tk_3DBorder sliderBorder; ! 934: ! 935: if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { ! 936: goto done; ! 937: } ! 938: ! 939: /* ! 940: * Scanning from bottom to top across the window, the window ! 941: * will contain four rows: ticks, value, scale, and label. ! 942: * Compute the y-coordinate for each of the rows. ! 943: */ ! 944: ! 945: totalPixels = scalePtr->tickPixels + scalePtr->valuePixels ! 946: + 2*scalePtr->borderWidth + scalePtr->width ! 947: + scalePtr->labelPixels; ! 948: tickBottom = (Tk_Height(tkwin) + totalPixels)/2 - 1; ! 949: valueBottom = tickBottom - scalePtr->tickPixels; ! 950: scaleBottom = valueBottom - scalePtr->valuePixels; ! 951: labelBottom = scaleBottom - 2*scalePtr->borderWidth - scalePtr->width; ! 952: ! 953: /* ! 954: * Display the information from bottom to top across the window. ! 955: */ ! 956: ! 957: if (scalePtr->flags & REDRAW_OTHER) { ! 958: XClearWindow(Tk_Display(tkwin), Tk_WindowId(tkwin)); ! 959: ! 960: /* ! 961: * Display the tick marks. ! 962: */ ! 963: ! 964: if (scalePtr->tickPixels != 0) { ! 965: for (tickValue = scalePtr->fromValue; ; ! 966: tickValue += scalePtr->tickInterval) { ! 967: if (scalePtr->toValue > scalePtr->fromValue) { ! 968: if (tickValue > scalePtr->toValue) { ! 969: break; ! 970: } ! 971: } else { ! 972: if (tickValue < scalePtr->toValue) { ! 973: break; ! 974: } ! 975: } ! 976: DisplayHorizontalValue(scalePtr, tickValue, tickBottom); ! 977: } ! 978: } ! 979: } ! 980: ! 981: /* ! 982: * Display the value, if it is desired. If not redisplaying the ! 983: * entire window, clear the area of the value to get rid of the ! 984: * old value displayed there. ! 985: */ ! 986: ! 987: if (scalePtr->showValue) { ! 988: if (!(scalePtr->flags & REDRAW_OTHER)) { ! 989: XClearArea(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 990: scalePtr->offset, scaleBottom + 1, ! 991: Tk_Width(tkwin) - 2*scalePtr->offset, ! 992: valueBottom - scaleBottom, False); ! 993: } ! 994: DisplayHorizontalValue(scalePtr, scalePtr->value, valueBottom); ! 995: } ! 996: ! 997: /* ! 998: * Display the scale and the slider. If not redisplaying the ! 999: * entire window, must clear the trench area to erase the old ! 1000: * slider, but don't need to redraw the border. ! 1001: */ ! 1002: ! 1003: y = scaleBottom - 2*scalePtr->borderWidth - scalePtr->width + 1; ! 1004: if (scalePtr->flags & REDRAW_OTHER) { ! 1005: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 1006: scalePtr->bgBorder, scalePtr->offset, y, ! 1007: Tk_Width(tkwin) - 2*scalePtr->offset, ! 1008: scalePtr->width + 2*scalePtr->borderWidth, ! 1009: scalePtr->borderWidth, TK_RELIEF_SUNKEN); ! 1010: } else { ! 1011: XClearArea(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 1012: scalePtr->offset + scalePtr->borderWidth, ! 1013: y + scalePtr->borderWidth, ! 1014: Tk_Width(tkwin) - 2*scalePtr->offset - 2*scalePtr->borderWidth, ! 1015: scalePtr->width, False); ! 1016: } ! 1017: if (scalePtr->flags & ACTIVE) { ! 1018: sliderBorder = scalePtr->activeBorder; ! 1019: } else { ! 1020: sliderBorder = scalePtr->sliderBorder; ! 1021: } ! 1022: width = scalePtr->sliderLength/2; ! 1023: height = scalePtr->width; ! 1024: x = ValueToPixel(scalePtr, scalePtr->value) - width; ! 1025: y += scalePtr->borderWidth; ! 1026: shadowWidth = scalePtr->borderWidth/2; ! 1027: if (shadowWidth == 0) { ! 1028: shadowWidth = 1; ! 1029: } ! 1030: relief = (scalePtr->flags & BUTTON_PRESSED) ? TK_RELIEF_SUNKEN ! 1031: : TK_RELIEF_RAISED; ! 1032: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), sliderBorder, ! 1033: x, y, 2*width, height, shadowWidth, relief); ! 1034: x += shadowWidth; ! 1035: y += shadowWidth; ! 1036: width -= shadowWidth; ! 1037: height -= 2*shadowWidth; ! 1038: Tk_Fill3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), sliderBorder, ! 1039: x, y, width, height, shadowWidth, relief); ! 1040: Tk_Fill3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), sliderBorder, ! 1041: x+width, y, width, height, shadowWidth, relief); ! 1042: ! 1043: /* ! 1044: * Draw the label to the top of the scale. ! 1045: */ ! 1046: ! 1047: if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelPixels != 0)) { ! 1048: XDrawString(Tk_Display(scalePtr->tkwin), Tk_WindowId(scalePtr->tkwin), ! 1049: scalePtr->textGC, scalePtr->offset + scalePtr->fontPtr->ascent/2, ! 1050: labelBottom - scalePtr->fontPtr->descent, ! 1051: scalePtr->label, scalePtr->labelLength); ! 1052: } ! 1053: ! 1054: /* ! 1055: * Draw the window border. ! 1056: */ ! 1057: ! 1058: if ((scalePtr->flags & REDRAW_OTHER) ! 1059: && (scalePtr->relief != TK_RELIEF_FLAT)) { ! 1060: Tk_Draw3DRectangle(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 1061: scalePtr->bgBorder, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), ! 1062: scalePtr->borderWidth, scalePtr->relief); ! 1063: } ! 1064: ! 1065: done: ! 1066: scalePtr->flags &= ~REDRAW_ALL; ! 1067: } ! 1068: ! 1069: /* ! 1070: *---------------------------------------------------------------------- ! 1071: * ! 1072: * DisplayHorizontalValue -- ! 1073: * ! 1074: * This procedure is called to display values (scale readings) ! 1075: * for horizontally-oriented scales. ! 1076: * ! 1077: * Results: ! 1078: * None. ! 1079: * ! 1080: * Side effects: ! 1081: * The numerical value corresponding to value is displayed with ! 1082: * its bottom edge at "bottom", and at a horizontal position in ! 1083: * the scale that corresponds to "value". ! 1084: * ! 1085: *---------------------------------------------------------------------- ! 1086: */ ! 1087: ! 1088: static void ! 1089: DisplayHorizontalValue(scalePtr, value, bottom) ! 1090: register Scale *scalePtr; /* Information about widget in which to ! 1091: * display value. */ ! 1092: int value; /* Y-coordinate of number to display, ! 1093: * specified in application coords, not ! 1094: * in pixels (we'll compute pixels). */ ! 1095: int bottom; /* Y-coordinate of bottom edge of text, ! 1096: * specified in pixels. */ ! 1097: { ! 1098: register Tk_Window tkwin = scalePtr->tkwin; ! 1099: int x, y, dummy, length; ! 1100: char valueString[30]; ! 1101: XCharStruct bbox; ! 1102: ! 1103: x = ValueToPixel(scalePtr, value); ! 1104: y = bottom - scalePtr->fontPtr->descent; ! 1105: sprintf(valueString, "%d", value); ! 1106: length = strlen(valueString); ! 1107: XTextExtents(scalePtr->fontPtr, valueString, length, ! 1108: &dummy, &dummy, &dummy, &bbox); ! 1109: ! 1110: /* ! 1111: * Adjust the x-coordinate if necessary to keep the text entirely ! 1112: * inside the window. ! 1113: */ ! 1114: ! 1115: x -= (bbox.lbearing + bbox.rbearing)/2; ! 1116: if ((x - bbox.lbearing) < scalePtr->offset) { ! 1117: x = scalePtr->offset + bbox.lbearing; ! 1118: } ! 1119: if ((y + bbox.rbearing) > (Tk_Width(tkwin) - scalePtr->offset)) { ! 1120: x = Tk_Width(tkwin) - scalePtr->offset - bbox.rbearing; ! 1121: } ! 1122: XDrawString(Tk_Display(tkwin), Tk_WindowId(tkwin), ! 1123: scalePtr->textGC, x, y, valueString, length); ! 1124: } ! 1125: ! 1126: /* ! 1127: *---------------------------------------------------------------------- ! 1128: * ! 1129: * PixelToValue -- ! 1130: * ! 1131: * Given a pixel within a scale window, return the scale ! 1132: * reading corresponding to that pixel. ! 1133: * ! 1134: * Results: ! 1135: * An integer scale reading. ! 1136: * ! 1137: * Side effects: ! 1138: * None. ! 1139: * ! 1140: *---------------------------------------------------------------------- ! 1141: */ ! 1142: ! 1143: static int ! 1144: PixelToValue(scalePtr, x, y) ! 1145: register Scale *scalePtr; /* Information about widget. */ ! 1146: int x, y; /* Coordinates of point within ! 1147: * window. */ ! 1148: { ! 1149: int value, pixelRange; ! 1150: ! 1151: if (scalePtr->vertical) { ! 1152: pixelRange = Tk_Height(scalePtr->tkwin) - scalePtr->sliderLength ! 1153: - 2*scalePtr->offset - 2*scalePtr->borderWidth; ! 1154: value = y; ! 1155: } else { ! 1156: pixelRange = Tk_Width(scalePtr->tkwin) - scalePtr->sliderLength ! 1157: - 2*scalePtr->offset - 2*scalePtr->borderWidth; ! 1158: value = x; ! 1159: } ! 1160: ! 1161: if (pixelRange <= 0) { ! 1162: /* ! 1163: * Not enough room for the slider to actually slide: just return ! 1164: * the scale's current value. ! 1165: */ ! 1166: ! 1167: return scalePtr->value; ! 1168: } ! 1169: value -= scalePtr->sliderLength/2 + scalePtr->offset ! 1170: + scalePtr->borderWidth; ! 1171: if (value < 0) { ! 1172: value = 0; ! 1173: } ! 1174: if (value > pixelRange) { ! 1175: value = pixelRange; ! 1176: } ! 1177: if (scalePtr->toValue > scalePtr->fromValue) { ! 1178: value = scalePtr->fromValue + ! 1179: ((value * (scalePtr->toValue - scalePtr->fromValue)) ! 1180: + pixelRange/2)/pixelRange; ! 1181: } else { ! 1182: value = scalePtr->toValue + ! 1183: (((pixelRange - value) ! 1184: * (scalePtr->fromValue - scalePtr->toValue)) ! 1185: + pixelRange/2)/pixelRange; ! 1186: } ! 1187: return value; ! 1188: } ! 1189: ! 1190: /* ! 1191: *---------------------------------------------------------------------- ! 1192: * ! 1193: * ValueToPixel -- ! 1194: * ! 1195: * Given a reading of the scale, return the x-coordinate or ! 1196: * y-coordinate corresponding to that reading, depending on ! 1197: * whether the scale is vertical or horizontal, respectively. ! 1198: * ! 1199: * Results: ! 1200: * An integer value giving the pixel location corresponding ! 1201: * to reading. The value is restricted to lie within the ! 1202: * defined range for the scale. ! 1203: * ! 1204: * Side effects: ! 1205: * None. ! 1206: * ! 1207: *---------------------------------------------------------------------- ! 1208: */ ! 1209: ! 1210: static int ! 1211: ValueToPixel(scalePtr, value) ! 1212: register Scale *scalePtr; /* Information about widget. */ ! 1213: int value; /* Reading of the widget. */ ! 1214: { ! 1215: int y, pixelRange, valueRange; ! 1216: ! 1217: valueRange = scalePtr->toValue - scalePtr->fromValue; ! 1218: pixelRange = (scalePtr->vertical ? Tk_Height(scalePtr->tkwin) ! 1219: : Tk_Width(scalePtr->tkwin)) - scalePtr->sliderLength ! 1220: - 2*scalePtr->offset - 2*scalePtr->borderWidth; ! 1221: y = ((value - scalePtr->fromValue) * pixelRange ! 1222: + valueRange/2) / valueRange; ! 1223: if (y < 0) { ! 1224: y = 0; ! 1225: } else if (y > pixelRange) { ! 1226: y = pixelRange; ! 1227: } ! 1228: y += scalePtr->sliderLength/2 + scalePtr->offset + scalePtr->borderWidth; ! 1229: return y; ! 1230: } ! 1231: ! 1232: /* ! 1233: *-------------------------------------------------------------- ! 1234: * ! 1235: * ScaleEventProc -- ! 1236: * ! 1237: * This procedure is invoked by the Tk dispatcher for various ! 1238: * events on scales. ! 1239: * ! 1240: * Results: ! 1241: * None. ! 1242: * ! 1243: * Side effects: ! 1244: * When the window gets deleted, internal structures get ! 1245: * cleaned up. When it gets exposed, it is redisplayed. ! 1246: * ! 1247: *-------------------------------------------------------------- ! 1248: */ ! 1249: ! 1250: static void ! 1251: ScaleEventProc(clientData, eventPtr) ! 1252: ClientData clientData; /* Information about window. */ ! 1253: XEvent *eventPtr; /* Information about event. */ ! 1254: { ! 1255: Scale *scalePtr = (Scale *) clientData; ! 1256: ! 1257: if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { ! 1258: EventuallyRedrawScale(scalePtr, REDRAW_ALL); ! 1259: } else if (eventPtr->type == DestroyNotify) { ! 1260: Tcl_DeleteCommand(scalePtr->interp, Tk_PathName(scalePtr->tkwin)); ! 1261: scalePtr->tkwin = NULL; ! 1262: if (scalePtr->flags & REDRAW_ALL) { ! 1263: if (scalePtr->vertical) { ! 1264: Tk_CancelIdleCall(DisplayVerticalScale, (ClientData) scalePtr); ! 1265: } else { ! 1266: Tk_CancelIdleCall(DisplayHorizontalScale, ! 1267: (ClientData) scalePtr); ! 1268: } ! 1269: } ! 1270: Tk_EventuallyFree((ClientData) scalePtr, DestroyScale); ! 1271: } else if (eventPtr->type == ConfigureNotify) { ! 1272: ComputeScaleGeometry(scalePtr); ! 1273: } ! 1274: } ! 1275: ! 1276: /* ! 1277: *-------------------------------------------------------------- ! 1278: * ! 1279: * ScaleMouseProc -- ! 1280: * ! 1281: * This procedure is called back by Tk in response to ! 1282: * mouse events such as window entry, window exit, mouse ! 1283: * motion, and button presses. ! 1284: * ! 1285: * Results: ! 1286: * None. ! 1287: * ! 1288: * Side effects: ! 1289: * This procedure implements the "feel" of the scale by ! 1290: * issuing commands in response to button presses and mouse ! 1291: * motion. ! 1292: * ! 1293: *-------------------------------------------------------------- ! 1294: */ ! 1295: ! 1296: static void ! 1297: ScaleMouseProc(clientData, eventPtr) ! 1298: ClientData clientData; /* Information about window. */ ! 1299: register XEvent *eventPtr; /* Information about event. */ ! 1300: { ! 1301: register Scale *scalePtr = (Scale *) clientData; ! 1302: ! 1303: if (scalePtr->state != tkNormalUid) { ! 1304: return; ! 1305: } ! 1306: ! 1307: Tk_Preserve((ClientData) scalePtr); ! 1308: if (eventPtr->type == EnterNotify) { ! 1309: scalePtr->flags |= ACTIVE; ! 1310: EventuallyRedrawScale(scalePtr, REDRAW_SLIDER); ! 1311: } else if (eventPtr->type == LeaveNotify) { ! 1312: scalePtr->flags &= ~ACTIVE; ! 1313: EventuallyRedrawScale(scalePtr, REDRAW_SLIDER); ! 1314: } else if ((eventPtr->type == MotionNotify) ! 1315: && (scalePtr->flags & BUTTON_PRESSED)) { ! 1316: SetScaleValue(scalePtr, PixelToValue(scalePtr, ! 1317: eventPtr->xmotion.x, eventPtr->xmotion.y)); ! 1318: } else if ((eventPtr->type == ButtonPress) ! 1319: /* && (eventPtr->xbutton.button == Button1) */ ! 1320: && (eventPtr->xbutton.state == 0)) { ! 1321: scalePtr->flags |= BUTTON_PRESSED; ! 1322: SetScaleValue(scalePtr, PixelToValue(scalePtr, ! 1323: eventPtr->xbutton.x, eventPtr->xbutton.y)); ! 1324: EventuallyRedrawScale(scalePtr, REDRAW_SLIDER); ! 1325: } else if ((eventPtr->type == ButtonRelease) ! 1326: /* && (eventPtr->xbutton.button == Button1) */ ! 1327: && (scalePtr->flags & BUTTON_PRESSED)) { ! 1328: scalePtr->flags &= ~BUTTON_PRESSED; ! 1329: EventuallyRedrawScale(scalePtr, REDRAW_SLIDER); ! 1330: } ! 1331: Tk_Release((ClientData) scalePtr); ! 1332: } ! 1333: ! 1334: /* ! 1335: *-------------------------------------------------------------- ! 1336: * ! 1337: * SetScaleValue -- ! 1338: * ! 1339: * This procedure changes the value of a scale and invokes ! 1340: * a Tcl command to reflect the current position of a scale ! 1341: * ! 1342: * Results: ! 1343: * None. ! 1344: * ! 1345: * Side effects: ! 1346: * A Tcl command is invoked, and an additional error-processing ! 1347: * command may also be invoked. The scale's slider is redrawn. ! 1348: * ! 1349: *-------------------------------------------------------------- ! 1350: */ ! 1351: ! 1352: static void ! 1353: SetScaleValue(scalePtr, value) ! 1354: register Scale *scalePtr; /* Info about widget. */ ! 1355: int value; /* New value for scale. Gets ! 1356: * adjusted if it's off the scale. */ ! 1357: { ! 1358: int result; ! 1359: char string[20]; ! 1360: ! 1361: if ((value < scalePtr->fromValue) ! 1362: ^ (scalePtr->toValue < scalePtr->fromValue)) { ! 1363: value = scalePtr->fromValue; ! 1364: } ! 1365: if ((value > scalePtr->toValue) ! 1366: ^ (scalePtr->toValue < scalePtr->fromValue)) { ! 1367: value = scalePtr->toValue; ! 1368: } ! 1369: if (value == scalePtr->value) { ! 1370: return; ! 1371: } ! 1372: scalePtr->value = value; ! 1373: EventuallyRedrawScale(scalePtr, REDRAW_SLIDER); ! 1374: ! 1375: sprintf(string, " %d", scalePtr->value); ! 1376: result = Tcl_VarEval(scalePtr->interp, scalePtr->command, string, ! 1377: (char *) NULL); ! 1378: if (result != TCL_OK) { ! 1379: TkBindError(scalePtr->interp); ! 1380: } ! 1381: } ! 1382: ! 1383: /* ! 1384: *-------------------------------------------------------------- ! 1385: * ! 1386: * EventuallyRedrawScale -- ! 1387: * ! 1388: * Arrange for part or all of a scale widget to redrawn at ! 1389: * the next convenient time in the future. ! 1390: * ! 1391: * Results: ! 1392: * None. ! 1393: * ! 1394: * Side effects: ! 1395: * If "what" is REDRAW_SLIDER then just the slider and the ! 1396: * value readout will be redrawn; if "what" is REDRAW_ALL ! 1397: * then the entire widget will be redrawn. ! 1398: * ! 1399: *-------------------------------------------------------------- ! 1400: */ ! 1401: ! 1402: static void ! 1403: EventuallyRedrawScale(scalePtr, what) ! 1404: register Scale *scalePtr; /* Information about widget. */ ! 1405: int what; /* What to redraw: REDRAW_SLIDER ! 1406: * or REDRAW_ALL. */ ! 1407: { ! 1408: if ((what == 0) || (scalePtr->tkwin == NULL) ! 1409: || !Tk_IsMapped(scalePtr->tkwin)) { ! 1410: return; ! 1411: } ! 1412: if ((scalePtr->flags & REDRAW_ALL) == 0) { ! 1413: if (scalePtr->vertical) { ! 1414: Tk_DoWhenIdle(DisplayVerticalScale, (ClientData) scalePtr); ! 1415: } else { ! 1416: Tk_DoWhenIdle(DisplayHorizontalScale, (ClientData) scalePtr); ! 1417: } ! 1418: } ! 1419: scalePtr->flags |= what; ! 1420: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.