Annotation of micropolis/src/tk/tkscale.c, revision 1.1

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

unix.superglobalmegacorp.com

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