Annotation of micropolis/src/sim/w_inter.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.