Annotation of micropolis/src/tk/tkscale.c, revision 1.1.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.