4 * This module implements a scrollbar widgets for the
5 * toolkit. A scrollbar displays a slider and two arrows;
6 * mouse clicks on features within the scrollbar cause
7 * scrolling commands to be invoked.
9 * Copyright (c) 1990-1994 The Regents of the University of California.
10 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
11 * Copyright (c) 1995 Christian Werner
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 * A data structure of the following type is kept for each scrollbar
23 * widget managed by this file:
27 CkWindow *winPtr; /* Window that embodies the scrollbar. NULL
28 * means that the window has been destroyed
29 * but the data structures haven't yet been
31 Tcl_Interp *interp; /* Interpreter associated with scrollbar. */
32 Tcl_Command widgetCmd; /* Token for scrollbar's widget command. */
33 Ck_Uid orientUid; /* Orientation for window ("vertical" or
35 int vertical; /* Non-zero means vertical orientation
36 * requested, zero means horizontal. */
37 char *command; /* Command prefix to use when invoking
38 * scrolling commands. NULL means don't
39 * invoke commands. Malloc'ed. */
40 int commandSize; /* Number of non-NULL bytes in command. */
43 * Information used when displaying widget:
46 int normalBg; /* Used for drawing background. */
47 int normalFg; /* Used for drawing foreground. */
48 int normalAttr; /* Video attributes for normal mode. */
49 int activeBg; /* Background in active mode. */
50 int activeFg; /* Foreground in active mode. */
51 int activeAttr; /* Video attributes for active mode. */
53 int sliderFirst; /* Coordinate of top or left edge
55 int sliderLast; /* Coordinate just after bottom
56 * or right edge of slider area. */
58 * Information describing the application related to the scrollbar.
59 * This information is provided by the application by invoking the
60 * "set" widget command.
63 double firstFraction; /* Position of first visible thing in window,
64 * specified as a fraction between 0 and
66 double lastFraction; /* Position of last visible thing in window,
67 * specified as a fraction between 0 and
71 * Miscellaneous information:
74 char *takeFocus; /* Value of -takefocus option; not used in
75 * the C code, but used by keyboard traversal
76 * scripts. Malloc'ed, but may be NULL. */
77 int flags; /* Various flags; see below for
82 * Flag bits for scrollbars:
84 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
85 * has already been queued to redraw
87 * ACTIVATED: 1 means draw in activated mode,
88 * 0 means draw in normal mode
91 #define REDRAW_PENDING 1
95 * Legal values for identifying position in scrollbar. These
96 * are the return values from the ScrollbarPosition procedure.
104 #define BOTTOM_ARROW 5
107 * Minimum slider length, in pixels (designed to make sure that the slider
108 * is always easy to grab with the mouse).
111 #define MIN_SLIDER_LENGTH 1
114 * Information used for argv parsing.
117 static Ck_ConfigSpec configSpecs[] = {
118 {CK_CONFIG_ATTR, "-activeattributes", "activeAttributes", "Attributes",
119 DEF_SCROLLBAR_ACTIVE_ATTR_COLOR, Ck_Offset(Scrollbar, activeAttr),
120 CK_CONFIG_COLOR_ONLY},
121 {CK_CONFIG_ATTR, "-activeattributes", "activeAttributes", "Attributes",
122 DEF_SCROLLBAR_ACTIVE_ATTR_MONO, Ck_Offset(Scrollbar, activeAttr),
123 CK_CONFIG_MONO_ONLY},
124 {CK_CONFIG_COLOR, "-activebackground", "activeBackground", "Foreground",
125 DEF_SCROLLBAR_ACTIVE_BG_COLOR, Ck_Offset(Scrollbar, activeBg),
126 CK_CONFIG_COLOR_ONLY},
127 {CK_CONFIG_COLOR, "-activebackground", "activeBackground", "Foreground",
128 DEF_SCROLLBAR_ACTIVE_BG_MONO, Ck_Offset(Scrollbar, activeBg),
129 CK_CONFIG_MONO_ONLY},
130 {CK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
131 DEF_SCROLLBAR_ACTIVE_FG_COLOR, Ck_Offset(Scrollbar, activeFg),
132 CK_CONFIG_COLOR_ONLY},
133 {CK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
134 DEF_SCROLLBAR_ACTIVE_FG_MONO, Ck_Offset(Scrollbar, activeBg),
135 CK_CONFIG_MONO_ONLY},
136 {CK_CONFIG_ATTR, "-attributes", "attributes", "Attributes",
137 DEF_SCROLLBAR_ATTR, Ck_Offset(Scrollbar, normalAttr), 0},
138 {CK_CONFIG_COLOR, "-background", "background", "Background",
139 DEF_SCROLLBAR_BG_COLOR, Ck_Offset(Scrollbar, normalBg),
140 CK_CONFIG_COLOR_ONLY},
141 {CK_CONFIG_COLOR, "-background", "background", "Background",
142 DEF_SCROLLBAR_BG_MONO, Ck_Offset(Scrollbar, normalBg),
143 CK_CONFIG_MONO_ONLY},
144 {CK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
145 (char *) NULL, 0, 0},
146 {CK_CONFIG_STRING, "-command", "command", "Command",
147 DEF_SCROLLBAR_COMMAND, Ck_Offset(Scrollbar, command),
149 {CK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
150 DEF_SCROLLBAR_FG_COLOR, Ck_Offset(Scrollbar, normalFg),
151 CK_CONFIG_COLOR_ONLY},
152 {CK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
153 DEF_SCROLLBAR_FG_MONO, Ck_Offset(Scrollbar, normalFg),
154 CK_CONFIG_MONO_ONLY},
155 {CK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
156 (char *) NULL, 0, 0},
157 {CK_CONFIG_UID, "-orient", "orient", "Orient",
158 DEF_SCROLLBAR_ORIENT, Ck_Offset(Scrollbar, orientUid), 0},
159 {CK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
160 DEF_SCROLLBAR_TAKE_FOCUS, Ck_Offset(Scrollbar, takeFocus),
162 {CK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
167 * Forward declarations for procedures defined later in this file:
170 static void ComputeScrollbarGeometry _ANSI_ARGS_((
171 Scrollbar *scrollPtr));
172 static int ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp,
173 Scrollbar *scrollPtr, int argc, char **argv,
175 static void DestroyScrollbar _ANSI_ARGS_((ClientData clientData));
176 static void DisplayScrollbar _ANSI_ARGS_((ClientData clientData));
177 static void EventuallyRedraw _ANSI_ARGS_((Scrollbar *scrollPtr));
178 static void ScrollbarEventProc _ANSI_ARGS_((ClientData clientData,
180 static void ScrollbarCmdDeletedProc _ANSI_ARGS_((
181 ClientData clientData));
182 static int ScrollbarPosition _ANSI_ARGS_((Scrollbar *scrollPtr,
184 static int ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData,
185 Tcl_Interp *, int argc, char **argv));
188 *--------------------------------------------------------------
192 * This procedure is invoked to process the "scrollbar" Tcl
193 * command. See the user documentation for details on what
197 * A standard Tcl result.
200 * See the user documentation.
202 *--------------------------------------------------------------
206 Ck_ScrollbarCmd(clientData, interp, argc, argv)
207 ClientData clientData; /* Main window associated with
209 Tcl_Interp *interp; /* Current interpreter. */
210 int argc; /* Number of arguments. */
211 char **argv; /* Argument strings. */
213 CkWindow *mainPtr = (CkWindow *) clientData;
214 register Scrollbar *scrollPtr;
218 Tcl_AppendResult(interp, "wrong # args: should be \"",
219 argv[0], " pathName ?options?\"", (char *) NULL);
223 new = Ck_CreateWindowFromPath(interp, mainPtr, argv[1], 0);
229 * Initialize fields that won't be initialized by ConfigureScrollbar,
230 * or which ConfigureScrollbar expects to have reasonable values
231 * (e.g. resource pointers).
234 scrollPtr = (Scrollbar *) ckalloc(sizeof (Scrollbar));
235 scrollPtr->winPtr = new;
236 scrollPtr->interp = interp;
237 scrollPtr->widgetCmd = Tcl_CreateCommand(interp,
238 scrollPtr->winPtr->pathName, ScrollbarWidgetCmd,
239 (ClientData) scrollPtr, ScrollbarCmdDeletedProc);
240 scrollPtr->orientUid = NULL;
241 scrollPtr->vertical = 0;
242 scrollPtr->command = NULL;
243 scrollPtr->commandSize = 0;
244 scrollPtr->normalBg = 0;
245 scrollPtr->normalFg = 0;
246 scrollPtr->normalAttr = 0;
247 scrollPtr->activeBg = 0;
248 scrollPtr->activeFg = 0;
249 scrollPtr->activeAttr = 0;
250 scrollPtr->firstFraction = 0.0;
251 scrollPtr->lastFraction = 0.0;
252 scrollPtr->takeFocus = NULL;
253 scrollPtr->flags = 0;
255 Ck_SetClass(scrollPtr->winPtr, "Scrollbar");
256 Ck_CreateEventHandler(scrollPtr->winPtr,
257 CK_EV_EXPOSE | CK_EV_MAP | CK_EV_DESTROY,
258 ScrollbarEventProc, (ClientData) scrollPtr);
259 if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) {
263 interp->result = scrollPtr->winPtr->pathName;
267 Ck_DestroyWindow(scrollPtr->winPtr);
272 *--------------------------------------------------------------
274 * ScrollbarWidgetCmd --
276 * This procedure is invoked to process the Tcl command
277 * that corresponds to a widget managed by this module.
278 * See the user documentation for details on what it does.
281 * A standard Tcl result.
284 * See the user documentation.
286 *--------------------------------------------------------------
290 ScrollbarWidgetCmd(clientData, interp, argc, argv)
291 ClientData clientData; /* Information about scrollbar
293 Tcl_Interp *interp; /* Current interpreter. */
294 int argc; /* Number of arguments. */
295 char **argv; /* Argument strings. */
297 register Scrollbar *scrollPtr = (Scrollbar *) clientData;
303 Tcl_AppendResult(interp, "wrong # args: should be \"",
304 argv[0], " option ?arg arg ...?\"", (char *) NULL);
307 Ck_Preserve((ClientData) scrollPtr);
309 length = strlen(argv[1]);
310 if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) {
312 Tcl_AppendResult(interp, "wrong # args: should be \"",
313 argv[0], " activate\"", (char *) NULL);
316 if (!(scrollPtr->flags & ACTIVATED)) {
317 scrollPtr->flags |= ACTIVATED;
318 EventuallyRedraw(scrollPtr);
320 } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
323 Tcl_AppendResult(interp, "wrong # args: should be \"",
324 argv[0], " cget option\"",
328 result = Ck_ConfigureValue(interp, scrollPtr->winPtr, configSpecs,
329 (char *) scrollPtr, argv[2], 0);
330 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
333 result = Ck_ConfigureInfo(interp, scrollPtr->winPtr, configSpecs,
334 (char *) scrollPtr, (char *) NULL, 0);
335 } else if (argc == 3) {
336 result = Ck_ConfigureInfo(interp, scrollPtr->winPtr, configSpecs,
337 (char *) scrollPtr, argv[2], 0);
339 result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2,
340 CK_CONFIG_ARGV_ONLY);
342 } else if ((c == 'd') && (strncmp(argv[1], "deactivate", length) == 0)) {
344 Tcl_AppendResult(interp, "wrong # args: should be \"",
345 argv[0], " deactivate\"", (char *) NULL);
348 if (scrollPtr->flags & ACTIVATED) {
349 scrollPtr->flags &= ~ACTIVATED;
350 EventuallyRedraw(scrollPtr);
352 } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) {
353 int x, y, pos, length;
357 Tcl_AppendResult(interp, "wrong # args: should be \"",
358 argv[0], " fraction x y\"", (char *) NULL);
361 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
362 || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
365 if (scrollPtr->vertical) {
367 length = scrollPtr->winPtr->height - 1 - 2;
370 length = scrollPtr->winPtr->width - 1 - 2;
375 fraction = ((double) pos / (double) length);
379 } else if (fraction > 1.0) {
382 sprintf(interp->result, "%g", fraction);
383 } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
384 char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE];
386 Tcl_AppendResult(interp, "wrong # args: should be \"",
387 argv[0], " get\"", (char *) NULL);
390 Tcl_PrintDouble(interp, scrollPtr->firstFraction, first);
391 Tcl_PrintDouble(interp, scrollPtr->lastFraction, last);
392 Tcl_AppendResult(interp, first, " ", last, (char *) NULL);
393 } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) {
397 Tcl_AppendResult(interp, "wrong # args: should be \"",
398 argv[0], " identify x y\"", (char *) NULL);
401 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
402 || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
405 thing = ScrollbarPosition(scrollPtr, x, y);
407 case TOP_ARROW: interp->result = "arrow1"; break;
408 case TOP_GAP: interp->result = "trough1"; break;
409 case SLIDER: interp->result = "slider"; break;
410 case BOTTOM_GAP: interp->result = "trough2"; break;
411 case BOTTOM_ARROW: interp->result = "arrow2"; break;
413 } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) {
417 if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) {
420 if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) {
424 scrollPtr->firstFraction = 0;
425 } else if (first > 1.0) {
426 scrollPtr->firstFraction = 1.0;
428 scrollPtr->firstFraction = first;
430 if (last < scrollPtr->firstFraction) {
431 scrollPtr->lastFraction = scrollPtr->firstFraction;
432 } else if (last > 1.0) {
433 scrollPtr->lastFraction = 1.0;
435 scrollPtr->lastFraction = last;
438 Tcl_AppendResult(interp, "wrong # args: should be \"",
439 argv[0], " set firstFraction lastFraction\"",
443 ComputeScrollbarGeometry(scrollPtr);
444 EventuallyRedraw(scrollPtr);
446 Tcl_AppendResult(interp, "bad option \"", argv[1],
447 "\": must be activate, cget, configure, deactivate, ",
448 "fraction, get, or set", (char *) NULL);
451 Ck_Release((ClientData) scrollPtr);
455 Ck_Release((ClientData) scrollPtr);
460 *----------------------------------------------------------------------
462 * DestroyScrollbar --
464 * This procedure is invoked by Ck_EventuallyFree or Ck_Release
465 * to clean up the internal structure of a scrollbar at a safe time
466 * (when no-one is using it anymore).
472 * Everything associated with the scrollbar is freed up.
474 *----------------------------------------------------------------------
478 DestroyScrollbar(clientData)
479 ClientData clientData; /* Info about scrollbar widget. */
481 register Scrollbar *scrollPtr = (Scrollbar *) clientData;
484 * Free up all the stuff that requires special handling, then
485 * let Ck_FreeOptions handle all the standard option-related
489 Ck_FreeOptions(configSpecs, (char *) scrollPtr, 0);
490 ckfree((char *) scrollPtr);
494 *----------------------------------------------------------------------
496 * ScrollbarCmdDeletedProc --
498 * This procedure is invoked when a widget command is deleted. If
499 * the widget isn't already in the process of being destroyed,
500 * this command destroys it.
506 * The widget is destroyed.
508 *----------------------------------------------------------------------
512 ScrollbarCmdDeletedProc(clientData)
513 ClientData clientData; /* Pointer to widget record for widget. */
515 Scrollbar *scrollPtr = (Scrollbar *) clientData;
516 CkWindow *winPtr = scrollPtr->winPtr;
519 * This procedure could be invoked either because the window was
520 * destroyed and the command was then deleted (in which case winPtr
521 * is NULL) or because the command was deleted, and then this procedure
522 * destroys the widget.
525 if (winPtr != NULL) {
526 scrollPtr->winPtr = NULL;
527 Ck_DestroyWindow(winPtr);
532 *----------------------------------------------------------------------
534 * ConfigureScrollbar --
536 * This procedure is called to process an argv/argc list, plus
537 * the option database, in order to configure (or
538 * reconfigure) a scrollbar widget.
541 * The return value is a standard Tcl result. If TCL_ERROR is
542 * returned, then interp->result contains an error message.
545 * Configuration information, such as colors, border width,
546 * etc. get set for scrollPtr; old resources get freed,
549 *----------------------------------------------------------------------
553 ConfigureScrollbar(interp, scrollPtr, argc, argv, flags)
554 Tcl_Interp *interp; /* Used for error reporting. */
555 register Scrollbar *scrollPtr; /* Information about widget; may or
556 * may not already have values for
558 int argc; /* Number of valid entries in argv. */
559 char **argv; /* Arguments. */
560 int flags; /* Flags to pass to
561 * Ck_ConfigureWidget. */
565 if (Ck_ConfigureWidget(interp, scrollPtr->winPtr, configSpecs,
566 argc, argv, (char *) scrollPtr, flags) != TCL_OK) {
571 * A few options need special processing, such as parsing the
572 * orientation or setting the background from a 3-D border.
575 length = strlen(scrollPtr->orientUid);
576 if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) {
577 scrollPtr->vertical = 1;
578 } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) {
579 scrollPtr->vertical = 0;
581 Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid,
582 "\": must be vertical or horizontal", (char *) NULL);
586 if (scrollPtr->command != NULL) {
587 scrollPtr->commandSize = strlen(scrollPtr->command);
589 scrollPtr->commandSize = 0;
593 * Register the desired geometry for the window (leave enough space
594 * for the two arrows plus a minimum-size slider, plus border around
595 * the whole window, if any). Then arrange for the window to be
599 ComputeScrollbarGeometry(scrollPtr);
600 EventuallyRedraw(scrollPtr);
605 *--------------------------------------------------------------
607 * DisplayScrollbar --
609 * This procedure redraws the contents of a scrollbar window.
610 * It is invoked as a do-when-idle handler, so it only runs
611 * when there's nothing else for the application to do.
617 * Information appears on the screen.
619 *--------------------------------------------------------------
623 DisplayScrollbar(clientData)
624 ClientData clientData; /* Information about window. */
626 register Scrollbar *scrollPtr = (Scrollbar *) clientData;
627 register CkWindow *winPtr = scrollPtr->winPtr;
630 if ((scrollPtr->winPtr == NULL) || !(winPtr->flags & CK_MAPPED)) {
634 width = (scrollPtr->vertical ? winPtr->height : winPtr->width);
636 if (scrollPtr->flags & ACTIVATED) {
637 Ck_SetWindowAttr(winPtr, scrollPtr->activeFg,
638 scrollPtr->activeBg, scrollPtr->activeAttr);
640 Ck_SetWindowAttr(winPtr, scrollPtr->normalFg,
641 scrollPtr->normalBg, scrollPtr->normalAttr);
645 * Fill space left with blanks.
648 if (scrollPtr->vertical) {
649 for (i = 0; i < width; i++) {
650 wmove(winPtr->window, i, 0);
651 waddch(winPtr->window, ' ');
654 wmove(winPtr->window, 0, 0);
655 for (i = 0; i < width; i++) {
656 waddch(winPtr->window, ' ');
661 * Display the slider.
664 Ck_GetGChar(scrollPtr->interp, "ckboard", &gchar);
665 if (scrollPtr->vertical) {
666 for (i = scrollPtr->sliderFirst; i < scrollPtr->sliderLast; i++) {
667 mvwaddch(winPtr->window, i, 0, gchar);
670 wmove(winPtr->window, 0, scrollPtr->sliderFirst);
671 for (i = scrollPtr->sliderFirst; i < scrollPtr->sliderLast; i++) {
672 waddch(winPtr->window, gchar);
677 * Display top or left arrow.
680 Ck_GetGChar(scrollPtr->interp, scrollPtr->vertical ? "uarrow" : "larrow",
682 mvwaddch(winPtr->window, 0, 0, gchar);
685 * Display the bottom or right arrow.
688 Ck_GetGChar(scrollPtr->interp, scrollPtr->vertical ? "darrow" : "rarrow",
690 scrollPtr->vertical ? wmove(winPtr->window, width - 1, 0) :
691 wmove(winPtr->window, 0, width - 1);
692 waddch(winPtr->window, gchar);
694 Ck_EventuallyRefresh(winPtr);
697 scrollPtr->flags &= ~REDRAW_PENDING;
701 *--------------------------------------------------------------
703 * ScrollbarEventProc --
705 * This procedure is invoked by the dispatcher for various
706 * events on scrollbars.
712 * When the window gets deleted, internal structures get
713 * cleaned up. When it gets exposed, it is redisplayed.
715 *--------------------------------------------------------------
719 ScrollbarEventProc(clientData, eventPtr)
720 ClientData clientData; /* Information about window. */
721 CkEvent *eventPtr; /* Information about event. */
723 Scrollbar *scrollPtr = (Scrollbar *) clientData;
725 if (eventPtr->type == CK_EV_EXPOSE) {
726 ComputeScrollbarGeometry(scrollPtr);
727 EventuallyRedraw(scrollPtr);
728 } else if (eventPtr->type == CK_EV_DESTROY) {
729 if (scrollPtr->winPtr != NULL) {
730 scrollPtr->winPtr = NULL;
731 Tcl_DeleteCommand(scrollPtr->interp,
732 Tcl_GetCommandName(scrollPtr->interp, scrollPtr->widgetCmd));
734 if (scrollPtr->flags & REDRAW_PENDING) {
735 Tk_CancelIdleCall(DisplayScrollbar, (ClientData) scrollPtr);
737 Ck_EventuallyFree((ClientData) scrollPtr,
738 (Ck_FreeProc *) DestroyScrollbar);
743 *----------------------------------------------------------------------
745 * ComputeScrollbarGeometry --
747 * After changes in a scrollbar's size or configuration, this
748 * procedure recomputes various geometry information used in
749 * displaying the scrollbar.
755 * The scrollbar will be displayed differently.
757 *----------------------------------------------------------------------
761 ComputeScrollbarGeometry(scrollPtr)
762 register Scrollbar *scrollPtr; /* Scrollbar whose geometry may
767 fieldLength = (scrollPtr->vertical ? scrollPtr->winPtr->height
768 : scrollPtr->winPtr->width) - 2;
769 if (fieldLength < 0) {
772 scrollPtr->sliderFirst = (int) (fieldLength * scrollPtr->firstFraction);
773 scrollPtr->sliderLast = (int) (fieldLength * scrollPtr->lastFraction);
776 * Adjust the slider so that some piece of it is always
777 * displayed in the scrollbar and so that it has at least
778 * a minimal width (so it can be grabbed with the mouse).
781 if (scrollPtr->sliderFirst > fieldLength) {
782 scrollPtr->sliderFirst = fieldLength;
784 if (scrollPtr->sliderFirst < 0) {
785 scrollPtr->sliderFirst = 0;
787 if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
788 + MIN_SLIDER_LENGTH)) {
789 scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
791 if (scrollPtr->sliderLast > fieldLength) {
792 scrollPtr->sliderLast = fieldLength;
794 scrollPtr->sliderFirst += 1;
795 scrollPtr->sliderLast += 1;
798 * Register the desired geometry for the window (leave enough space
799 * for the two arrows plus a minimum-size slider, plus border around
800 * the whole window, if any). Then arrange for the window to be
804 if (scrollPtr->vertical) {
805 Ck_GeometryRequest(scrollPtr->winPtr, 1, 2 + MIN_SLIDER_LENGTH);
807 Ck_GeometryRequest(scrollPtr->winPtr, 2 + MIN_SLIDER_LENGTH, 1);
812 *--------------------------------------------------------------
814 * ScrollbarPosition --
816 * Determine the scrollbar element corresponding to a
820 * One of TOP_ARROW, TOP_GAP, etc., indicating which element
821 * of the scrollbar covers the position given by (x, y). If
822 * (x,y) is outside the scrollbar entirely, then OUTSIDE is
828 *--------------------------------------------------------------
832 ScrollbarPosition(scrollPtr, x, y)
833 register Scrollbar *scrollPtr; /* Scrollbar widget record. */
834 int x, y; /* Coordinates within scrollPtr's
837 int length, width, tmp;
839 if (scrollPtr->vertical) {
840 length = scrollPtr->winPtr->height;
841 width = scrollPtr->winPtr->width;
846 length = scrollPtr->winPtr->width;
847 width = scrollPtr->winPtr->height;
850 if (x < 0 || x >= width || y < 0 || y >= length)
855 if (y < scrollPtr->sliderFirst)
857 if (y < scrollPtr->sliderLast)
865 *--------------------------------------------------------------
867 * EventuallyRedraw --
869 * Arrange for one or more of the fields of a scrollbar
878 *--------------------------------------------------------------
882 EventuallyRedraw(scrollPtr)
883 register Scrollbar *scrollPtr; /* Information about widget. */
885 if ((scrollPtr->winPtr == NULL) ||
886 !(scrollPtr->winPtr->flags & CK_MAPPED)) {
889 if ((scrollPtr->flags & REDRAW_PENDING) == 0) {
890 Tk_DoWhenIdle(DisplayScrollbar, (ClientData) scrollPtr);
891 scrollPtr->flags |= REDRAW_PENDING;