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, 
   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. 
  20 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkScale.c,v 1.28 92/08/21 11:45:25 ouster Exp $ SPRITE (Berkeley)"; 
  28  * A data structure of the following type is kept for each scale 
  29  * widget managed by this file: 
  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 
  37     Tcl_Interp 
*interp
;         /* Interpreter associated with scale. */ 
  38     Tk_Uid orientUid
;           /* Orientation for window ("vertical" or 
  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 
  45     int toValue
;                /* Value corresponding to right or bottom 
  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. 
  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. */ 
  62      * Information used when displaying widget: 
  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, 
  75     int length
;                 /* Desired long dimension of scale, 
  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. */ 
  95      * Miscellaneous information: 
  98     Cursor cursor
;              /* Current cursor for window, or None. */ 
  99     int flags
;                  /* Various flags;  see below for 
 104  * Flag bits for scales: 
 106  * REDRAW_SLIDER -              1 means slider (and numerical readout) need 
 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 
 113  * BUTTON_PRESSED -             1 means a button press is in progress, so 
 114  *                              slider should appear depressed and should be 
 118 #define REDRAW_SLIDER           1 
 119 #define REDRAW_OTHER            2 
 122 #define BUTTON_PRESSED          8 
 125  * Space to leave between scale area and text. 
 131  * Information used for argv parsing. 
 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
), 
 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
, 
 202  * Forward declarations for procedures defined later in this file: 
 205 static void             ComputeScaleGeometry 
_ANSI_ARGS_((Scale 
*scalePtr
)); 
 206 static int              ConfigureScale 
_ANSI_ARGS_((Tcl_Interp 
*interp
, 
 207                             Scale 
*scalePtr
, int argc
, char **argv
, 
 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
, 
 220 static int              PixelToValue 
_ANSI_ARGS_((Scale 
*scalePtr
, int x
, 
 222 static void             ScaleEventProc 
_ANSI_ARGS_((ClientData clientData
, 
 224 static void             ScaleMouseProc 
_ANSI_ARGS_((ClientData clientData
, 
 226 static int              ScaleWidgetCmd 
_ANSI_ARGS_((ClientData clientData
, 
 227                             Tcl_Interp 
*interp
, int argc
, char **argv
)); 
 228 static void             SetScaleValue 
_ANSI_ARGS_((Scale 
*scalePtr
, 
 230 static int              ValueToPixel 
_ANSI_ARGS_((Scale 
*scalePtr
, int value
)); 
 233  *-------------------------------------------------------------- 
 237  *      This procedure is invoked to process the "scale" Tcl 
 238  *      command.  See the user documentation for details on what 
 242  *      A standard Tcl result. 
 245  *      See the user documentation. 
 247  *-------------------------------------------------------------- 
 251 Tk_ScaleCmd(clientData
, interp
, argc
, argv
) 
 252     ClientData clientData
;              /* Main window associated with 
 254     Tcl_Interp 
*interp
;         /* Current interpreter. */ 
 255     int argc
;                   /* Number of arguments. */ 
 256     char **argv
;                /* Argument strings. */ 
 258     Tk_Window tkwin 
= (Tk_Window
) clientData
; 
 259     register Scale 
*scalePtr
; 
 263         Tcl_AppendResult(interp
, "wrong # args: should be \"", 
 264                 argv
[0], " pathName ?options?\"", (char *) NULL
); 
 268     new = Tk_CreateWindowFromPath(interp
, tkwin
, argv
[1], (char *) NULL
); 
 274      * Initialize fields that won't be initialized by ConfigureScale, 
 275      * or which ConfigureScale expects to have reasonable values 
 276      * (e.g. resource pointers). 
 279     scalePtr 
= (Scale 
*) ckalloc(sizeof(Scale
)); 
 280     scalePtr
->tkwin 
= new; 
 281     scalePtr
->interp 
= interp
; 
 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
; 
 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
) { 
 307     interp
->result 
= Tk_PathName(scalePtr
->tkwin
); 
 311     Tk_DestroyWindow(scalePtr
->tkwin
); 
 316  *-------------------------------------------------------------- 
 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. 
 325  *      A standard Tcl result. 
 328  *      See the user documentation. 
 330  *-------------------------------------------------------------- 
 334 ScaleWidgetCmd(clientData
, interp
, argc
, argv
) 
 335     ClientData clientData
;              /* Information about scale 
 337     Tcl_Interp 
*interp
;                 /* Current interpreter. */ 
 338     int argc
;                           /* Number of arguments. */ 
 339     char **argv
;                        /* Argument strings. */ 
 341     register Scale 
*scalePtr 
= (Scale 
*) clientData
; 
 347         Tcl_AppendResult(interp
, "wrong # args: should be \"", 
 348                 argv
[0], " option ?arg arg ...?\"", (char *) NULL
); 
 351     Tk_Preserve((ClientData
) scalePtr
); 
 353     length 
= strlen(argv
[1]); 
 354     if ((c 
== 'c') && (strncmp(argv
[1], "configure", length
) == 0)) { 
 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); 
 362             result 
= ConfigureScale(interp
, scalePtr
, argc
-2, argv
+2, 
 363                     TK_CONFIG_ARGV_ONLY
); 
 365     } else if ((c 
== 'g') && (strncmp(argv
[1], "get", length
) == 0)) { 
 367             Tcl_AppendResult(interp
, "wrong # args: should be \"", 
 368                     argv
[0], " get\"", (char *) NULL
); 
 371         sprintf(interp
->result
, "%d", scalePtr
->value
); 
 372     } else if ((c 
== 's') && (strncmp(argv
[1], "set", length
) == 0)) { 
 376             Tcl_AppendResult(interp
, "wrong # args: should be \"", 
 377                     argv
[0], " set value\"", (char *) NULL
); 
 380         if (Tcl_GetInt(interp
, argv
[2], &value
) != TCL_OK
) { 
 383         if (scalePtr
->state 
== tkNormalUid
) { 
 384             if ((value 
< scalePtr
->fromValue
) 
 385                     ^ (scalePtr
->toValue 
< scalePtr
->fromValue
)) { 
 386                 value 
= scalePtr
->fromValue
; 
 388             if ((value 
> scalePtr
->toValue
) 
 389                     ^ (scalePtr
->toValue 
< scalePtr
->fromValue
)) { 
 390                 value 
= scalePtr
->toValue
; 
 392             SetScaleValue(scalePtr
, value
); 
 395         Tcl_AppendResult(interp
, "bad option \"", argv
[1], 
 396                 "\":  must be configure, get, or set", (char *) NULL
); 
 399     Tk_Release((ClientData
) scalePtr
); 
 403     Tk_Release((ClientData
) scalePtr
); 
 408  *---------------------------------------------------------------------- 
 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). 
 420  *      Everything associated with the scale is freed up. 
 422  *---------------------------------------------------------------------- 
 426 DestroyScale(clientData
) 
 427     ClientData clientData
;      /* Info about scale widget. */ 
 429     register Scale 
*scalePtr 
= (Scale 
*) clientData
; 
 431     if (scalePtr
->command 
!= NULL
) { 
 432         ckfree(scalePtr
->command
); 
 434     if (scalePtr
->label 
!= NULL
) { 
 435         ckfree(scalePtr
->label
); 
 437     if (scalePtr
->bgBorder 
!= NULL
) { 
 438         Tk_Free3DBorder(scalePtr
->bgBorder
); 
 440     if (scalePtr
->sliderBorder 
!= NULL
) { 
 441         Tk_Free3DBorder(scalePtr
->sliderBorder
); 
 443     if (scalePtr
->activeBorder 
!= NULL
) { 
 444         Tk_Free3DBorder(scalePtr
->activeBorder
); 
 446     if (scalePtr
->fontPtr 
!= NULL
) { 
 447         Tk_FreeFontStruct(scalePtr
->fontPtr
); 
 449     if (scalePtr
->textColorPtr 
!= NULL
) { 
 450         Tk_FreeColor(scalePtr
->textColorPtr
); 
 452     if (scalePtr
->textGC 
!= None
) { 
 453         Tk_FreeGC(scalePtr
->textGC
); 
 455     if (scalePtr
->cursor 
!= None
) { 
 456         Tk_FreeCursor(scalePtr
->cursor
); 
 458     ckfree((char *) scalePtr
); 
 462  *---------------------------------------------------------------------- 
 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. 
 471  *      The return value is a standard Tcl result.  If TCL_ERROR is 
 472  *      returned, then interp->result contains an error message. 
 475  *      Configuration information, such as colors, border width, 
 476  *      etc. get set for scalePtr;  old resources get freed, 
 479  *---------------------------------------------------------------------- 
 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. */ 
 495     if (Tk_ConfigureWidget(interp
, scalePtr
->tkwin
, configSpecs
, 
 496             argc
, argv
, (char *) scalePtr
, flags
) != TCL_OK
) { 
 501      * A few options need special processing, such as parsing the 
 502      * orientation or setting the background from a 3-D border. 
 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; 
 511         Tcl_AppendResult(interp
, "bad orientation \"", scalePtr
->orientUid
, 
 512                 "\": must be vertical or horizontal", (char *) NULL
); 
 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
; 
 525      * Make sure that the tick interval has the right sign so that 
 526      * addition moves from fromValue to toValue. 
 529     if ((scalePtr
->tickInterval 
< 0) 
 530             ^ ((scalePtr
->toValue 
- scalePtr
->fromValue
) <  0)) { 
 531         scalePtr
->tickInterval 
= -scalePtr
->tickInterval
; 
 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 
 540     SetScaleValue(scalePtr
, scalePtr
->value
); 
 542     if (scalePtr
->command 
!= NULL
) { 
 543         scalePtr
->commandLength 
= strlen(scalePtr
->command
); 
 545         scalePtr
->commandLength 
= 0; 
 548     if (scalePtr
->label 
!= NULL
) { 
 549         scalePtr
->labelLength 
= strlen(scalePtr
->label
); 
 551         scalePtr
->labelLength 
= 0; 
 554     Tk_SetBackgroundFromBorder(scalePtr
->tkwin
, scalePtr
->bgBorder
); 
 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
); 
 562     scalePtr
->textGC 
= newGC
; 
 564     if (scalePtr
->relief 
!= TK_RELIEF_FLAT
) { 
 565         scalePtr
->offset 
= scalePtr
->borderWidth
; 
 567         scalePtr
->offset 
= 0; 
 571      * Recompute display-related information, and let the geometry 
 572      * manager know how much space is needed now. 
 575     ComputeScaleGeometry(scalePtr
); 
 577     EventuallyRedrawScale(scalePtr
, REDRAW_ALL
); 
 582  *---------------------------------------------------------------------- 
 584  * ComputeScaleGeometry -- 
 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. 
 594  *      Display-related numbers get changed in *scrollPtr.  The 
 595  *      geometry manager gets told about the window's preferred size. 
 597  *---------------------------------------------------------------------- 
 601 ComputeScaleGeometry(scalePtr
) 
 602     register Scale 
*scalePtr
;           /* Information about widget. */ 
 605     char valueString
[30]; 
 606     int dummy
, lineHeight
; 
 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. 
 614     if (!scalePtr
->vertical
) { 
 615         lineHeight 
= scalePtr
->fontPtr
->ascent 
+ scalePtr
->fontPtr
->descent
; 
 616         if (scalePtr
->tickInterval 
!= 0) { 
 617             scalePtr
->tickPixels 
= lineHeight
; 
 619             scalePtr
->tickPixels 
= 0; 
 621         if (scalePtr
->showValue
) { 
 622             scalePtr
->valuePixels 
= lineHeight 
+ SPACING
; 
 624             scalePtr
->valuePixels 
= 0; 
 626         if (scalePtr
->labelLength 
!= 0) { 
 627             scalePtr
->labelPixels 
= lineHeight
; 
 629             scalePtr
->labelPixels 
= 0; 
 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
); 
 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. 
 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
; 
 659      * Pad the value with a bit of extra space for prettier printing. 
 662     scalePtr
->tickPixels 
+= scalePtr
->fontPtr
->ascent
/2; 
 663     scalePtr
->valuePixels 
= scalePtr
->tickPixels
; 
 664     if (scalePtr
->tickInterval 
== 0) { 
 665         scalePtr
->tickPixels 
= 0; 
 667     if (!scalePtr
->showValue
) { 
 668         scalePtr
->valuePixels 
= 0; 
 671     if (scalePtr
->labelLength 
== 0) { 
 672         scalePtr
->labelPixels 
= 0; 
 674         XTextExtents(scalePtr
->fontPtr
, scalePtr
->label
, 
 675                 scalePtr
->labelLength
, &dummy
, &dummy
, &dummy
, &bbox
); 
 676         scalePtr
->labelPixels 
= bbox
.rbearing 
+ bbox
.lbearing
 
 677                 + scalePtr
->fontPtr
->ascent
; 
 679     Tk_GeometryRequest(scalePtr
->tkwin
, 4*scalePtr
->borderWidth
 
 680             + scalePtr
->tickPixels 
+ scalePtr
->valuePixels 
+ SPACING
 
 681             + scalePtr
->width 
+ scalePtr
->labelPixels
, 
 683     Tk_SetInternalBorder(scalePtr
->tkwin
, scalePtr
->borderWidth
); 
 687  *-------------------------------------------------------------- 
 689  * DisplayVerticalScale -- 
 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. 
 699  *      Information appears on the screen. 
 701  *-------------------------------------------------------------- 
 705 DisplayVerticalScale(clientData
) 
 706     ClientData clientData
;      /* Information about widget. */ 
 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
; 
 713     Tk_3DBorder sliderBorder
; 
 715     if ((scalePtr
->tkwin 
== NULL
) || !Tk_IsMapped(tkwin
)) { 
 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. 
 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; 
 735      * Display the information from left to right across the window. 
 738     if (scalePtr
->flags 
& REDRAW_OTHER
) { 
 739         XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
)); 
 742          * Display the tick marks. 
 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
) { 
 753                     if (tickValue 
< scalePtr
->toValue
) { 
 757                 DisplayVerticalValue(scalePtr
, tickValue
, tickRightEdge
); 
 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. 
 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
); 
 775         DisplayVerticalValue(scalePtr
, scalePtr
->value
, valueRightEdge
); 
 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. 
 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
, 
 791         XClearArea(Tk_Display(tkwin
), Tk_WindowId(tkwin
), 
 792                 scaleLeftEdge 
+ scalePtr
->borderWidth
, 
 793                 scalePtr
->offset 
+ scalePtr
->borderWidth
, 
 795                 Tk_Height(tkwin
) - 2*scalePtr
->offset
 
 796                 - 2*scalePtr
->borderWidth
, False
); 
 798     if (scalePtr
->flags 
& ACTIVE
) { 
 799         sliderBorder 
= scalePtr
->activeBorder
; 
 801         sliderBorder 
= scalePtr
->sliderBorder
; 
 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) { 
 811     relief 
= (scalePtr
->flags 
& BUTTON_PRESSED
) ? TK_RELIEF_SUNKEN
 
 813     Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
), sliderBorder
, 
 814             x
, y
, width
, 2*height
, shadowWidth
, relief
); 
 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
); 
 825      * Draw the label to the right of the scale. 
 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
); 
 836      * Draw the window border. 
 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
); 
 847     scalePtr
->flags 
&= ~REDRAW_ALL
; 
 851  *---------------------------------------------------------------------- 
 853  * DisplayVerticalValue -- 
 855  *      This procedure is called to display values (scale readings) 
 856  *      for vertically-oriented scales. 
 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". 
 866  *---------------------------------------------------------------------- 
 870 DisplayVerticalValue(scalePtr
, value
, rightEdge
) 
 871     register Scale 
*scalePtr
;   /* Information about widget in which to 
 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. */ 
 879     register Tk_Window tkwin 
= scalePtr
->tkwin
; 
 880     int y
, dummy
, length
; 
 881     char valueString
[30]; 
 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
); 
 891      * Adjust the y-coordinate if necessary to keep the text entirely 
 895     if ((y 
- bbox
.ascent
) < scalePtr
->offset
) { 
 896         y 
= scalePtr
->offset 
+ bbox
.ascent
; 
 898     if ((y 
+ bbox
.descent
) > (Tk_Height(tkwin
) - scalePtr
->offset
)) { 
 899         y 
= Tk_Height(tkwin
) - scalePtr
->offset 
- bbox
.descent
; 
 901     XDrawString(Tk_Display(tkwin
), Tk_WindowId(tkwin
), 
 902             scalePtr
->textGC
, rightEdge 
- bbox
.rbearing
, 
 903             y
, valueString
, length
); 
 907  *-------------------------------------------------------------- 
 909  * DisplayHorizontalScale -- 
 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. 
 919  *      Information appears on the screen. 
 921  *-------------------------------------------------------------- 
 925 DisplayHorizontalScale(clientData
) 
 926     ClientData clientData
;      /* Information about widget. */ 
 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
; 
 933     Tk_3DBorder sliderBorder
; 
 935     if ((scalePtr
->tkwin 
== NULL
) || !Tk_IsMapped(tkwin
)) { 
 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. 
 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
; 
 954      * Display the information from bottom to top across the window. 
 957     if (scalePtr
->flags 
& REDRAW_OTHER
) { 
 958         XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
)); 
 961          * Display the tick marks. 
 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
) { 
 972                     if (tickValue 
< scalePtr
->toValue
) { 
 976                 DisplayHorizontalValue(scalePtr
, tickValue
, tickBottom
); 
 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. 
 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
); 
 994         DisplayHorizontalValue(scalePtr
, scalePtr
->value
, valueBottom
); 
 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. 
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
); 
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
); 
1017     if (scalePtr
->flags 
& ACTIVE
) { 
1018         sliderBorder 
= scalePtr
->activeBorder
; 
1020         sliderBorder 
= scalePtr
->sliderBorder
; 
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) { 
1030     relief 
= (scalePtr
->flags 
& BUTTON_PRESSED
) ? TK_RELIEF_SUNKEN
 
1032     Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
), sliderBorder
, 
1033             x
, y
, 2*width
, height
, shadowWidth
, relief
); 
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
); 
1044      * Draw the label to the top of the scale. 
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
); 
1055      * Draw the window border. 
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
); 
1066     scalePtr
->flags 
&= ~REDRAW_ALL
; 
1070  *---------------------------------------------------------------------- 
1072  * DisplayHorizontalValue -- 
1074  *      This procedure is called to display values (scale readings) 
1075  *      for horizontally-oriented scales. 
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". 
1085  *---------------------------------------------------------------------- 
1089 DisplayHorizontalValue(scalePtr
, value
, bottom
) 
1090     register Scale 
*scalePtr
;   /* Information about widget in which to 
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. */ 
1098     register Tk_Window tkwin 
= scalePtr
->tkwin
; 
1099     int x
, y
, dummy
, length
; 
1100     char valueString
[30]; 
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
); 
1111      * Adjust the x-coordinate if necessary to keep the text entirely 
1112      * inside the window. 
1115     x 
-= (bbox
.lbearing 
+ bbox
.rbearing
)/2; 
1116     if ((x 
- bbox
.lbearing
) < scalePtr
->offset
) { 
1117         x 
= scalePtr
->offset 
+ bbox
.lbearing
; 
1119     if ((y 
+ bbox
.rbearing
) > (Tk_Width(tkwin
) - scalePtr
->offset
)) { 
1120         x 
= Tk_Width(tkwin
) - scalePtr
->offset 
- bbox
.rbearing
; 
1122     XDrawString(Tk_Display(tkwin
), Tk_WindowId(tkwin
), 
1123             scalePtr
->textGC
, x
, y
, valueString
, length
); 
1127  *---------------------------------------------------------------------- 
1131  *      Given a pixel within a scale window, return the scale 
1132  *      reading corresponding to that pixel. 
1135  *      An integer scale reading. 
1140  *---------------------------------------------------------------------- 
1144 PixelToValue(scalePtr
, x
, y
) 
1145     register Scale 
*scalePtr
;           /* Information about widget. */ 
1146     int x
, y
;                           /* Coordinates of point within 
1149     int value
, pixelRange
; 
1151     if (scalePtr
->vertical
) { 
1152         pixelRange 
= Tk_Height(scalePtr
->tkwin
) - scalePtr
->sliderLength
 
1153                 - 2*scalePtr
->offset 
- 2*scalePtr
->borderWidth
; 
1156         pixelRange 
= Tk_Width(scalePtr
->tkwin
) - scalePtr
->sliderLength
 
1157                 - 2*scalePtr
->offset 
- 2*scalePtr
->borderWidth
; 
1161     if (pixelRange 
<= 0) { 
1163          * Not enough room for the slider to actually slide:  just return 
1164          * the scale's current value. 
1167         return scalePtr
->value
; 
1169     value 
-= scalePtr
->sliderLength
/2 + scalePtr
->offset
 
1170                 + scalePtr
->borderWidth
; 
1174     if (value 
> pixelRange
) { 
1177     if (scalePtr
->toValue 
> scalePtr
->fromValue
) { 
1178         value 
= scalePtr
->fromValue 
+ 
1179                 ((value 
* (scalePtr
->toValue 
- scalePtr
->fromValue
)) 
1180                 + pixelRange
/2)/pixelRange
; 
1182         value 
= scalePtr
->toValue 
+ 
1183                 (((pixelRange 
- value
) 
1184                 * (scalePtr
->fromValue 
- scalePtr
->toValue
)) 
1185                 + pixelRange
/2)/pixelRange
; 
1191  *---------------------------------------------------------------------- 
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. 
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. 
1207  *---------------------------------------------------------------------- 
1211 ValueToPixel(scalePtr
, value
) 
1212     register Scale 
*scalePtr
;           /* Information about widget. */ 
1213     int value
;                          /* Reading of the widget. */ 
1215     int y
, pixelRange
, valueRange
; 
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
; 
1225     } else if (y 
> pixelRange
) { 
1228     y 
+= scalePtr
->sliderLength
/2 + scalePtr
->offset 
+ scalePtr
->borderWidth
; 
1233  *-------------------------------------------------------------- 
1237  *      This procedure is invoked by the Tk dispatcher for various 
1244  *      When the window gets deleted, internal structures get 
1245  *      cleaned up.  When it gets exposed, it is redisplayed. 
1247  *-------------------------------------------------------------- 
1251 ScaleEventProc(clientData
, eventPtr
) 
1252     ClientData clientData
;      /* Information about window. */ 
1253     XEvent 
*eventPtr
;           /* Information about event. */ 
1255     Scale 
*scalePtr 
= (Scale 
*) clientData
; 
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
); 
1266                 Tk_CancelIdleCall(DisplayHorizontalScale
, 
1267                         (ClientData
) scalePtr
); 
1270         Tk_EventuallyFree((ClientData
) scalePtr
, DestroyScale
); 
1271     } else if (eventPtr
->type 
== ConfigureNotify
) { 
1272         ComputeScaleGeometry(scalePtr
); 
1277  *-------------------------------------------------------------- 
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. 
1289  *      This procedure implements the "feel" of the scale by 
1290  *      issuing commands in response to button presses and mouse 
1293  *-------------------------------------------------------------- 
1297 ScaleMouseProc(clientData
, eventPtr
) 
1298     ClientData clientData
;              /* Information about window. */ 
1299     register XEvent 
*eventPtr
;          /* Information about event. */ 
1301     register Scale 
*scalePtr 
= (Scale 
*) clientData
; 
1303     if (scalePtr
->state 
!= tkNormalUid
) { 
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
); 
1331     Tk_Release((ClientData
) scalePtr
); 
1335  *-------------------------------------------------------------- 
1339  *      This procedure changes the value of a scale and invokes 
1340  *      a Tcl command to reflect the current position of a scale 
1346  *      A Tcl command is invoked, and an additional error-processing 
1347  *      command may also be invoked.  The scale's slider is redrawn. 
1349  *-------------------------------------------------------------- 
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. */ 
1361     if ((value 
< scalePtr
->fromValue
) 
1362             ^ (scalePtr
->toValue 
< scalePtr
->fromValue
)) { 
1363         value 
= scalePtr
->fromValue
; 
1365     if ((value 
> scalePtr
->toValue
) 
1366             ^ (scalePtr
->toValue 
< scalePtr
->fromValue
)) { 
1367         value 
= scalePtr
->toValue
; 
1369     if (value 
== scalePtr
->value
) { 
1372     scalePtr
->value 
= value
; 
1373     EventuallyRedrawScale(scalePtr
, REDRAW_SLIDER
); 
1375     sprintf(string
, " %d", scalePtr
->value
); 
1376     result 
= Tcl_VarEval(scalePtr
->interp
, scalePtr
->command
, string
, 
1378     if (result 
!= TCL_OK
) { 
1379         TkBindError(scalePtr
->interp
); 
1384  *-------------------------------------------------------------- 
1386  * EventuallyRedrawScale -- 
1388  *      Arrange for part or all of a scale widget to redrawn at 
1389  *      the next convenient time in the future. 
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. 
1399  *-------------------------------------------------------------- 
1403 EventuallyRedrawScale(scalePtr
, what
) 
1404     register Scale 
*scalePtr
;   /* Information about widget. */ 
1405     int what
;                   /* What to redraw:  REDRAW_SLIDER 
1408     if ((what 
== 0) || (scalePtr
->tkwin 
== NULL
) 
1409             || !Tk_IsMapped(scalePtr
->tkwin
)) { 
1412     if ((scalePtr
->flags 
& REDRAW_ALL
) == 0) { 
1413         if (scalePtr
->vertical
) { 
1414             Tk_DoWhenIdle(DisplayVerticalScale
, (ClientData
) scalePtr
); 
1416             Tk_DoWhenIdle(DisplayHorizontalScale
, (ClientData
) scalePtr
); 
1419     scalePtr
->flags 
|= what
;