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