4 * This module implements a interval widgets for the Tk toolkit.
5 * A interval 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.
19 /* Improvements in the version used for Micropolis are copyrighted and
20 * licensed under these copyright terms.
22 * Micropolis, Unix Version. This game was released for the Unix platform
23 * in or about 1990 and has been modified for inclusion in the One Laptop
24 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
25 * you need assistance with this program, you may contact:
26 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
28 * This program is free software: you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, either version 3 of the License, or (at
31 * your option) any later version.
33 * This program is distributed in the hope that it will be useful, but
34 * WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * General Public License for more details. You should have received a
37 * copy of the GNU General Public License along with this program. If
38 * not, see <http://www.gnu.org/licenses/>.
40 * ADDITIONAL TERMS per GNU GPL Section 7
42 * No trademark or publicity rights are granted. This license does NOT
43 * give you any right, title or interest in the trademark SimCity or any
44 * other Electronic Arts trademark. You may not distribute any
45 * modification of this program using the trademark SimCity or claim any
46 * affliation or association with Electronic Arts Inc. or its employees.
48 * Any propagation or conveyance of this program must include this
49 * copyright notice and these terms.
51 * If you convey this program (or any modifications of it) and assume
52 * contractual liability for the program to recipients of it, you agree
53 * to indemnify Electronic Arts for any liability that those contractual
54 * assumptions impose on Electronic Arts.
56 * You may not misrepresent the origins of this program; modified
57 * versions of the program must be marked as such and not identified as
58 * the original program.
60 * This disclaimer supplements the one included in the General Public
61 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
62 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
63 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
64 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
65 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
66 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
67 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
68 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
69 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
70 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
71 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
72 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
73 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
74 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
75 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
76 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
77 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
78 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
87 * A data structure of the following type is kept for each interval
88 * widget managed by this file:
92 Tk_Window tkwin
; /* Window that embodies the interval. NULL
93 * means that the window has been destroyed
94 * but the data structures haven't yet been
96 Tcl_Interp
*interp
; /* Interpreter associated with interval. */
97 Tk_Uid orientUid
; /* Orientation for window ("vertical" or
99 int vertical
; /* Non-zero means vertical orientation,
100 * zero means horizontal. */
101 int minValue
; /* Value corresponding to minimum of interval. */
102 int maxValue
; /* Value corresponding to maximum of interval. */
103 int fromValue
; /* Value corresponding to left or top of
105 int toValue
; /* Value corresponding to right or bottom
107 int tickInterval
; /* Distance between tick marks; 0 means
108 * don't display any tick marks. */
109 int trackValue
; /* Value of mouse at start of tracking. */
110 int trackWidth
; /* Value of max-min at start of tracking. */
111 int trackState
; /* Tracking state. */
112 char *command
; /* Command prefix to use when invoking Tcl
113 * commands because the interval value changed.
114 * NULL means don't invoke commands.
116 int commandLength
; /* Number of non-NULL bytes in command. */
117 char *label
; /* Label to display above or to right of
118 * interval; NULL means don't display a
119 * label. Malloc'ed. */
120 int labelLength
; /* Number of non-NULL chars. in label. */
121 Tk_Uid state
; /* Normal or disabled. Value cannot be
122 * changed when interval is disabled. */
125 * Information used when displaying widget:
128 int borderWidth
; /* Width of 3-D border around window. */
129 Tk_3DBorder bgBorder
; /* Used for drawing background. */
130 Tk_3DBorder sliderBorder
; /* Used for drawing slider in normal mode. */
131 Tk_3DBorder activeBorder
; /* Used for drawing slider when active (i.e.
132 * when mouse is in window). */
133 XFontStruct
*fontPtr
; /* Information about text font, or NULL. */
134 XColor
*textColorPtr
; /* Color for drawing text. */
135 GC textGC
; /* GC for drawing text in normal mode. */
136 int width
; /* Desired narrow dimension of interval,
138 int length
; /* Desired long dimension of interval,
140 int relief
; /* Indicates whether window as a whole is
141 * raised, sunken, or flat. */
142 int offset
; /* Zero if relief is TK_RELIEF_FLAT,
143 * borderWidth otherwise. Indicates how
144 * much interior stuff must be offset from
145 * outside edges to leave room for border. */
146 int showValue
; /* Non-zero means to display the interval value
147 * below or to the left of the slider; zero
148 * means don't display the value. */
149 int tickPixels
; /* Number of pixels required for widest tick
150 * mark. 0 means don't display ticks.*/
151 int valuePixels
; /* Number of pixels required for value text. */
152 int labelPixels
; /* Number of pixels required for label. 0
153 * means don't display label. */
156 * Miscellaneous information:
159 Cursor cursor
; /* Current cursor for window, or None. */
160 int flags
; /* Various flags; see below for
165 * Flag bits for intervals:
167 * REDRAW_SLIDER - 1 means slider (and numerical readout) need
169 * REDRAW_OTHER - 1 means other stuff besides slider and value
170 * need to be redrawn.
171 * REDRAW_ALL - 1 means the entire widget needs to be redrawn.
172 * ACTIVE - 1 means the widget is active (the mouse is
174 * BUTTON_PRESSED - 1 means a button press is in progress, so
175 * slider should appear depressed and should be
179 #define REDRAW_SLIDER 1
180 #define REDRAW_OTHER 2
183 #define BUTTON_PRESSED 8
186 * Space to leave between interval area and text.
192 * Information used for argv parsing.
196 static Tk_ConfigSpec configSpecs
[] = {
197 {TK_CONFIG_BORDER
, "-activeforeground", "activeForeground", "Background",
198 DEF_SCALE_ACTIVE_FG_COLOR
, Tk_Offset(Interval
, activeBorder
),
199 TK_CONFIG_COLOR_ONLY
},
200 {TK_CONFIG_BORDER
, "-activeforeground", "activeForeground", "Background",
201 DEF_SCALE_ACTIVE_FG_MONO
, Tk_Offset(Interval
, activeBorder
),
202 TK_CONFIG_MONO_ONLY
},
203 {TK_CONFIG_BORDER
, "-background", "background", "Background",
204 DEF_SCALE_BG_COLOR
, Tk_Offset(Interval
, bgBorder
),
205 TK_CONFIG_COLOR_ONLY
},
206 {TK_CONFIG_BORDER
, "-background", "background", "Background",
207 DEF_SCALE_BG_MONO
, Tk_Offset(Interval
, bgBorder
),
208 TK_CONFIG_MONO_ONLY
},
209 {TK_CONFIG_SYNONYM
, "-bd", "borderWidth", (char *) NULL
,
210 (char *) NULL
, 0, 0},
211 {TK_CONFIG_SYNONYM
, "-bg", "background", (char *) NULL
,
212 (char *) NULL
, 0, 0},
213 {TK_CONFIG_PIXELS
, "-borderwidth", "borderWidth", "BorderWidth",
214 DEF_SCALE_BORDER_WIDTH
, Tk_Offset(Interval
, borderWidth
), 0},
215 {TK_CONFIG_STRING
, "-command", "command", "Command",
216 (char *) NULL
, Tk_Offset(Interval
, command
), 0},
217 {TK_CONFIG_ACTIVE_CURSOR
, "-cursor", "cursor", "Cursor",
218 DEF_SCALE_CURSOR
, Tk_Offset(Interval
, cursor
), TK_CONFIG_NULL_OK
},
219 {TK_CONFIG_SYNONYM
, "-fg", "foreground", (char *) NULL
,
220 (char *) NULL
, 0, 0},
221 {TK_CONFIG_FONT
, "-font", "font", "Font",
222 DEF_SCALE_FONT
, Tk_Offset(Interval
, fontPtr
),
224 {TK_CONFIG_COLOR
, "-foreground", "foreground", "Foreground",
225 DEF_SCALE_FG_COLOR
, Tk_Offset(Interval
, textColorPtr
),
226 TK_CONFIG_COLOR_ONLY
},
227 {TK_CONFIG_COLOR
, "-foreground", "foreground", "Foreground",
228 DEF_SCALE_FG_MONO
, Tk_Offset(Interval
, textColorPtr
),
229 TK_CONFIG_MONO_ONLY
},
230 {TK_CONFIG_INT
, "-from", "from", "From",
231 DEF_SCALE_FROM
, Tk_Offset(Interval
, fromValue
), 0},
232 {TK_CONFIG_STRING
, "-label", "label", "Label",
233 DEF_SCALE_LABEL
, Tk_Offset(Interval
, label
), 0},
234 {TK_CONFIG_PIXELS
, "-length", "length", "Length",
235 DEF_SCALE_LENGTH
, Tk_Offset(Interval
, length
), 0},
236 {TK_CONFIG_UID
, "-orient", "orient", "Orient",
237 DEF_SCALE_ORIENT
, Tk_Offset(Interval
, orientUid
), 0},
238 {TK_CONFIG_RELIEF
, "-relief", "relief", "Relief",
239 DEF_SCALE_RELIEF
, Tk_Offset(Interval
, relief
), 0},
240 {TK_CONFIG_BOOLEAN
, "-showvalue", "showValue", "ShowValue",
241 DEF_SCALE_SHOW_VALUE
, Tk_Offset(Interval
, showValue
), 0},
242 {TK_CONFIG_BORDER
, "-sliderforeground", "sliderForeground", "Background",
243 DEF_SCALE_SLIDER_FG_COLOR
, Tk_Offset(Interval
, sliderBorder
),
244 TK_CONFIG_COLOR_ONLY
},
245 {TK_CONFIG_BORDER
, "-sliderforeground", "sliderForeground", "Background",
246 DEF_SCALE_SLIDER_FG_MONO
, Tk_Offset(Interval
, sliderBorder
),
247 TK_CONFIG_MONO_ONLY
},
248 {TK_CONFIG_PIXELS
, "-min", "min", "Min",
249 "0", Tk_Offset(Interval
, minValue
), 0},
250 {TK_CONFIG_PIXELS
, "-max", "max", "Max",
251 "9999", Tk_Offset(Interval
, maxValue
), 0},
252 {TK_CONFIG_UID
, "-state", "state", "State",
253 DEF_SCALE_STATE
, Tk_Offset(Interval
, state
), 0},
254 {TK_CONFIG_INT
, "-tickinterval", "tickInterval", "TickInterval",
255 DEF_SCALE_TICK_INTERVAL
, Tk_Offset(Interval
, tickInterval
), 0},
256 {TK_CONFIG_INT
, "-to", "to", "To",
257 DEF_SCALE_TO
, Tk_Offset(Interval
, toValue
), 0},
258 {TK_CONFIG_PIXELS
, "-width", "width", "Width",
259 DEF_SCALE_WIDTH
, Tk_Offset(Interval
, width
), 0},
260 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
265 * Forward declarations for procedures defined later in this file:
268 static void ComputeIntervalGeometry
_ANSI_ARGS_((Interval
*intervalPtr
));
269 static int ConfigureInterval
_ANSI_ARGS_((Tcl_Interp
*interp
,
270 Interval
*intervalPtr
, int argc
, char **argv
,
272 static void DestroyInterval
_ANSI_ARGS_((ClientData clientData
));
273 static void DisplayHorizontalInterval
_ANSI_ARGS_((
274 ClientData clientData
));
275 static void DisplayHorizontalValue
_ANSI_ARGS_((Interval
*intervalPtr
,
276 int value
, int bottom
));
277 static void DisplayVerticalInterval
_ANSI_ARGS_((
278 ClientData clientData
));
279 static void DisplayVerticalValue
_ANSI_ARGS_((Interval
*intervalPtr
,
280 int value
, int rightEdge
));
281 static void EventuallyRedrawInterval
_ANSI_ARGS_((Interval
*intervalPtr
,
283 static int PixelToValue
_ANSI_ARGS_((Interval
*intervalPtr
, int x
,
285 static void IntervalEventProc
_ANSI_ARGS_((ClientData clientData
,
287 static void IntervalMouseProc
_ANSI_ARGS_((ClientData clientData
,
289 static int IntervalWidgetCmd
_ANSI_ARGS_((ClientData clientData
,
290 Tcl_Interp
*interp
, int argc
, char **argv
));
291 static void SetInterval
_ANSI_ARGS_((Interval
*intervalPtr
,
292 int minValue
, int maxValue
, int notify
));
293 static void TrackInterval
_ANSI_ARGS_((Interval
*intervalPtr
,
295 static void StartTrackInterval
_ANSI_ARGS_((Interval
*intervalPtr
,
297 static int ValueToPixel
_ANSI_ARGS_((Interval
*intervalPtr
, int value
));
300 *--------------------------------------------------------------
304 * This procedure is invoked to process the "interval" Tcl
305 * command. See the user documentation for details on what
309 * A standard Tcl result.
312 * See the user documentation.
314 *--------------------------------------------------------------
318 Tk_IntervalCmd(clientData
, interp
, argc
, argv
)
319 ClientData clientData
; /* Main window associated with
321 Tcl_Interp
*interp
; /* Current interpreter. */
322 int argc
; /* Number of arguments. */
323 char **argv
; /* Argument strings. */
325 Tk_Window tkwin
= (Tk_Window
) clientData
;
326 register Interval
*intervalPtr
;
330 Tcl_AppendResult(interp
, "wrong # args: should be \"",
331 argv
[0], " pathName ?options?\"", (char *) NULL
);
335 new = Tk_CreateWindowFromPath(interp
, tkwin
, argv
[1], (char *) NULL
);
341 * Initialize fields that won't be initialized by ConfigureInterval,
342 * or which ConfigureInterval expects to have reasonable values
343 * (e.g. resource pointers).
346 intervalPtr
= (Interval
*) ckalloc(sizeof(Interval
));
347 intervalPtr
->tkwin
= new;
348 intervalPtr
->interp
= interp
;
349 intervalPtr
->minValue
= 0;
350 intervalPtr
->maxValue
= 0;
351 intervalPtr
->command
= NULL
;
352 intervalPtr
->label
= NULL
;
353 intervalPtr
->state
= tkNormalUid
;
354 intervalPtr
->bgBorder
= NULL
;
355 intervalPtr
->sliderBorder
= NULL
;
356 intervalPtr
->activeBorder
= NULL
;
357 intervalPtr
->fontPtr
= NULL
;
358 intervalPtr
->textColorPtr
= NULL
;
359 intervalPtr
->textGC
= None
;
360 intervalPtr
->cursor
= None
;
361 intervalPtr
->flags
= 0;
363 Tk_SetClass(intervalPtr
->tkwin
, "Interval");
364 Tk_CreateEventHandler(intervalPtr
->tkwin
, ExposureMask
|StructureNotifyMask
,
365 IntervalEventProc
, (ClientData
) intervalPtr
);
366 Tk_CreateEventHandler(intervalPtr
->tkwin
, EnterWindowMask
|LeaveWindowMask
367 |PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
368 IntervalMouseProc
, (ClientData
) intervalPtr
);
369 Tcl_CreateCommand(interp
, Tk_PathName(intervalPtr
->tkwin
), IntervalWidgetCmd
,
370 (ClientData
) intervalPtr
, (void (*)()) NULL
);
371 if (ConfigureInterval(interp
, intervalPtr
, argc
-2, argv
+2, 0) != TCL_OK
) {
375 interp
->result
= Tk_PathName(intervalPtr
->tkwin
);
379 Tk_DestroyWindow(intervalPtr
->tkwin
);
384 *--------------------------------------------------------------
386 * IntervalWidgetCmd --
388 * This procedure is invoked to process the Tcl command
389 * that corresponds to a widget managed by this module.
390 * See the user documentation for details on what it does.
393 * A standard Tcl result.
396 * See the user documentation.
398 *--------------------------------------------------------------
402 IntervalWidgetCmd(clientData
, interp
, argc
, argv
)
403 ClientData clientData
; /* Information about interval
405 Tcl_Interp
*interp
; /* Current interpreter. */
406 int argc
; /* Number of arguments. */
407 char **argv
; /* Argument strings. */
409 register Interval
*intervalPtr
= (Interval
*) clientData
;
415 Tcl_AppendResult(interp
, "wrong # args: should be \"",
416 argv
[0], " option ?arg arg ...?\"", (char *) NULL
);
419 Tk_Preserve((ClientData
) intervalPtr
);
421 length
= strlen(argv
[1]);
422 if ((c
== 'c') && (strncmp(argv
[1], "configure", length
) == 0)) {
424 result
= Tk_ConfigureInfo(interp
, intervalPtr
->tkwin
, configSpecs
,
425 (char *) intervalPtr
, (char *) NULL
, 0);
426 } else if (argc
== 3) {
427 result
= Tk_ConfigureInfo(interp
, intervalPtr
->tkwin
, configSpecs
,
428 (char *) intervalPtr
, argv
[2], 0);
430 result
= ConfigureInterval(interp
, intervalPtr
, argc
-2, argv
+2,
431 TK_CONFIG_ARGV_ONLY
);
433 } else if ((c
== 'g') && (strncmp(argv
[1], "get", length
) == 0)) {
435 Tcl_AppendResult(interp
, "wrong # args: should be \"",
436 argv
[0], " get\"", (char *) NULL
);
439 sprintf(interp
->result
, "%d %d", intervalPtr
->minValue
, intervalPtr
->maxValue
);
440 } else if ((c
== 's') && (strncmp(argv
[1], "set", length
) == 0)) {
441 int minValue
, maxValue
;
444 Tcl_AppendResult(interp
, "wrong # args: should be \"",
445 argv
[0], " set minValue maxValue\"", (char *) NULL
);
448 if (Tcl_GetInt(interp
, argv
[2], &minValue
) != TCL_OK
) {
451 if (Tcl_GetInt(interp
, argv
[3], &maxValue
) != TCL_OK
) {
454 if (minValue
> maxValue
) {
456 minValue
= maxValue
; maxValue
= temp
;
458 if (intervalPtr
->state
== tkNormalUid
) {
459 if ((minValue
< intervalPtr
->fromValue
)
460 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
461 minValue
= intervalPtr
->fromValue
;
463 if ((minValue
> intervalPtr
->toValue
)
464 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
465 minValue
= intervalPtr
->toValue
;
467 if ((maxValue
< intervalPtr
->fromValue
)
468 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
469 maxValue
= intervalPtr
->fromValue
;
471 if ((maxValue
> intervalPtr
->toValue
)
472 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
473 maxValue
= intervalPtr
->toValue
;
475 SetInterval(intervalPtr
, minValue
, maxValue
, 1);
477 } else if ((c
== 'r') && (strncmp(argv
[1], "reset", length
) == 0)) {
479 Tcl_AppendResult(interp
, "wrong # args: should be \"",
480 argv
[0], " reset\"", (char *) NULL
);
483 SetInterval(intervalPtr
,
484 intervalPtr
->fromValue
, intervalPtr
->toValue
, 0);
486 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
487 "\": must be configure, get, or set", (char *) NULL
);
490 Tk_Release((ClientData
) intervalPtr
);
494 Tk_Release((ClientData
) intervalPtr
);
499 *----------------------------------------------------------------------
503 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
504 * to clean up the internal structure of a button at a safe time
505 * (when no-one is using it anymore).
511 * Everything associated with the interval is freed up.
513 *----------------------------------------------------------------------
517 DestroyInterval(clientData
)
518 ClientData clientData
; /* Info about interval widget. */
520 register Interval
*intervalPtr
= (Interval
*) clientData
;
522 if (intervalPtr
->command
!= NULL
) {
523 ckfree(intervalPtr
->command
);
525 if (intervalPtr
->label
!= NULL
) {
526 ckfree(intervalPtr
->label
);
528 if (intervalPtr
->bgBorder
!= NULL
) {
529 Tk_Free3DBorder(intervalPtr
->bgBorder
);
531 if (intervalPtr
->sliderBorder
!= NULL
) {
532 Tk_Free3DBorder(intervalPtr
->sliderBorder
);
534 if (intervalPtr
->activeBorder
!= NULL
) {
535 Tk_Free3DBorder(intervalPtr
->activeBorder
);
537 if (intervalPtr
->fontPtr
!= NULL
) {
538 Tk_FreeFontStruct(intervalPtr
->fontPtr
);
540 if (intervalPtr
->textColorPtr
!= NULL
) {
541 Tk_FreeColor(intervalPtr
->textColorPtr
);
543 if (intervalPtr
->textGC
!= None
) {
544 Tk_FreeGC(intervalPtr
->textGC
);
546 if (intervalPtr
->cursor
!= None
) {
547 Tk_FreeCursor(intervalPtr
->cursor
);
549 ckfree((char *) intervalPtr
);
553 *----------------------------------------------------------------------
555 * ConfigureInterval --
557 * This procedure is called to process an argv/argc list, plus
558 * the Tk option database, in order to configure (or
559 * reconfigure) a interval widget.
562 * The return value is a standard Tcl result. If TCL_ERROR is
563 * returned, then interp->result contains an error message.
566 * Configuration information, such as colors, border width,
567 * etc. get set for intervalPtr; old resources get freed,
570 *----------------------------------------------------------------------
574 ConfigureInterval(interp
, intervalPtr
, argc
, argv
, flags
)
575 Tcl_Interp
*interp
; /* Used for error reporting. */
576 register Interval
*intervalPtr
; /* Information about widget; may or may
577 * not already have values for some fields. */
578 int argc
; /* Number of valid entries in argv. */
579 char **argv
; /* Arguments. */
580 int flags
; /* Flags to pass to Tk_ConfigureWidget. */
586 if (Tk_ConfigureWidget(interp
, intervalPtr
->tkwin
, configSpecs
,
587 argc
, argv
, (char *) intervalPtr
, flags
) != TCL_OK
) {
592 * A few options need special processing, such as parsing the
593 * orientation or setting the background from a 3-D border.
596 length
= strlen(intervalPtr
->orientUid
);
597 if (strncmp(intervalPtr
->orientUid
, "vertical", length
) == 0) {
598 intervalPtr
->vertical
= 1;
599 } else if (strncmp(intervalPtr
->orientUid
, "horizontal", length
) == 0) {
600 intervalPtr
->vertical
= 0;
602 Tcl_AppendResult(interp
, "bad orientation \"", intervalPtr
->orientUid
,
603 "\": must be vertical or horizontal", (char *) NULL
);
607 if ((intervalPtr
->state
!= tkNormalUid
)
608 && (intervalPtr
->state
!= tkDisabledUid
)) {
609 Tcl_AppendResult(interp
, "bad state value \"", intervalPtr
->state
,
610 "\": must be normal or disabled", (char *) NULL
);
611 intervalPtr
->state
= tkNormalUid
;
616 * Make sure that the tick interval has the right sign so that
617 * addition moves from fromValue to toValue.
620 if ((intervalPtr
->tickInterval
< 0)
621 ^ ((intervalPtr
->toValue
- intervalPtr
->fromValue
) < 0)) {
622 intervalPtr
->tickInterval
= -intervalPtr
->tickInterval
;
626 * Set the interval mix and max values to themselves; all this does is
627 * to make sure that the interval's value is within the new acceptable
628 * range for the interval.
631 SetInterval(intervalPtr
, intervalPtr
->minValue
, intervalPtr
->maxValue
, 0);
633 if (intervalPtr
->command
!= NULL
) {
634 intervalPtr
->commandLength
= strlen(intervalPtr
->command
);
636 intervalPtr
->commandLength
= 0;
639 if (intervalPtr
->label
!= NULL
) {
640 intervalPtr
->labelLength
= strlen(intervalPtr
->label
);
642 intervalPtr
->labelLength
= 0;
645 Tk_SetBackgroundFromBorder(intervalPtr
->tkwin
, intervalPtr
->bgBorder
);
647 gcValues
.font
= intervalPtr
->fontPtr
->fid
;
648 gcValues
.foreground
= intervalPtr
->textColorPtr
->pixel
;
649 newGC
= Tk_GetGC(intervalPtr
->tkwin
, GCForeground
|GCFont
, &gcValues
);
650 if (intervalPtr
->textGC
!= None
) {
651 Tk_FreeGC(intervalPtr
->textGC
);
653 intervalPtr
->textGC
= newGC
;
655 if (intervalPtr
->relief
!= TK_RELIEF_FLAT
) {
656 intervalPtr
->offset
= intervalPtr
->borderWidth
;
658 intervalPtr
->offset
= 0;
662 * Recompute display-related information, and let the geometry
663 * manager know how much space is needed now.
666 ComputeIntervalGeometry(intervalPtr
);
668 EventuallyRedrawInterval(intervalPtr
, REDRAW_ALL
);
673 *----------------------------------------------------------------------
675 * ComputeIntervalGeometry --
677 * This procedure is called to compute various geometrical
678 * information for a interval, such as where various things get
679 * displayed. It's called when the window is reconfigured.
685 * Display-related numbers get changed in *scrollPtr. The
686 * geometry manager gets told about the window's preferred size.
688 *----------------------------------------------------------------------
692 ComputeIntervalGeometry(intervalPtr
)
693 register Interval
*intervalPtr
; /* Information about widget. */
696 char valueString
[30];
697 int dummy
, lineHeight
;
700 * Horizontal intervals are simpler than vertical ones because
701 * all sizes are the same (the height of a line of text);
702 * handle them first and then quit.
705 if (!intervalPtr
->vertical
) {
706 lineHeight
= intervalPtr
->fontPtr
->ascent
+ intervalPtr
->fontPtr
->descent
;
707 if (intervalPtr
->tickInterval
!= 0) {
708 intervalPtr
->tickPixels
= lineHeight
;
710 intervalPtr
->tickPixels
= 0;
712 if (intervalPtr
->showValue
) {
713 intervalPtr
->valuePixels
= lineHeight
+ SPACING
;
715 intervalPtr
->valuePixels
= 0;
717 if (intervalPtr
->labelLength
!= 0) {
718 intervalPtr
->labelPixels
= lineHeight
;
720 intervalPtr
->labelPixels
= 0;
723 Tk_GeometryRequest(intervalPtr
->tkwin
,
724 intervalPtr
->length
+ 2*intervalPtr
->offset
,
725 intervalPtr
->tickPixels
+ intervalPtr
->valuePixels
726 + intervalPtr
->width
+ 2*intervalPtr
->borderWidth
727 + intervalPtr
->labelPixels
+ 2*intervalPtr
->offset
);
728 Tk_SetInternalBorder(intervalPtr
->tkwin
, intervalPtr
->borderWidth
);
733 * Vertical interval: compute the amount of space needed for tick marks
734 * and current value by formatting strings for the two end points;
735 * use whichever length is longer.
738 sprintf(valueString
, "%d", intervalPtr
->fromValue
);
739 XTextExtents(intervalPtr
->fontPtr
, valueString
, strlen(valueString
),
740 &dummy
, &dummy
, &dummy
, &bbox
);
741 intervalPtr
->tickPixels
= bbox
.rbearing
+ bbox
.lbearing
;
742 sprintf(valueString
, "%d", intervalPtr
->toValue
);
743 XTextExtents(intervalPtr
->fontPtr
, valueString
, strlen(valueString
),
744 &dummy
, &dummy
, &dummy
, &bbox
);
745 if (intervalPtr
->tickPixels
< bbox
.rbearing
+ bbox
.lbearing
) {
746 intervalPtr
->tickPixels
= bbox
.rbearing
+ bbox
.lbearing
;
750 * Pad the value with a bit of extra space for prettier printing.
753 intervalPtr
->tickPixels
+= intervalPtr
->fontPtr
->ascent
/2;
754 intervalPtr
->valuePixels
= intervalPtr
->tickPixels
;
755 if (intervalPtr
->tickInterval
== 0) {
756 intervalPtr
->tickPixels
= 0;
758 if (!intervalPtr
->showValue
) {
759 intervalPtr
->valuePixels
= 0;
762 if (intervalPtr
->labelLength
== 0) {
763 intervalPtr
->labelPixels
= 0;
765 XTextExtents(intervalPtr
->fontPtr
, intervalPtr
->label
,
766 intervalPtr
->labelLength
, &dummy
, &dummy
, &dummy
, &bbox
);
767 intervalPtr
->labelPixels
= bbox
.rbearing
+ bbox
.lbearing
768 + intervalPtr
->fontPtr
->ascent
;
770 Tk_GeometryRequest(intervalPtr
->tkwin
, 2*intervalPtr
->borderWidth
771 + intervalPtr
->tickPixels
+ intervalPtr
->valuePixels
+ SPACING
772 + intervalPtr
->width
+ intervalPtr
->labelPixels
,
773 intervalPtr
->length
);
774 Tk_SetInternalBorder(intervalPtr
->tkwin
, intervalPtr
->borderWidth
);
778 *--------------------------------------------------------------
780 * DisplayVerticalInterval --
782 * This procedure redraws the contents of a vertical interval
783 * window. It is invoked as a do-when-idle handler, so it only
784 * runs when there's nothing else for the application to do.
790 * Information appears on the screen.
792 *--------------------------------------------------------------
796 DisplayVerticalInterval(clientData
)
797 ClientData clientData
; /* Information about widget. */
799 register Interval
*intervalPtr
= (Interval
*) clientData
;
800 register Tk_Window tkwin
= intervalPtr
->tkwin
;
801 int tickRightEdge
, valueRightEdge
, labelLeftEdge
, intervalLeftEdge
;
802 int totalPixels
, x
, y
, width
, height
, tickValue
, min
, max
;
804 Tk_3DBorder sliderBorder
;
806 if ((intervalPtr
->tkwin
== NULL
) || !Tk_IsMapped(tkwin
)) {
811 * Scanning from left to right across the window, the window
812 * will contain four columns: ticks, value, interval, and label.
813 * Compute the x-coordinate for each of the columns.
816 totalPixels
= intervalPtr
->tickPixels
+ intervalPtr
->valuePixels
817 + 2*intervalPtr
->borderWidth
+ intervalPtr
->width
818 + 2*SPACING
+ intervalPtr
->labelPixels
;
819 tickRightEdge
= (Tk_Width(tkwin
) - totalPixels
)/2 + intervalPtr
->tickPixels
;
820 valueRightEdge
= tickRightEdge
+ intervalPtr
->valuePixels
;
821 intervalLeftEdge
= valueRightEdge
+ SPACING
;
822 labelLeftEdge
= intervalLeftEdge
+ 2*intervalPtr
->borderWidth
823 + intervalPtr
->width
+ intervalPtr
->fontPtr
->ascent
/2;
826 * Display the information from left to right across the window.
829 if (intervalPtr
->flags
& REDRAW_OTHER
) {
830 XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
));
833 * Display the tick marks.
836 if (intervalPtr
->tickPixels
!= 0) {
837 for (tickValue
= intervalPtr
->fromValue
; ;
838 tickValue
+= intervalPtr
->tickInterval
) {
839 if (intervalPtr
->toValue
> intervalPtr
->fromValue
) {
840 if (tickValue
> intervalPtr
->toValue
) {
844 if (tickValue
< intervalPtr
->toValue
) {
848 DisplayVerticalValue(intervalPtr
, tickValue
, tickRightEdge
);
854 * Display the values, if they are desired. If not redisplaying the
855 * entire window, clear the area of the value to get rid of the
856 * old value displayed there.
859 if (intervalPtr
->showValue
) {
860 if (!(intervalPtr
->flags
& REDRAW_OTHER
)) {
861 XClearArea(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
862 valueRightEdge
-intervalPtr
->valuePixels
, intervalPtr
->offset
,
863 intervalPtr
->valuePixels
,
864 Tk_Height(tkwin
) - 2*intervalPtr
->offset
, False
);
866 DisplayVerticalValue(intervalPtr
, intervalPtr
->minValue
, valueRightEdge
);
867 DisplayVerticalValue(intervalPtr
, intervalPtr
->maxValue
, valueRightEdge
);
871 * Display the interval and the slider. If not redisplaying the
872 * entire window, must clear the trench area to erase the old
873 * slider, but don't need to redraw the border.
876 if (intervalPtr
->flags
& REDRAW_OTHER
) {
877 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
878 intervalPtr
->bgBorder
, intervalLeftEdge
, intervalPtr
->offset
,
879 intervalPtr
->width
+ 2*intervalPtr
->borderWidth
,
880 Tk_Height(tkwin
) - 2*intervalPtr
->offset
, intervalPtr
->borderWidth
,
883 XClearArea(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
884 intervalLeftEdge
+ intervalPtr
->borderWidth
,
885 intervalPtr
->offset
+ intervalPtr
->borderWidth
,
887 Tk_Height(tkwin
) - 2*intervalPtr
->offset
888 - 2*intervalPtr
->borderWidth
, False
);
890 if (intervalPtr
->flags
& ACTIVE
) {
891 sliderBorder
= intervalPtr
->activeBorder
;
893 sliderBorder
= intervalPtr
->sliderBorder
;
895 width
= intervalPtr
->width
;
897 min
= ValueToPixel(intervalPtr
, intervalPtr
->minValue
);
898 max
= ValueToPixel(intervalPtr
, intervalPtr
->maxValue
);
900 height
= (max
- min
) + (2 * intervalPtr
->borderWidth
);
902 x
= intervalLeftEdge
+ intervalPtr
->borderWidth
;
904 relief
= (intervalPtr
->flags
& BUTTON_PRESSED
) ? TK_RELIEF_SUNKEN
906 Tk_Fill3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
), sliderBorder
,
907 x
, min
, width
, height
, intervalPtr
->borderWidth
, relief
);
910 * Draw the label to the right of the interval.
913 if ((intervalPtr
->flags
& REDRAW_OTHER
) && (intervalPtr
->labelPixels
!= 0)) {
914 XDrawString(Tk_Display(intervalPtr
->tkwin
), Tk_WindowId(intervalPtr
->tkwin
),
915 intervalPtr
->textGC
, labelLeftEdge
,
916 intervalPtr
->offset
+ (3*intervalPtr
->fontPtr
->ascent
)/2,
917 intervalPtr
->label
, intervalPtr
->labelLength
);
921 * Draw the window border.
924 if ((intervalPtr
->flags
& REDRAW_OTHER
)
925 && (intervalPtr
->relief
!= TK_RELIEF_FLAT
)) {
926 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
927 intervalPtr
->bgBorder
, 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
),
928 intervalPtr
->borderWidth
, intervalPtr
->relief
);
932 intervalPtr
->flags
&= ~REDRAW_ALL
;
936 *----------------------------------------------------------------------
938 * DisplayVerticalValue --
940 * This procedure is called to display values (interval readings)
941 * for vertically-oriented intervals.
947 * The numerical value corresponding to value is displayed with
948 * its right edge at "rightEdge", and at a vertical position in
949 * the interval that corresponds to "value".
951 *----------------------------------------------------------------------
955 DisplayVerticalValue(intervalPtr
, value
, rightEdge
)
956 register Interval
*intervalPtr
; /* Information about widget in which to
958 int value
; /* Y-coordinate of number to display,
959 * specified in application coords, not
960 * in pixels (we'll compute pixels). */
961 int rightEdge
; /* X-coordinate of right edge of text,
962 * specified in pixels. */
964 register Tk_Window tkwin
= intervalPtr
->tkwin
;
965 int y
, dummy
, length
;
966 char valueString
[30];
969 y
= ValueToPixel(intervalPtr
, value
) + intervalPtr
->fontPtr
->ascent
/2;
970 sprintf(valueString
, "%d", value
);
971 length
= strlen(valueString
);
972 XTextExtents(intervalPtr
->fontPtr
, valueString
, length
,
973 &dummy
, &dummy
, &dummy
, &bbox
);
976 * Adjust the y-coordinate if necessary to keep the text entirely
980 if ((y
- bbox
.ascent
) < intervalPtr
->offset
) {
981 y
= intervalPtr
->offset
+ bbox
.ascent
;
983 if ((y
+ bbox
.descent
) > (Tk_Height(tkwin
) - intervalPtr
->offset
)) {
984 y
= Tk_Height(tkwin
) - intervalPtr
->offset
- bbox
.descent
;
986 XDrawString(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
987 intervalPtr
->textGC
, rightEdge
- bbox
.rbearing
,
988 y
, valueString
, length
);
992 *--------------------------------------------------------------
994 * DisplayHorizontalInterval --
996 * This procedure redraws the contents of a horizontal interval
997 * window. It is invoked as a do-when-idle handler, so it only
998 * runs when there's nothing else for the application to do.
1004 * Information appears on the screen.
1006 *--------------------------------------------------------------
1010 DisplayHorizontalInterval(clientData
)
1011 ClientData clientData
; /* Information about widget. */
1013 register Interval
*intervalPtr
= (Interval
*) clientData
;
1014 register Tk_Window tkwin
= intervalPtr
->tkwin
;
1015 int tickBottom
, valueBottom
, labelBottom
, intervalBottom
;
1016 int totalPixels
, x
, y
, width
, height
, tickValue
, min
, max
;
1018 Tk_3DBorder sliderBorder
;
1020 if ((intervalPtr
->tkwin
== NULL
) || !Tk_IsMapped(tkwin
)) {
1025 * Scanning from bottom to top across the window, the window
1026 * will contain four rows: ticks, value, interval, and label.
1027 * Compute the y-coordinate for each of the rows.
1030 totalPixels
= intervalPtr
->tickPixels
+ intervalPtr
->valuePixels
1031 + 2*intervalPtr
->borderWidth
+ intervalPtr
->width
1032 + intervalPtr
->labelPixels
;
1033 tickBottom
= (Tk_Height(tkwin
) + totalPixels
)/2 - 1;
1034 valueBottom
= tickBottom
- intervalPtr
->tickPixels
;
1035 intervalBottom
= valueBottom
- intervalPtr
->valuePixels
;
1036 labelBottom
= intervalBottom
- 2*intervalPtr
->borderWidth
- intervalPtr
->width
;
1039 * Display the information from bottom to top across the window.
1042 if (intervalPtr
->flags
& REDRAW_OTHER
) {
1043 XClearWindow(Tk_Display(tkwin
), Tk_WindowId(tkwin
));
1046 * Display the tick marks.
1049 if (intervalPtr
->tickPixels
!= 0) {
1050 for (tickValue
= intervalPtr
->fromValue
; ;
1051 tickValue
+= intervalPtr
->tickInterval
) {
1052 if (intervalPtr
->toValue
> intervalPtr
->fromValue
) {
1053 if (tickValue
> intervalPtr
->toValue
) {
1057 if (tickValue
< intervalPtr
->toValue
) {
1061 DisplayHorizontalValue(intervalPtr
, tickValue
, tickBottom
);
1067 * Display the values, if they are desired. If not redisplaying the
1068 * entire window, clear the area of the value to get rid of the
1069 * old value displayed there.
1072 if (intervalPtr
->showValue
) {
1073 if (!(intervalPtr
->flags
& REDRAW_OTHER
)) {
1074 XClearArea(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
1075 intervalPtr
->offset
, intervalBottom
+ 1,
1076 Tk_Width(tkwin
) - 2*intervalPtr
->offset
,
1077 valueBottom
- intervalBottom
, False
);
1079 DisplayHorizontalValue(intervalPtr
, intervalPtr
->minValue
, valueBottom
);
1080 DisplayHorizontalValue(intervalPtr
, intervalPtr
->maxValue
, valueBottom
);
1084 * Display the interval and the slider. If not redisplaying the
1085 * entire window, must clear the trench area to erase the old
1086 * slider, but don't need to redraw the border.
1089 y
= intervalBottom
- 2*intervalPtr
->borderWidth
- intervalPtr
->width
+ 1;
1090 if (intervalPtr
->flags
& REDRAW_OTHER
) {
1091 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
1092 intervalPtr
->bgBorder
, intervalPtr
->offset
, y
,
1093 Tk_Width(tkwin
) - 2*intervalPtr
->offset
,
1094 intervalPtr
->width
+ 2*intervalPtr
->borderWidth
,
1095 intervalPtr
->borderWidth
, TK_RELIEF_SUNKEN
);
1097 XClearArea(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
1098 intervalPtr
->offset
+ intervalPtr
->borderWidth
,
1099 y
+ intervalPtr
->borderWidth
,
1100 Tk_Width(tkwin
) - 2*intervalPtr
->offset
- 2*intervalPtr
->borderWidth
,
1101 intervalPtr
->width
, False
);
1103 if (intervalPtr
->flags
& ACTIVE
) {
1104 sliderBorder
= intervalPtr
->activeBorder
;
1106 sliderBorder
= intervalPtr
->sliderBorder
;
1108 height
= intervalPtr
->width
;
1110 min
= ValueToPixel(intervalPtr
, intervalPtr
->minValue
);
1111 max
= ValueToPixel(intervalPtr
, intervalPtr
->maxValue
);
1113 width
= (max
- min
) + (2 * intervalPtr
->borderWidth
);
1115 y
+= intervalPtr
->borderWidth
;
1116 relief
= (intervalPtr
->flags
& BUTTON_PRESSED
) ? TK_RELIEF_SUNKEN
1118 Tk_Fill3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
), sliderBorder
,
1119 min
, y
, width
, height
, intervalPtr
->borderWidth
, relief
);
1122 * Draw the label to the top of the interval.
1125 if ((intervalPtr
->flags
& REDRAW_OTHER
) && (intervalPtr
->labelPixels
!= 0)) {
1126 XDrawString(Tk_Display(intervalPtr
->tkwin
), Tk_WindowId(intervalPtr
->tkwin
),
1127 intervalPtr
->textGC
, intervalPtr
->offset
+ intervalPtr
->fontPtr
->ascent
/2,
1128 labelBottom
- intervalPtr
->fontPtr
->descent
,
1129 intervalPtr
->label
, intervalPtr
->labelLength
);
1133 * Draw the window border.
1136 if ((intervalPtr
->flags
& REDRAW_OTHER
)
1137 && (intervalPtr
->relief
!= TK_RELIEF_FLAT
)) {
1138 Tk_Draw3DRectangle(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
1139 intervalPtr
->bgBorder
, 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
),
1140 intervalPtr
->borderWidth
, intervalPtr
->relief
);
1144 intervalPtr
->flags
&= ~REDRAW_ALL
;
1148 *----------------------------------------------------------------------
1150 * DisplayHorizontalValue --
1152 * This procedure is called to display values (interval readings)
1153 * for horizontally-oriented intervals.
1159 * The numerical value corresponding to value is displayed with
1160 * its bottom edge at "bottom", and at a horizontal position in
1161 * the interval that corresponds to "value".
1163 *----------------------------------------------------------------------
1167 DisplayHorizontalValue(intervalPtr
, value
, bottom
)
1168 register Interval
*intervalPtr
; /* Information about widget in which to
1170 int value
; /* Y-coordinate of number to display,
1171 * specified in application coords, not
1172 * in pixels (we'll compute pixels). */
1173 int bottom
; /* Y-coordinate of bottom edge of text,
1174 * specified in pixels. */
1176 register Tk_Window tkwin
= intervalPtr
->tkwin
;
1177 int x
, y
, dummy
, length
;
1178 char valueString
[30];
1181 x
= ValueToPixel(intervalPtr
, value
);
1182 y
= bottom
- intervalPtr
->fontPtr
->descent
;
1183 sprintf(valueString
, "%d", value
);
1184 length
= strlen(valueString
);
1185 XTextExtents(intervalPtr
->fontPtr
, valueString
, length
,
1186 &dummy
, &dummy
, &dummy
, &bbox
);
1189 * Adjust the x-coordinate if necessary to keep the text entirely
1190 * inside the window.
1193 x
-= (bbox
.lbearing
+ bbox
.rbearing
)/2;
1194 if ((x
- bbox
.lbearing
) < intervalPtr
->offset
) {
1195 x
= intervalPtr
->offset
+ bbox
.lbearing
;
1197 if ((x
+ bbox
.rbearing
) > (Tk_Width(tkwin
) - intervalPtr
->offset
)) {
1198 x
= Tk_Width(tkwin
) - intervalPtr
->offset
- bbox
.rbearing
;
1200 XDrawString(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
1201 intervalPtr
->textGC
, x
, y
, valueString
, length
);
1205 *----------------------------------------------------------------------
1209 * Given a pixel within a interval window, return the interval
1210 * reading corresponding to that pixel.
1213 * An integer interval reading.
1218 *----------------------------------------------------------------------
1222 PixelToValue(intervalPtr
, x
, y
)
1223 register Interval
*intervalPtr
; /* Information about widget. */
1224 int x
, y
; /* Coordinates of point within
1227 int value
, pixelRange
;
1229 if (intervalPtr
->vertical
) {
1230 pixelRange
= Tk_Height(intervalPtr
->tkwin
)
1231 - 2*intervalPtr
->offset
- 4*intervalPtr
->borderWidth
;
1234 pixelRange
= Tk_Width(intervalPtr
->tkwin
)
1235 - 2*intervalPtr
->offset
- 4*intervalPtr
->borderWidth
;
1239 if (pixelRange
<= 0) {
1241 * Not enough room for the slider to actually slide: just return
1247 value
-= intervalPtr
->offset
+ intervalPtr
->borderWidth
;
1252 if (value
> pixelRange
) {
1256 if (intervalPtr
->toValue
> intervalPtr
->fromValue
) {
1257 value
= intervalPtr
->fromValue
+
1258 ((value
* (intervalPtr
->toValue
- intervalPtr
->fromValue
))
1259 + pixelRange
/2)/pixelRange
;
1261 value
= intervalPtr
->toValue
+
1262 (((pixelRange
- value
)
1263 * (intervalPtr
->fromValue
- intervalPtr
->toValue
))
1264 + pixelRange
/2)/pixelRange
;
1270 *----------------------------------------------------------------------
1274 * Given a reading of the interval, return the x-coordinate or
1275 * y-coordinate corresponding to that reading, depending on
1276 * whether the interval is vertical or horizontal, respectively.
1279 * An integer value giving the pixel location corresponding
1280 * to reading. The value is restricted to lie within the
1281 * defined range for the interval.
1286 *----------------------------------------------------------------------
1290 ValueToPixel(intervalPtr
, value
)
1291 register Interval
*intervalPtr
; /* Information about widget. */
1292 int value
; /* Reading of the widget. */
1294 int y
, pixelRange
, valueRange
;
1296 valueRange
= intervalPtr
->toValue
- intervalPtr
->fromValue
;
1297 pixelRange
= (intervalPtr
->vertical
? Tk_Height(intervalPtr
->tkwin
)
1298 : Tk_Width(intervalPtr
->tkwin
))
1299 - 2*intervalPtr
->offset
- 4*intervalPtr
->borderWidth
;
1300 y
= ((value
- intervalPtr
->fromValue
) * pixelRange
1301 + valueRange
/2) / valueRange
;
1304 } else if (y
> pixelRange
) {
1307 y
+= intervalPtr
->offset
+ intervalPtr
->borderWidth
;
1312 *--------------------------------------------------------------
1314 * IntervalEventProc --
1316 * This procedure is invoked by the Tk dispatcher for various
1317 * events on intervals.
1323 * When the window gets deleted, internal structures get
1324 * cleaned up. When it gets exposed, it is redisplayed.
1326 *--------------------------------------------------------------
1330 IntervalEventProc(clientData
, eventPtr
)
1331 ClientData clientData
; /* Information about window. */
1332 XEvent
*eventPtr
; /* Information about event. */
1334 Interval
*intervalPtr
= (Interval
*) clientData
;
1336 if ((eventPtr
->type
== Expose
) && (eventPtr
->xexpose
.count
== 0)) {
1337 EventuallyRedrawInterval(intervalPtr
, REDRAW_ALL
);
1338 } else if (eventPtr
->type
== DestroyNotify
) {
1339 Tcl_DeleteCommand(intervalPtr
->interp
, Tk_PathName(intervalPtr
->tkwin
));
1340 intervalPtr
->tkwin
= NULL
;
1341 if (intervalPtr
->flags
& REDRAW_ALL
) {
1342 if (intervalPtr
->vertical
) {
1343 Tk_CancelIdleCall(DisplayVerticalInterval
, (ClientData
) intervalPtr
);
1345 Tk_CancelIdleCall(DisplayHorizontalInterval
,
1346 (ClientData
) intervalPtr
);
1349 Tk_EventuallyFree((ClientData
) intervalPtr
, DestroyInterval
);
1350 } else if (eventPtr
->type
== ConfigureNotify
) {
1351 ComputeIntervalGeometry(intervalPtr
);
1356 *--------------------------------------------------------------
1358 * IntervalMouseProc --
1360 * This procedure is called back by Tk in response to
1361 * mouse events such as window entry, window exit, mouse
1362 * motion, and button presses.
1368 * This procedure implements the "feel" of the interval by
1369 * issuing commands in response to button presses and mouse
1372 *--------------------------------------------------------------
1376 IntervalMouseProc(clientData
, eventPtr
)
1377 ClientData clientData
; /* Information about window. */
1378 register XEvent
*eventPtr
; /* Information about event. */
1380 register Interval
*intervalPtr
= (Interval
*) clientData
;
1382 if (intervalPtr
->state
!= tkNormalUid
) {
1386 Tk_Preserve((ClientData
) intervalPtr
);
1387 if (eventPtr
->type
== EnterNotify
) {
1388 intervalPtr
->flags
|= ACTIVE
;
1389 EventuallyRedrawInterval(intervalPtr
, REDRAW_SLIDER
);
1390 } else if (eventPtr
->type
== LeaveNotify
) {
1391 intervalPtr
->flags
&= ~ACTIVE
;
1392 EventuallyRedrawInterval(intervalPtr
, REDRAW_SLIDER
);
1393 } else if ((eventPtr
->type
== MotionNotify
)
1394 && (intervalPtr
->flags
& BUTTON_PRESSED
)) {
1395 TrackInterval(intervalPtr
, PixelToValue(intervalPtr
,
1396 eventPtr
->xmotion
.x
, eventPtr
->xmotion
.y
));
1397 } else if ((eventPtr
->type
== ButtonPress
)
1398 /* && (eventPtr->xbutton.button == Button1) */
1399 && (eventPtr
->xbutton
.state
== 0)) {
1400 intervalPtr
->flags
|= BUTTON_PRESSED
;
1401 StartTrackInterval(intervalPtr
, PixelToValue(intervalPtr
,
1402 eventPtr
->xbutton
.x
, eventPtr
->xbutton
.y
));
1403 /* NotifyInterval(intervalPtr); */
1404 EventuallyRedrawInterval(intervalPtr
, REDRAW_SLIDER
);
1405 } else if ((eventPtr
->type
== ButtonRelease
)
1406 /* && (eventPtr->xbutton.button == Button1) */
1407 && (intervalPtr
->flags
& BUTTON_PRESSED
)) {
1408 intervalPtr
->flags
&= ~BUTTON_PRESSED
;
1409 TrackInterval(intervalPtr
, PixelToValue(intervalPtr
,
1410 eventPtr
->xmotion
.x
, eventPtr
->xmotion
.y
));
1411 /* NotifyInterval(intervalPtr); */
1412 EventuallyRedrawInterval(intervalPtr
, REDRAW_SLIDER
);
1414 Tk_Release((ClientData
) intervalPtr
);
1418 *--------------------------------------------------------------
1422 * This procedure changes the value of a interval and invokes
1423 * a Tcl command to reflect the current position of a interval
1429 * A Tcl command is invoked, and an additional error-processing
1430 * command may also be invoked. The interval's slider is redrawn.
1432 *--------------------------------------------------------------
1436 StartTrackInterval(intervalPtr
, value
)
1437 register Interval
*intervalPtr
; /* Info about widget. */
1438 int value
; /* New value for interval. Gets
1439 * adjusted if it's off the interval. */
1444 if ((value
< intervalPtr
->fromValue
)
1445 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
1446 value
= intervalPtr
->fromValue
;
1448 if ((value
> intervalPtr
->toValue
)
1449 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
1450 value
= intervalPtr
->toValue
;
1452 intervalPtr
->trackValue
= value
;
1453 intervalPtr
->trackWidth
= intervalPtr
->maxValue
- intervalPtr
->minValue
;
1454 if (value
<= intervalPtr
->minValue
) {
1455 intervalPtr
->trackState
= -1;
1456 } else if (value
>= intervalPtr
->maxValue
) {
1457 intervalPtr
->trackState
= 1;
1459 intervalPtr
->trackState
= 0;
1461 SetInterval(intervalPtr
, intervalPtr
->minValue
, intervalPtr
->maxValue
, 1);
1466 TrackInterval(intervalPtr
, value
)
1467 register Interval
*intervalPtr
; /* Info about widget. */
1472 int min
, max
, delta
, lastmin
, lastmax
;
1475 delta
= value
- intervalPtr
->trackValue
;
1476 if (delta
== 0) return;
1478 intervalPtr
->trackValue
= value
;
1480 min
= intervalPtr
->minValue
;
1481 max
= intervalPtr
->maxValue
;
1483 switch (intervalPtr
->trackState
) {
1484 case -1: /* left trench */
1486 if (min
> max
) max
= min
;
1488 case 1: /* right trench */
1490 if (min
> max
) min
= max
;
1492 case 0: /* center slider */
1493 lastmin
= min
; lastmax
= max
;
1494 min
+= delta
; max
+= delta
;
1495 if ((max
- min
) != intervalPtr
->trackWidth
) { /* squished */
1496 if (lastmin
== intervalPtr
->fromValue
) {
1497 min
= max
- intervalPtr
->trackWidth
;
1498 } else if (lastmax
== intervalPtr
->toValue
) {
1499 max
= min
+ intervalPtr
->trackWidth
;
1505 SetInterval(intervalPtr
, min
, max
, 1);
1510 SetInterval(intervalPtr
, min
, max
, notify
)
1511 register Interval
*intervalPtr
; /* Info about widget. */
1512 int min
, max
, notify
;
1520 if ((min
< intervalPtr
->fromValue
)
1521 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
1522 min
= intervalPtr
->fromValue
;
1524 if ((min
> intervalPtr
->toValue
)
1525 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
1526 min
= intervalPtr
->toValue
;
1528 if ((max
< intervalPtr
->fromValue
)
1529 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
1530 max
= intervalPtr
->fromValue
;
1532 if ((max
> intervalPtr
->toValue
)
1533 ^ (intervalPtr
->toValue
< intervalPtr
->fromValue
)) {
1534 max
= intervalPtr
->toValue
;
1537 if ((min
== intervalPtr
->minValue
) &&
1538 (max
== intervalPtr
->maxValue
)) {
1542 intervalPtr
->minValue
= min
;
1543 intervalPtr
->maxValue
= max
;
1544 EventuallyRedrawInterval(intervalPtr
, REDRAW_SLIDER
);
1547 NotifyInterval(intervalPtr
);
1551 NotifyInterval(intervalPtr
)
1552 register Interval
*intervalPtr
; /* Info about widget. */
1557 sprintf(string
, " %d %d", intervalPtr
->minValue
, intervalPtr
->maxValue
);
1558 result
= Tcl_VarEval(intervalPtr
->interp
, intervalPtr
->command
, string
,
1560 if (result
!= TCL_OK
) {
1561 TkBindError(intervalPtr
->interp
);
1568 *--------------------------------------------------------------
1570 * EventuallyRedrawInterval --
1572 * Arrange for part or all of a interval widget to redrawn at
1573 * the next convenient time in the future.
1579 * If "what" is REDRAW_SLIDER then just the slider and the
1580 * value readout will be redrawn; if "what" is REDRAW_ALL
1581 * then the entire widget will be redrawn.
1583 *--------------------------------------------------------------
1587 EventuallyRedrawInterval(intervalPtr
, what
)
1588 register Interval
*intervalPtr
; /* Information about widget. */
1589 int what
; /* What to redraw: REDRAW_SLIDER
1592 if ((what
== 0) || (intervalPtr
->tkwin
== NULL
)
1593 || !Tk_IsMapped(intervalPtr
->tkwin
)) {
1596 if ((intervalPtr
->flags
& REDRAW_ALL
) == 0) {
1597 if (intervalPtr
->vertical
) {
1598 Tk_DoWhenIdle(DisplayVerticalInterval
, (ClientData
) intervalPtr
);
1600 Tk_DoWhenIdle(DisplayHorizontalInterval
, (ClientData
) intervalPtr
);
1603 intervalPtr
->flags
|= what
;