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
& ALL_BUTTONS
) == 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
;