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