tkUnixScale.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:21k
- /*
- * tkUnixScale.c --
- *
- * This file implements the X specific portion of the scrollbar
- * widget.
- *
- * Copyright (c) 1996 by Sun Microsystems, Inc.
- * Copyright (c) 1998-2000 by Scriptics Corporation.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkUnixScale.c,v 1.8.4.2 2007/04/29 02:24:01 das Exp $
- */
- #include "tkScale.h"
- #include "tkInt.h"
- /*
- * Forward declarations for procedures defined later in this file:
- */
- static void DisplayHorizontalScale _ANSI_ARGS_((TkScale *scalePtr,
- Drawable drawable, XRectangle *drawnAreaPtr));
- static void DisplayHorizontalValue _ANSI_ARGS_((TkScale *scalePtr,
- Drawable drawable, double value, int top));
- static void DisplayVerticalScale _ANSI_ARGS_((TkScale *scalePtr,
- Drawable drawable, XRectangle *drawnAreaPtr));
- static void DisplayVerticalValue _ANSI_ARGS_((TkScale *scalePtr,
- Drawable drawable, double value, int rightEdge));
- /*
- *----------------------------------------------------------------------
- *
- * TkpCreateScale --
- *
- * Allocate a new TkScale structure.
- *
- * Results:
- * Returns a newly allocated TkScale structure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- TkScale *
- TkpCreateScale(tkwin)
- Tk_Window tkwin;
- {
- return (TkScale *) ckalloc(sizeof(TkScale));
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpDestroyScale --
- *
- * Destroy a TkScale structure. It's necessary to do this with
- * Tcl_EventuallyFree to allow the Tcl_Preserve(scalePtr) to work
- * as expected in TkpDisplayScale. (hobbs)
- *
- * Results:
- * None
- *
- * Side effects:
- * Memory is freed.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpDestroyScale(scalePtr)
- TkScale *scalePtr;
- {
- Tcl_EventuallyFree((ClientData) scalePtr, TCL_DYNAMIC);
- }
- /*
- *--------------------------------------------------------------
- *
- * DisplayVerticalScale --
- *
- * This procedure redraws the contents of a vertical scale
- * window. It is invoked as a do-when-idle handler, so it only
- * runs when there's nothing else for the application to do.
- *
- * Results:
- * There is no return value. If only a part of the scale needs
- * to be redrawn, then drawnAreaPtr is modified to reflect the
- * area that was actually modified.
- *
- * Side effects:
- * Information appears on the screen.
- *
- *--------------------------------------------------------------
- */
- static void
- DisplayVerticalScale(scalePtr, drawable, drawnAreaPtr)
- TkScale *scalePtr; /* Widget record for scale. */
- Drawable drawable; /* Where to display scale (window
- * or pixmap). */
- XRectangle *drawnAreaPtr; /* Initally contains area of window;
- * if only a part of the scale is
- * redrawn, gets modified to reflect
- * the part of the window that was
- * redrawn. */
- {
- Tk_Window tkwin = scalePtr->tkwin;
- int x, y, width, height, shadowWidth;
- double tickValue, tickInterval = scalePtr->tickInterval;
- Tk_3DBorder sliderBorder;
- /*
- * Display the information from left to right across the window.
- */
- if (!(scalePtr->flags & REDRAW_OTHER)) {
- drawnAreaPtr->x = scalePtr->vertTickRightX;
- drawnAreaPtr->y = scalePtr->inset;
- drawnAreaPtr->width = scalePtr->vertTroughX + scalePtr->width
- + 2*scalePtr->borderWidth - scalePtr->vertTickRightX;
- drawnAreaPtr->height -= 2*scalePtr->inset;
- }
- Tk_Fill3DRectangle(tkwin, drawable, scalePtr->bgBorder,
- drawnAreaPtr->x, drawnAreaPtr->y, drawnAreaPtr->width,
- drawnAreaPtr->height, 0, TK_RELIEF_FLAT);
- if (scalePtr->flags & REDRAW_OTHER) {
- /*
- * Display the tick marks.
- */
- if (tickInterval != 0) {
- double ticks, maxTicks;
- /*
- * Ensure that we will only draw enough of the tick values
- * such that they don't overlap
- */
- ticks = fabs((scalePtr->toValue - scalePtr->fromValue)
- / tickInterval);
- maxTicks = (double) Tk_Height(tkwin)
- / (double) scalePtr->fontHeight;
- if (ticks > maxTicks) {
- tickInterval *= (ticks / maxTicks);
- }
- for (tickValue = scalePtr->fromValue; ;
- tickValue += tickInterval) {
- /*
- * The TkRoundToResolution call gets rid of accumulated
- * round-off errors, if any.
- */
- tickValue = TkRoundToResolution(scalePtr, tickValue);
- if (scalePtr->toValue >= scalePtr->fromValue) {
- if (tickValue > scalePtr->toValue) {
- break;
- }
- } else {
- if (tickValue < scalePtr->toValue) {
- break;
- }
- }
- DisplayVerticalValue(scalePtr, drawable, tickValue,
- scalePtr->vertTickRightX);
- }
- }
- }
- /*
- * Display the value, if it is desired.
- */
- if (scalePtr->showValue) {
- DisplayVerticalValue(scalePtr, drawable, scalePtr->value,
- scalePtr->vertValueRightX);
- }
- /*
- * Display the trough and the slider.
- */
- Tk_Draw3DRectangle(tkwin, drawable,
- scalePtr->bgBorder, scalePtr->vertTroughX, scalePtr->inset,
- scalePtr->width + 2*scalePtr->borderWidth,
- Tk_Height(tkwin) - 2*scalePtr->inset, scalePtr->borderWidth,
- TK_RELIEF_SUNKEN);
- XFillRectangle(scalePtr->display, drawable, scalePtr->troughGC,
- scalePtr->vertTroughX + scalePtr->borderWidth,
- scalePtr->inset + scalePtr->borderWidth,
- (unsigned) scalePtr->width,
- (unsigned) (Tk_Height(tkwin) - 2*scalePtr->inset
- - 2*scalePtr->borderWidth));
- if (scalePtr->state == STATE_ACTIVE) {
- sliderBorder = scalePtr->activeBorder;
- } else {
- sliderBorder = scalePtr->bgBorder;
- }
- width = scalePtr->width;
- height = scalePtr->sliderLength/2;
- x = scalePtr->vertTroughX + scalePtr->borderWidth;
- y = TkScaleValueToPixel(scalePtr, scalePtr->value) - height;
- shadowWidth = scalePtr->borderWidth/2;
- if (shadowWidth == 0) {
- shadowWidth = 1;
- }
- Tk_Draw3DRectangle(tkwin, drawable, sliderBorder, x, y, width,
- 2*height, shadowWidth, scalePtr->sliderRelief);
- x += shadowWidth;
- y += shadowWidth;
- width -= 2*shadowWidth;
- height -= shadowWidth;
- Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y, width,
- height, shadowWidth, scalePtr->sliderRelief);
- Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y+height,
- width, height, shadowWidth, scalePtr->sliderRelief);
- /*
- * Draw the label to the right of the scale.
- */
- if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelLength != 0)) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(scalePtr->tkfont, &fm);
- Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
- scalePtr->tkfont, scalePtr->label,
- scalePtr->labelLength, scalePtr->vertLabelX,
- scalePtr->inset + (3*fm.ascent)/2);
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * DisplayVerticalValue --
- *
- * This procedure is called to display values (scale readings)
- * for vertically-oriented scales.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The numerical value corresponding to value is displayed with
- * its right edge at "rightEdge", and at a vertical position in
- * the scale that corresponds to "value".
- *
- *----------------------------------------------------------------------
- */
- static void
- DisplayVerticalValue(scalePtr, drawable, value, rightEdge)
- register TkScale *scalePtr; /* Information about widget in which to
- * display value. */
- Drawable drawable; /* Pixmap or window in which to draw
- * the value. */
- double value; /* Y-coordinate of number to display,
- * specified in application coords, not
- * in pixels (we'll compute pixels). */
- int rightEdge; /* X-coordinate of right edge of text,
- * specified in pixels. */
- {
- register Tk_Window tkwin = scalePtr->tkwin;
- int y, width, length;
- char valueString[PRINT_CHARS];
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(scalePtr->tkfont, &fm);
- y = TkScaleValueToPixel(scalePtr, value) + fm.ascent/2;
- sprintf(valueString, scalePtr->format, value);
- length = (int) strlen(valueString);
- width = Tk_TextWidth(scalePtr->tkfont, valueString, length);
- /*
- * Adjust the y-coordinate if necessary to keep the text entirely
- * inside the window.
- */
- if ((y - fm.ascent) < (scalePtr->inset + SPACING)) {
- y = scalePtr->inset + SPACING + fm.ascent;
- }
- if ((y + fm.descent) > (Tk_Height(tkwin) - scalePtr->inset - SPACING)) {
- y = Tk_Height(tkwin) - scalePtr->inset - SPACING - fm.descent;
- }
- Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
- scalePtr->tkfont, valueString, length, rightEdge - width, y);
- }
- /*
- *--------------------------------------------------------------
- *
- * DisplayHorizontalScale --
- *
- * This procedure redraws the contents of a horizontal scale
- * window. It is invoked as a do-when-idle handler, so it only
- * runs when there's nothing else for the application to do.
- *
- * Results:
- * There is no return value. If only a part of the scale needs
- * to be redrawn, then drawnAreaPtr is modified to reflect the
- * area that was actually modified.
- *
- * Side effects:
- * Information appears on the screen.
- *
- *--------------------------------------------------------------
- */
- static void
- DisplayHorizontalScale(scalePtr, drawable, drawnAreaPtr)
- TkScale *scalePtr; /* Widget record for scale. */
- Drawable drawable; /* Where to display scale (window
- * or pixmap). */
- XRectangle *drawnAreaPtr; /* Initally contains area of window;
- * if only a part of the scale is
- * redrawn, gets modified to reflect
- * the part of the window that was
- * redrawn. */
- {
- register Tk_Window tkwin = scalePtr->tkwin;
- int x, y, width, height, shadowWidth;
- double tickValue, tickInterval = scalePtr->tickInterval;
- Tk_3DBorder sliderBorder;
- /*
- * Display the information from bottom to top across the window.
- */
- if (!(scalePtr->flags & REDRAW_OTHER)) {
- drawnAreaPtr->x = scalePtr->inset;
- drawnAreaPtr->y = scalePtr->horizValueY;
- drawnAreaPtr->width -= 2*scalePtr->inset;
- drawnAreaPtr->height = scalePtr->horizTroughY + scalePtr->width
- + 2*scalePtr->borderWidth - scalePtr->horizValueY;
- }
- Tk_Fill3DRectangle(tkwin, drawable, scalePtr->bgBorder,
- drawnAreaPtr->x, drawnAreaPtr->y, drawnAreaPtr->width,
- drawnAreaPtr->height, 0, TK_RELIEF_FLAT);
- if (scalePtr->flags & REDRAW_OTHER) {
- /*
- * Display the tick marks.
- */
- if (tickInterval != 0) {
- char valueString[PRINT_CHARS];
- double ticks, maxTicks;
- /*
- * Ensure that we will only draw enough of the tick values
- * such that they don't overlap. We base this off the width that
- * fromValue would take. Not exact, but better than no constraint.
- */
- ticks = fabs((scalePtr->toValue - scalePtr->fromValue)
- / tickInterval);
- sprintf(valueString, scalePtr->format, scalePtr->fromValue);
- maxTicks = (double) Tk_Width(tkwin)
- / (double) Tk_TextWidth(scalePtr->tkfont, valueString, -1);
- if (ticks > maxTicks) {
- tickInterval *= (ticks / maxTicks);
- }
- for (tickValue = scalePtr->fromValue; ;
- tickValue += tickInterval) {
- /*
- * The TkRoundToResolution call gets rid of accumulated
- * round-off errors, if any.
- */
- tickValue = TkRoundToResolution(scalePtr, tickValue);
- if (scalePtr->toValue >= scalePtr->fromValue) {
- if (tickValue > scalePtr->toValue) {
- break;
- }
- } else {
- if (tickValue < scalePtr->toValue) {
- break;
- }
- }
- DisplayHorizontalValue(scalePtr, drawable, tickValue,
- scalePtr->horizTickY);
- }
- }
- }
- /*
- * Display the value, if it is desired.
- */
- if (scalePtr->showValue) {
- DisplayHorizontalValue(scalePtr, drawable, scalePtr->value,
- scalePtr->horizValueY);
- }
- /*
- * Display the trough and the slider.
- */
- y = scalePtr->horizTroughY;
- Tk_Draw3DRectangle(tkwin, drawable,
- scalePtr->bgBorder, scalePtr->inset, y,
- Tk_Width(tkwin) - 2*scalePtr->inset,
- scalePtr->width + 2*scalePtr->borderWidth,
- scalePtr->borderWidth, TK_RELIEF_SUNKEN);
- XFillRectangle(scalePtr->display, drawable, scalePtr->troughGC,
- scalePtr->inset + scalePtr->borderWidth,
- y + scalePtr->borderWidth,
- (unsigned) (Tk_Width(tkwin) - 2*scalePtr->inset
- - 2*scalePtr->borderWidth),
- (unsigned) scalePtr->width);
- if (scalePtr->state == STATE_ACTIVE) {
- sliderBorder = scalePtr->activeBorder;
- } else {
- sliderBorder = scalePtr->bgBorder;
- }
- width = scalePtr->sliderLength/2;
- height = scalePtr->width;
- x = TkScaleValueToPixel(scalePtr, scalePtr->value) - width;
- y += scalePtr->borderWidth;
- shadowWidth = scalePtr->borderWidth/2;
- if (shadowWidth == 0) {
- shadowWidth = 1;
- }
- Tk_Draw3DRectangle(tkwin, drawable, sliderBorder,
- x, y, 2*width, height, shadowWidth, scalePtr->sliderRelief);
- x += shadowWidth;
- y += shadowWidth;
- width -= shadowWidth;
- height -= 2*shadowWidth;
- Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x, y, width, height,
- shadowWidth, scalePtr->sliderRelief);
- Tk_Fill3DRectangle(tkwin, drawable, sliderBorder, x+width, y,
- width, height, shadowWidth, scalePtr->sliderRelief);
- /*
- * Draw the label at the top of the scale.
- */
- if ((scalePtr->flags & REDRAW_OTHER) && (scalePtr->labelLength != 0)) {
- Tk_FontMetrics fm;
- Tk_GetFontMetrics(scalePtr->tkfont, &fm);
- Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
- scalePtr->tkfont, scalePtr->label,
- scalePtr->labelLength, scalePtr->inset + fm.ascent/2,
- scalePtr->horizLabelY + fm.ascent);
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * DisplayHorizontalValue --
- *
- * This procedure is called to display values (scale readings)
- * for horizontally-oriented scales.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The numerical value corresponding to value is displayed with
- * its bottom edge at "bottom", and at a horizontal position in
- * the scale that corresponds to "value".
- *
- *----------------------------------------------------------------------
- */
- static void
- DisplayHorizontalValue(scalePtr, drawable, value, top)
- register TkScale *scalePtr; /* Information about widget in which to
- * display value. */
- Drawable drawable; /* Pixmap or window in which to draw
- * the value. */
- double value; /* X-coordinate of number to display,
- * specified in application coords, not
- * in pixels (we'll compute pixels). */
- int top; /* Y-coordinate of top edge of text,
- * specified in pixels. */
- {
- register Tk_Window tkwin = scalePtr->tkwin;
- int x, y, length, width;
- char valueString[PRINT_CHARS];
- Tk_FontMetrics fm;
- x = TkScaleValueToPixel(scalePtr, value);
- Tk_GetFontMetrics(scalePtr->tkfont, &fm);
- y = top + fm.ascent;
- sprintf(valueString, scalePtr->format, value);
- length = (int) strlen(valueString);
- width = Tk_TextWidth(scalePtr->tkfont, valueString, length);
- /*
- * Adjust the x-coordinate if necessary to keep the text entirely
- * inside the window.
- */
- x -= (width)/2;
- if (x < (scalePtr->inset + SPACING)) {
- x = scalePtr->inset + SPACING;
- }
- /*
- * Check the right border so use starting point +text width
- * for the check.
- */
- if (x + width >= (Tk_Width(tkwin) - scalePtr->inset)) {
- x = Tk_Width(tkwin) - scalePtr->inset - SPACING - width;
- }
- Tk_DrawChars(scalePtr->display, drawable, scalePtr->textGC,
- scalePtr->tkfont, valueString, length, x, y);
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpDisplayScale --
- *
- * This procedure is invoked as an idle handler to redisplay
- * the contents of a scale widget.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The scale gets redisplayed.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpDisplayScale(clientData)
- ClientData clientData; /* Widget record for scale. */
- {
- TkScale *scalePtr = (TkScale *) clientData;
- Tk_Window tkwin = scalePtr->tkwin;
- Tcl_Interp *interp = scalePtr->interp;
- Pixmap pixmap;
- int result;
- char string[PRINT_CHARS];
- XRectangle drawnArea;
- scalePtr->flags &= ~REDRAW_PENDING;
- if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) {
- goto done;
- }
- /*
- * Invoke the scale's command if needed.
- */
- Tcl_Preserve((ClientData) scalePtr);
- if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
- Tcl_Preserve((ClientData) interp);
- sprintf(string, scalePtr->format, scalePtr->value);
- result = Tcl_VarEval(interp, scalePtr->command, " ", string,
- (char *) NULL);
- if (result != TCL_OK) {
- Tcl_AddErrorInfo(interp, "n (command executed by scale)");
- Tcl_BackgroundError(interp);
- }
- Tcl_Release((ClientData) interp);
- }
- scalePtr->flags &= ~INVOKE_COMMAND;
- if (scalePtr->flags & SCALE_DELETED) {
- Tcl_Release((ClientData) scalePtr);
- return;
- }
- Tcl_Release((ClientData) scalePtr);
- #ifndef TK_NO_DOUBLE_BUFFERING
- /*
- * In order to avoid screen flashes, this procedure redraws
- * the scale in a pixmap, then copies the pixmap to the
- * screen in a single operation. This means that there's no
- * point in time where the on-sreen image has been cleared.
- */
- pixmap = Tk_GetPixmap(scalePtr->display, Tk_WindowId(tkwin),
- Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
- #else
- pixmap = Tk_WindowId(tkwin);
- #endif /* TK_NO_DOUBLE_BUFFERING */
- drawnArea.x = 0;
- drawnArea.y = 0;
- drawnArea.width = Tk_Width(tkwin);
- drawnArea.height = Tk_Height(tkwin);
- /*
- * Much of the redisplay is done totally differently for
- * horizontal and vertical scales. Handle the part that's
- * different.
- */
- if (scalePtr->orient == ORIENT_VERTICAL) {
- DisplayVerticalScale(scalePtr, pixmap, &drawnArea);
- } else {
- DisplayHorizontalScale(scalePtr, pixmap, &drawnArea);
- }
- /*
- * Now handle the part of redisplay that is the same for
- * horizontal and vertical scales: border and traversal
- * highlight.
- */
- if (scalePtr->flags & REDRAW_OTHER) {
- if (scalePtr->relief != TK_RELIEF_FLAT) {
- Tk_Draw3DRectangle(tkwin, pixmap, scalePtr->bgBorder,
- scalePtr->highlightWidth, scalePtr->highlightWidth,
- Tk_Width(tkwin) - 2*scalePtr->highlightWidth,
- Tk_Height(tkwin) - 2*scalePtr->highlightWidth,
- scalePtr->borderWidth, scalePtr->relief);
- }
- if (scalePtr->highlightWidth != 0) {
- GC gc;
-
- if (scalePtr->flags & GOT_FOCUS) {
- gc = Tk_GCForColor(scalePtr->highlightColorPtr, pixmap);
- } else {
- gc = Tk_GCForColor(
- Tk_3DBorderColor(scalePtr->highlightBorder), pixmap);
- }
- Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, pixmap);
- }
- }
- #ifndef TK_NO_DOUBLE_BUFFERING
- /*
- * Copy the information from the off-screen pixmap onto the screen,
- * then delete the pixmap.
- */
- XCopyArea(scalePtr->display, pixmap, Tk_WindowId(tkwin),
- scalePtr->copyGC, drawnArea.x, drawnArea.y, drawnArea.width,
- drawnArea.height, drawnArea.x, drawnArea.y);
- Tk_FreePixmap(scalePtr->display, pixmap);
- #endif /* TK_NO_DOUBLE_BUFFERING */
- done:
- scalePtr->flags &= ~REDRAW_ALL;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpScaleElement --
- *
- * Determine which part of a scale widget lies under a given
- * point.
- *
- * Results:
- * The return value is either TROUGH1, SLIDER, TROUGH2, or
- * OTHER, depending on which of the scale's active elements
- * (if any) is under the point at (x,y).
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- TkpScaleElement(scalePtr, x, y)
- TkScale *scalePtr; /* Widget record for scale. */
- int x, y; /* Coordinates within scalePtr's window. */
- {
- int sliderFirst;
- if (scalePtr->orient == ORIENT_VERTICAL) {
- if ((x < scalePtr->vertTroughX)
- || (x >= (scalePtr->vertTroughX + 2*scalePtr->borderWidth +
- scalePtr->width))) {
- return OTHER;
- }
- if ((y < scalePtr->inset)
- || (y >= (Tk_Height(scalePtr->tkwin) - scalePtr->inset))) {
- return OTHER;
- }
- sliderFirst = TkScaleValueToPixel(scalePtr, scalePtr->value)
- - scalePtr->sliderLength/2;
- if (y < sliderFirst) {
- return TROUGH1;
- }
- if (y < (sliderFirst+scalePtr->sliderLength)) {
- return SLIDER;
- }
- return TROUGH2;
- }
- if ((y < scalePtr->horizTroughY)
- || (y >= (scalePtr->horizTroughY + 2*scalePtr->borderWidth +
- scalePtr->width))) {
- return OTHER;
- }
- if ((x < scalePtr->inset)
- || (x >= (Tk_Width(scalePtr->tkwin) - scalePtr->inset))) {
- return OTHER;
- }
- sliderFirst = TkScaleValueToPixel(scalePtr, scalePtr->value)
- - scalePtr->sliderLength/2;
- if (x < sliderFirst) {
- return TROUGH1;
- }
- if (x < (sliderFirst+scalePtr->sliderLength)) {
- return SLIDER;
- }
- return TROUGH2;
- }