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