1 /*
2 * tkUnixScale.c --
3 *
4 * This file implements the X specific portion of the scrollbar widget.
5 *
6 * Copyright (c) 1996 by Sun Microsystems, Inc.
7 * Copyright (c) 1998-2000 by Scriptics Corporation.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 */
12
13 #include "tkInt.h"
14 #include "tkScale.h"
15
16 #if defined(_WIN32)
17 #define snprintf _snprintf
18 #endif
19
20 /*
21 * Forward declarations for functions defined later in this file:
22 */
23
24 static void DisplayHorizontalScale(TkScale *scalePtr,
25 Drawable drawable, XRectangle *drawnAreaPtr);
26 static void DisplayHorizontalValue(TkScale *scalePtr,
27 Drawable drawable, double value, int top,
28 const char *format);
29 static void DisplayVerticalScale(TkScale *scalePtr,
30 Drawable drawable, XRectangle *drawnAreaPtr);
31 static void DisplayVerticalValue(TkScale *scalePtr,
32 Drawable drawable, double value, int rightEdge,
33 const char *format);
34
35 /*
36 *----------------------------------------------------------------------
37 *
38 * TkpCreateScale --
39 *
40 * Allocate a new TkScale structure.
41 *
42 * Results:
43 * Returns a newly allocated TkScale structure.
44 *
45 * Side effects:
46 * None.
47 *
48 *----------------------------------------------------------------------
49 */
50
51 TkScale *
TkpCreateScale(TCL_UNUSED (Tk_Window))52 TkpCreateScale(
53 TCL_UNUSED(Tk_Window))
54 {
55 return (TkScale *)ckalloc(sizeof(TkScale));
56 }
57
58 /*
59 *----------------------------------------------------------------------
60 *
61 * TkpDestroyScale --
62 *
63 * Destroy a TkScale structure. It's necessary to do this with
64 * Tcl_EventuallyFree to allow the Tcl_Preserve(scalePtr) to work as
65 * expected in TkpDisplayScale. (hobbs)
66 *
67 * Results:
68 * None
69 *
70 * Side effects:
71 * Memory is freed.
72 *
73 *----------------------------------------------------------------------
74 */
75
76 void
TkpDestroyScale(TkScale * scalePtr)77 TkpDestroyScale(
78 TkScale *scalePtr)
79 {
80 Tcl_EventuallyFree(scalePtr, TCL_DYNAMIC);
81 }
82
83 /*
84 *--------------------------------------------------------------
85 *
86 * DisplayVerticalScale --
87 *
88 * This function redraws the contents of a vertical scale window. It is
89 * invoked as a do-when-idle handler, so it only runs when there's
90 * nothing else for the application to do.
91 *
92 * Results:
93 * There is no return value. If only a part of the scale needs to be
94 * redrawn, then drawnAreaPtr is modified to reflect the area that was
95 * actually modified.
96 *
97 * Side effects:
98 * Information appears on the screen.
99 *
100 *--------------------------------------------------------------
101 */
102
103 static void
DisplayVerticalScale(TkScale * scalePtr,Drawable drawable,XRectangle * drawnAreaPtr)104 DisplayVerticalScale(
105 TkScale *scalePtr, /* Widget record for scale. */
106 Drawable drawable, /* Where to display scale (window or
107 * pixmap). */
108 XRectangle *drawnAreaPtr) /* Initally contains area of window; if only a
109 * part of the scale is redrawn, gets modified
110 * to reflect the part of the window that was
111 * redrawn. */
112 {
113 Tk_Window tkwin = scalePtr->tkwin;
114 int x, y, width, height, shadowWidth;
115 double tickValue, tickInterval = scalePtr->tickInterval;
116 Tk_3DBorder sliderBorder;
117
118 /*
119 * Display the information from left to right across the window.
120 */
121
122 if (!(scalePtr->flags & REDRAW_OTHER)) {
123 drawnAreaPtr->x = scalePtr->vertTickRightX;
124 drawnAreaPtr->y = scalePtr->inset;
125 drawnAreaPtr->width = scalePtr->vertTroughX + scalePtr->width
126 + 2*scalePtr->borderWidth - scalePtr->vertTickRightX;
127 drawnAreaPtr->height -= 2*scalePtr->inset;
128 }
129 Tk_Fill3DRectangle(tkwin, drawable, scalePtr->bgBorder,
130 drawnAreaPtr->x, drawnAreaPtr->y, drawnAreaPtr->width,
131 drawnAreaPtr->height, 0, TK_RELIEF_FLAT);
132 if (scalePtr->flags & REDRAW_OTHER) {
133 /*
134 * Display the tick marks.
135 */
136
137 if (tickInterval != 0) {
138 double ticks, maxTicks;
139
140 /*
141 * Ensure that we will only draw enough of the tick values such
142 * that they don't overlap
143 */
144
145 ticks = fabs((scalePtr->toValue - scalePtr->fromValue)
146 / tickInterval);
147 maxTicks = (double) Tk_Height(tkwin)
148 / (double) scalePtr->fontHeight;
149 if (ticks > maxTicks) {
150 tickInterval *= (ticks / maxTicks);
151 }
152 for (tickValue = scalePtr->fromValue; ;
153 tickValue += tickInterval) {
154 /*
155 * The TkRoundValueToResolution call gets rid of accumulated
156 * round-off errors, if any.
157 */
158
159 tickValue = TkRoundValueToResolution(scalePtr, tickValue);
160 if (scalePtr->toValue >= scalePtr->fromValue) {
161 if (tickValue > scalePtr->toValue) {
162 break;
163 }
164 } else {
165 if (tickValue < scalePtr->toValue) {
166 break;
167 }
168 }
169 DisplayVerticalValue(scalePtr, drawable, tickValue,
170 scalePtr->vertTickRightX, scalePtr->tickFormat);
171 }
172 }
173 }
174
175 /*
176 * Display the value, if it is desired.
177 */
178
179 if (scalePtr->showValue) {
180 DisplayVerticalValue(scalePtr, drawable, scalePtr->value,
181 scalePtr->vertValueRightX, scalePtr->valueFormat);
182 }
183
184 /*
185 * Display the trough and the slider.
186 */
187
188 Tk_Draw3DRectangle(tkwin, drawable,
189 scalePtr->bgBorder, scalePtr->vertTroughX, scalePtr->inset,
190 scalePtr->width + 2*scalePtr->borderWidth,
191 Tk_Height(tkwin) - 2*scalePtr->inset, scalePtr->borderWidth,
192 TK_RELIEF_SUNKEN);
193 XFillRectangle(scalePtr->display, drawable, scalePtr->troughGC,
194 scalePtr->vertTroughX + scalePtr->borderWidth,
195 scalePtr->inset + scalePtr->borderWidth,
196 (unsigned) scalePtr->width,
197 (unsigned) (Tk_Height(tkwin) - 2*scalePtr->inset
198 - 2*scalePtr->borderWidth));
199 if (scalePtr->state == STATE_ACTIVE) {
200 sliderBorder = scalePtr->activeBorder;
201 } else {
202 sliderBorder = scalePtr->bgBorder;
203 }
204 width = scalePtr->width;
205 height = scalePtr->sliderLength/2;
206 x = scalePtr->vertTroughX + scalePtr->borderWidth;
207 y = TkScaleValueToPixel(scalePtr, scalePtr->value) - height;
208 shadowWidth = scalePtr->borderWidth/2;
209 if (shadowWidth == 0) {
210 shadowWidth = 1;
211 }
212 Tk_Draw3DRectangle(tkwin, drawable, sliderBorder, x, y, width,
213 2*height, shadowWidth, scalePtr->sliderRelief);
214 x += shadowWidth;
215 y += shadowWidth;
216 width -= 2*shadowWidth;
217 height -= shadowWidth;
218 Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y, width,
219 height, shadowWidth, scalePtr->sliderRelief);
220 Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y+height,
221 width, height, shadowWidth, scalePtr->sliderRelief);
222
223 /*
224 * Draw the label to the right of the scale.
225 */
226
227 if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelLength != 0)) {
228 Tk_FontMetrics fm;
229
230 Tk_GetFontMetrics(scalePtr->tkfont, &fm);
231 Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
232 scalePtr->tkfont, scalePtr->label,
233 scalePtr->labelLength, scalePtr->vertLabelX,
234 scalePtr->inset + (3 * fm.ascent) / 2);
235 }
236 }
237
238 /*
239 *----------------------------------------------------------------------
240 *
241 * DisplayVerticalValue --
242 *
243 * This function is called to display values (scale readings) for
244 * vertically-oriented scales.
245 *
246 * Results:
247 * None.
248 *
249 * Side effects:
250 * The numerical value corresponding to value is displayed with its right
251 * edge at "rightEdge", and at a vertical position in the scale that
252 * corresponds to "value".
253 *
254 *----------------------------------------------------------------------
255 */
256
257 static void
DisplayVerticalValue(TkScale * scalePtr,Drawable drawable,double value,int rightEdge,const char * format)258 DisplayVerticalValue(
259 TkScale *scalePtr, /* Information about widget in which to
260 * display value. */
261 Drawable drawable, /* Pixmap or window in which to draw the
262 * value. */
263 double value, /* Y-coordinate of number to display,
264 * specified in application coords, not in
265 * pixels (we'll compute pixels). */
266 int rightEdge, /* X-coordinate of right edge of text,
267 * specified in pixels. */
268 const char *format) /* Format string to use for the value */
269 {
270 Tk_Window tkwin = scalePtr->tkwin;
271 int y, width, length;
272 char valueString[TCL_DOUBLE_SPACE];
273 Tk_FontMetrics fm;
274
275 Tk_GetFontMetrics(scalePtr->tkfont, &fm);
276 y = TkScaleValueToPixel(scalePtr, value) + fm.ascent/2;
277 if (snprintf(valueString, TCL_DOUBLE_SPACE, format, value) < 0) {
278 valueString[TCL_DOUBLE_SPACE - 1] = '\0';
279 }
280 length = (int) strlen(valueString);
281 width = Tk_TextWidth(scalePtr->tkfont, valueString, length);
282
283 /*
284 * Adjust the y-coordinate if necessary to keep the text entirely inside
285 * the window.
286 */
287
288 if (y - fm.ascent < scalePtr->inset + SPACING) {
289 y = scalePtr->inset + SPACING + fm.ascent;
290 }
291 if (y + fm.descent > Tk_Height(tkwin) - scalePtr->inset - SPACING) {
292 y = Tk_Height(tkwin) - scalePtr->inset - SPACING - fm.descent;
293 }
294 Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
295 scalePtr->tkfont, valueString, length, rightEdge - width, y);
296 }
297
298 /*
299 *--------------------------------------------------------------
300 *
301 * DisplayHorizontalScale --
302 *
303 * This function redraws the contents of a horizontal scale window. It is
304 * invoked as a do-when-idle handler, so it only runs when there's
305 * nothing else for the application to do.
306 *
307 * Results:
308 * There is no return value. If only a part of the scale needs to be
309 * redrawn, then drawnAreaPtr is modified to reflect the area that was
310 * actually modified.
311 *
312 * Side effects:
313 * Information appears on the screen.
314 *
315 *--------------------------------------------------------------
316 */
317
318 static void
DisplayHorizontalScale(TkScale * scalePtr,Drawable drawable,XRectangle * drawnAreaPtr)319 DisplayHorizontalScale(
320 TkScale *scalePtr, /* Widget record for scale. */
321 Drawable drawable, /* Where to display scale (window or
322 * pixmap). */
323 XRectangle *drawnAreaPtr) /* Initally contains area of window; if only a
324 * part of the scale is redrawn, gets modified
325 * to reflect the part of the window that was
326 * redrawn. */
327 {
328 Tk_Window tkwin = scalePtr->tkwin;
329 int x, y, width, height, shadowWidth;
330 double tickInterval = scalePtr->tickInterval;
331 Tk_3DBorder sliderBorder;
332
333 /*
334 * Display the information from bottom to top across the window.
335 */
336
337 if (!(scalePtr->flags & REDRAW_OTHER)) {
338 drawnAreaPtr->x = scalePtr->inset;
339 drawnAreaPtr->y = scalePtr->horizValueY;
340 drawnAreaPtr->width -= 2*scalePtr->inset;
341 drawnAreaPtr->height = scalePtr->horizTroughY + scalePtr->width
342 + 2*scalePtr->borderWidth - scalePtr->horizValueY;
343 }
344 Tk_Fill3DRectangle(tkwin, drawable, scalePtr->bgBorder,
345 drawnAreaPtr->x, drawnAreaPtr->y, drawnAreaPtr->width,
346 drawnAreaPtr->height, 0, TK_RELIEF_FLAT);
347 if (scalePtr->flags & REDRAW_OTHER) {
348 /*
349 * Display the tick marks.
350 */
351
352 if (tickInterval != 0) {
353 char valueString[TCL_DOUBLE_SPACE];
354 double ticks, maxTicks, tickValue;
355
356 /*
357 * Ensure that we will only draw enough of the tick values such
358 * that they don't overlap. We base this off the width that
359 * fromValue would take. Not exact, but better than no constraint.
360 */
361
362 ticks = fabs((scalePtr->toValue - scalePtr->fromValue)
363 / tickInterval);
364 if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->tickFormat,
365 scalePtr->fromValue) < 0) {
366 valueString[TCL_DOUBLE_SPACE - 1] = '\0';
367 }
368 maxTicks = (double) Tk_Width(tkwin)
369 / (double) Tk_TextWidth(scalePtr->tkfont, valueString, -1);
370 if (ticks > maxTicks) {
371 tickInterval *= ticks / maxTicks;
372 }
373 tickValue = scalePtr->fromValue;
374 while (1) {
375 /*
376 * The TkRoundValueToResolution call gets rid of accumulated
377 * round-off errors, if any.
378 */
379
380 tickValue = TkRoundValueToResolution(scalePtr, tickValue);
381 if (scalePtr->toValue >= scalePtr->fromValue) {
382 if (tickValue > scalePtr->toValue) {
383 break;
384 }
385 } else {
386 if (tickValue < scalePtr->toValue) {
387 break;
388 }
389 }
390 DisplayHorizontalValue(scalePtr, drawable, tickValue,
391 scalePtr->horizTickY, scalePtr->tickFormat);
392 tickValue += tickInterval;
393 }
394 }
395 }
396
397 /*
398 * Display the value, if it is desired.
399 */
400
401 if (scalePtr->showValue) {
402 DisplayHorizontalValue(scalePtr, drawable, scalePtr->value,
403 scalePtr->horizValueY, scalePtr->valueFormat);
404 }
405
406 /*
407 * Display the trough and the slider.
408 */
409
410 y = scalePtr->horizTroughY;
411 Tk_Draw3DRectangle(tkwin, drawable,
412 scalePtr->bgBorder, scalePtr->inset, y,
413 Tk_Width(tkwin) - 2*scalePtr->inset,
414 scalePtr->width + 2*scalePtr->borderWidth,
415 scalePtr->borderWidth, TK_RELIEF_SUNKEN);
416 XFillRectangle(scalePtr->display, drawable, scalePtr->troughGC,
417 scalePtr->inset + scalePtr->borderWidth,
418 y + scalePtr->borderWidth,
419 (unsigned) (Tk_Width(tkwin) - 2*scalePtr->inset
420 - 2*scalePtr->borderWidth),
421 (unsigned) scalePtr->width);
422 if (scalePtr->state == STATE_ACTIVE) {
423 sliderBorder = scalePtr->activeBorder;
424 } else {
425 sliderBorder = scalePtr->bgBorder;
426 }
427 width = scalePtr->sliderLength/2;
428 height = scalePtr->width;
429 x = TkScaleValueToPixel(scalePtr, scalePtr->value) - width;
430 y += scalePtr->borderWidth;
431 shadowWidth = scalePtr->borderWidth/2;
432 if (shadowWidth == 0) {
433 shadowWidth = 1;
434 }
435 Tk_Draw3DRectangle(tkwin, drawable, sliderBorder,
436 x, y, 2*width, height, shadowWidth, scalePtr->sliderRelief);
437 x += shadowWidth;
438 y += shadowWidth;
439 width -= shadowWidth;
440 height -= 2*shadowWidth;
441 Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y, width, height,
442 shadowWidth, scalePtr->sliderRelief);
443 Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x+width, y,
444 width, height, shadowWidth, scalePtr->sliderRelief);
445
446 /*
447 * Draw the label at the top of the scale.
448 */
449
450 if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelLength != 0)) {
451 Tk_FontMetrics fm;
452
453 Tk_GetFontMetrics(scalePtr->tkfont, &fm);
454 Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
455 scalePtr->tkfont, scalePtr->label,
456 scalePtr->labelLength, scalePtr->inset + fm.ascent/2,
457 scalePtr->horizLabelY + fm.ascent);
458 }
459 }
460
461 /*
462 *----------------------------------------------------------------------
463 *
464 * DisplayHorizontalValue --
465 *
466 * This function is called to display values (scale readings) for
467 * horizontally-oriented scales.
468 *
469 * Results:
470 * None.
471 *
472 * Side effects:
473 * The numerical value corresponding to value is displayed with its
474 * bottom edge at "bottom", and at a horizontal position in the scale
475 * that corresponds to "value".
476 *
477 *----------------------------------------------------------------------
478 */
479
480 static void
DisplayHorizontalValue(TkScale * scalePtr,Drawable drawable,double value,int top,const char * format)481 DisplayHorizontalValue(
482 TkScale *scalePtr, /* Information about widget in which to
483 * display value. */
484 Drawable drawable, /* Pixmap or window in which to draw the
485 * value. */
486 double value, /* X-coordinate of number to display,
487 * specified in application coords, not in
488 * pixels (we'll compute pixels). */
489 int top, /* Y-coordinate of top edge of text, specified
490 * in pixels. */
491 const char *format) /* Format string to use for the value */
492 {
493 Tk_Window tkwin = scalePtr->tkwin;
494 int x, y, length, width;
495 char valueString[TCL_DOUBLE_SPACE];
496 Tk_FontMetrics fm;
497
498 x = TkScaleValueToPixel(scalePtr, value);
499 Tk_GetFontMetrics(scalePtr->tkfont, &fm);
500 y = top + fm.ascent;
501 if (snprintf(valueString, TCL_DOUBLE_SPACE, format, value) < 0) {
502 valueString[TCL_DOUBLE_SPACE - 1] = '\0';
503 }
504 length = (int) strlen(valueString);
505 width = Tk_TextWidth(scalePtr->tkfont, valueString, length);
506
507 /*
508 * Adjust the x-coordinate if necessary to keep the text entirely inside
509 * the window.
510 */
511
512 x -= width / 2;
513 if (x < scalePtr->inset + SPACING) {
514 x = scalePtr->inset + SPACING;
515 }
516
517 /*
518 * Check the right border so use starting point +text width for the check.
519 */
520
521 if (x + width >= (Tk_Width(tkwin) - scalePtr->inset)) {
522 x = Tk_Width(tkwin) - scalePtr->inset - SPACING - width;
523 }
524 Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
525 scalePtr->tkfont, valueString, length, x, y);
526 }
527
528 /*
529 *----------------------------------------------------------------------
530 *
531 * TkpDisplayScale --
532 *
533 * This function is invoked as an idle handler to redisplay the contents
534 * of a scale widget.
535 *
536 * Results:
537 * None.
538 *
539 * Side effects:
540 * The scale gets redisplayed.
541 *
542 *----------------------------------------------------------------------
543 */
544
545 void
TkpDisplayScale(ClientData clientData)546 TkpDisplayScale(
547 ClientData clientData) /* Widget record for scale. */
548 {
549 TkScale *scalePtr = (TkScale *)clientData;
550 Tk_Window tkwin = scalePtr->tkwin;
551 Tcl_Interp *interp = scalePtr->interp;
552 Pixmap pixmap;
553 int result;
554 char string[TCL_DOUBLE_SPACE];
555 XRectangle drawnArea;
556 Tcl_DString buf;
557
558 scalePtr->flags &= ~REDRAW_PENDING;
559 if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) {
560 goto done;
561 }
562
563 /*
564 * Invoke the scale's command if needed.
565 */
566
567 Tcl_Preserve(scalePtr);
568 if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
569 Tcl_Preserve(interp);
570 if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->valueFormat,
571 scalePtr->value) < 0) {
572 string[TCL_DOUBLE_SPACE - 1] = '\0';
573 }
574 Tcl_DStringInit(&buf);
575 Tcl_DStringAppend(&buf, scalePtr->command, -1);
576 Tcl_DStringAppend(&buf, " ", -1);
577 Tcl_DStringAppend(&buf, string, -1);
578 result = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, TCL_EVAL_GLOBAL);
579 Tcl_DStringFree(&buf);
580 if (result != TCL_OK) {
581 Tcl_AddErrorInfo(interp, "\n (command executed by scale)");
582 Tcl_BackgroundException(interp, result);
583 }
584 Tcl_Release(interp);
585 }
586 scalePtr->flags &= ~INVOKE_COMMAND;
587 if (scalePtr->flags & SCALE_DELETED) {
588 Tcl_Release(scalePtr);
589 return;
590 }
591 Tcl_Release(scalePtr);
592
593 #ifndef TK_NO_DOUBLE_BUFFERING
594 /*
595 * In order to avoid screen flashes, this function redraws the scale in a
596 * pixmap, then copies the pixmap to the screen in a single operation.
597 * This means that there's no point in time where the on-sreen image has
598 * been cleared.
599 */
600
601 pixmap = Tk_GetPixmap(scalePtr->display, Tk_WindowId(tkwin),
602 Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
603 #else
604 pixmap = Tk_WindowId(tkwin);
605 #endif /* TK_NO_DOUBLE_BUFFERING */
606 drawnArea.x = 0;
607 drawnArea.y = 0;
608 drawnArea.width = Tk_Width(tkwin);
609 drawnArea.height = Tk_Height(tkwin);
610
611 /*
612 * Much of the redisplay is done totally differently for horizontal and
613 * vertical scales. Handle the part that's different.
614 */
615
616 if (scalePtr->orient == ORIENT_VERTICAL) {
617 DisplayVerticalScale(scalePtr, pixmap, &drawnArea);
618 } else {
619 DisplayHorizontalScale(scalePtr, pixmap, &drawnArea);
620 }
621
622 /*
623 * Now handle the part of redisplay that is the same for horizontal and
624 * vertical scales: border and traversal highlight.
625 */
626
627 if (scalePtr->flags & REDRAW_OTHER) {
628 if (scalePtr->relief != TK_RELIEF_FLAT) {
629 Tk_Draw3DRectangle(tkwin, pixmap, scalePtr->bgBorder,
630 scalePtr->highlightWidth, scalePtr->highlightWidth,
631 Tk_Width(tkwin) - 2*scalePtr->highlightWidth,
632 Tk_Height(tkwin) - 2*scalePtr->highlightWidth,
633 scalePtr->borderWidth, scalePtr->relief);
634 }
635 if (scalePtr->highlightWidth != 0) {
636 GC gc;
637
638 if (scalePtr->flags & GOT_FOCUS) {
639 gc = Tk_GCForColor(scalePtr->highlightColorPtr, pixmap);
640 } else {
641 gc = Tk_GCForColor(
642 Tk_3DBorderColor(scalePtr->highlightBorder), pixmap);
643 }
644 Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, pixmap);
645 }
646 }
647
648 #ifndef TK_NO_DOUBLE_BUFFERING
649 /*
650 * Copy the information from the off-screen pixmap onto the screen, then
651 * delete the pixmap.
652 */
653
654 XCopyArea(scalePtr->display, pixmap, Tk_WindowId(tkwin),
655 scalePtr->copyGC, drawnArea.x, drawnArea.y, drawnArea.width,
656 drawnArea.height, drawnArea.x, drawnArea.y);
657 Tk_FreePixmap(scalePtr->display, pixmap);
658 #endif /* TK_NO_DOUBLE_BUFFERING */
659
660 done:
661 scalePtr->flags &= ~REDRAW_ALL;
662 }
663
664 /*
665 *----------------------------------------------------------------------
666 *
667 * TkpScaleElement --
668 *
669 * Determine which part of a scale widget lies under a given point.
670 *
671 * Results:
672 * The return value is either TROUGH1, SLIDER, TROUGH2, or OTHER,
673 * depending on which of the scale's active elements (if any) is under
674 * the point at (x,y).
675 *
676 * Side effects:
677 * None.
678 *
679 *----------------------------------------------------------------------
680 */
681
682 int
TkpScaleElement(TkScale * scalePtr,int x,int y)683 TkpScaleElement(
684 TkScale *scalePtr, /* Widget record for scale. */
685 int x, int y) /* Coordinates within scalePtr's window. */
686 {
687 int sliderFirst;
688
689 if (scalePtr->orient == ORIENT_VERTICAL) {
690 if ((x < scalePtr->vertTroughX)
691 || (x >= (scalePtr->vertTroughX + 2*scalePtr->borderWidth +
692 scalePtr->width))) {
693 return OTHER;
694 }
695 if ((y < scalePtr->inset)
696 || (y >= (Tk_Height(scalePtr->tkwin) - scalePtr->inset))) {
697 return OTHER;
698 }
699 sliderFirst = TkScaleValueToPixel(scalePtr, scalePtr->value)
700 - scalePtr->sliderLength/2;
701 if (y < sliderFirst) {
702 return TROUGH1;
703 }
704 if (y < sliderFirst + scalePtr->sliderLength) {
705 return SLIDER;
706 }
707 return TROUGH2;
708 }
709
710 if ((y < scalePtr->horizTroughY)
711 || (y >= (scalePtr->horizTroughY + 2*scalePtr->borderWidth +
712 scalePtr->width))) {
713 return OTHER;
714 }
715 if ((x < scalePtr->inset)
716 || (x >= (Tk_Width(scalePtr->tkwin) - scalePtr->inset))) {
717 return OTHER;
718 }
719 sliderFirst = TkScaleValueToPixel(scalePtr, scalePtr->value)
720 - scalePtr->sliderLength/2;
721 if (x < sliderFirst) {
722 return TROUGH1;
723 }
724 if (x < sliderFirst + scalePtr->sliderLength) {
725 return SLIDER;
726 }
727 return TROUGH2;
728 }
729
730 /*
731 * Local Variables:
732 * mode: c
733 * c-basic-offset: 4
734 * fill-column: 78
735 * End:
736 */
737