Annotation of micropolis/src/sim/w_inter.c, revision 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.