📄 tkscale.c
字号:
if (afterDecimal > 0) { fDigits++; /* Decimal point. */ } if (mostSigDigit < 0) { fDigits++; /* Zero to left of decimal point. */ } if (fDigits <= eDigits) { sprintf(scalePtr->format, "%%.%df", afterDecimal); } else { sprintf(scalePtr->format, "%%.%de", numDigits-1); }}/* *---------------------------------------------------------------------- * * ComputeScaleGeometry -- * * This procedure is called to compute various geometrical * information for a scale, such as where various things get * displayed. It's called when the window is reconfigured. * * Results: * None. * * Side effects: * Display-related numbers get changed in *scalePtr. The * geometry manager gets told about the window's preferred size. * *---------------------------------------------------------------------- */static voidComputeScaleGeometry(scalePtr) register TkScale *scalePtr; /* Information about widget. */{ char valueString[PRINT_CHARS]; int tmp, valuePixels, x, y, extraSpace; Tk_FontMetrics fm; /* * Horizontal scales are simpler than vertical ones because * all sizes are the same (the height of a line of text); * handle them first and then quit. */ Tk_GetFontMetrics(scalePtr->tkfont, &fm); if (!scalePtr->vertical) { y = scalePtr->inset; extraSpace = 0; if (scalePtr->labelLength != 0) { scalePtr->horizLabelY = y + SPACING; y += fm.linespace + SPACING; extraSpace = SPACING; } if (scalePtr->showValue) { scalePtr->horizValueY = y + SPACING; y += fm.linespace + SPACING; extraSpace = SPACING; } else { scalePtr->horizValueY = y; } y += extraSpace; scalePtr->horizTroughY = y; y += scalePtr->width + 2*scalePtr->borderWidth; if (scalePtr->tickInterval != 0) { scalePtr->horizTickY = y + SPACING; y += fm.linespace + 2*SPACING; } Tk_GeometryRequest(scalePtr->tkwin, scalePtr->length + 2*scalePtr->inset, y + scalePtr->inset); Tk_SetInternalBorder(scalePtr->tkwin, scalePtr->inset); return; } /* * Vertical scale: compute the amount of space needed to display * the scales value by formatting strings for the two end points; * use whichever length is longer. */ sprintf(valueString, scalePtr->format, scalePtr->fromValue); valuePixels = Tk_TextWidth(scalePtr->tkfont, valueString, -1); sprintf(valueString, scalePtr->format, scalePtr->toValue); tmp = Tk_TextWidth(scalePtr->tkfont, valueString, -1); if (valuePixels < tmp) { valuePixels = tmp; } /* * Assign x-locations to the elements of the scale, working from * left to right. */ x = scalePtr->inset; if ((scalePtr->tickInterval != 0) && (scalePtr->showValue)) { scalePtr->vertTickRightX = x + SPACING + valuePixels; scalePtr->vertValueRightX = scalePtr->vertTickRightX + valuePixels + fm.ascent/2; x = scalePtr->vertValueRightX + SPACING; } else if (scalePtr->tickInterval != 0) { scalePtr->vertTickRightX = x + SPACING + valuePixels; scalePtr->vertValueRightX = scalePtr->vertTickRightX; x = scalePtr->vertTickRightX + SPACING; } else if (scalePtr->showValue) { scalePtr->vertTickRightX = x; scalePtr->vertValueRightX = x + SPACING + valuePixels; x = scalePtr->vertValueRightX + SPACING; } else { scalePtr->vertTickRightX = x; scalePtr->vertValueRightX = x; } scalePtr->vertTroughX = x; x += 2*scalePtr->borderWidth + scalePtr->width; if (scalePtr->labelLength == 0) { scalePtr->vertLabelX = 0; } else { scalePtr->vertLabelX = x + fm.ascent/2; x = scalePtr->vertLabelX + fm.ascent/2 + Tk_TextWidth(scalePtr->tkfont, scalePtr->label, scalePtr->labelLength); } Tk_GeometryRequest(scalePtr->tkwin, x + scalePtr->inset, scalePtr->length + 2*scalePtr->inset); Tk_SetInternalBorder(scalePtr->tkwin, scalePtr->inset);}/* *-------------------------------------------------------------- * * ScaleEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on scales. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */static voidScaleEventProc(clientData, eventPtr) ClientData clientData; /* Information about window. */ XEvent *eventPtr; /* Information about event. */{ TkScale *scalePtr = (TkScale *) clientData; if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); } else if (eventPtr->type == DestroyNotify) { if (scalePtr->tkwin != NULL) { scalePtr->tkwin = NULL; Tcl_DeleteCommandFromToken(scalePtr->interp, scalePtr->widgetCmd); } if (scalePtr->flags & REDRAW_ALL) { Tcl_CancelIdleCall(TkpDisplayScale, (ClientData) scalePtr); } Tcl_EventuallyFree((ClientData) scalePtr, DestroyScale); } else if (eventPtr->type == ConfigureNotify) { ComputeScaleGeometry(scalePtr); TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); } else if (eventPtr->type == FocusIn) { if (eventPtr->xfocus.detail != NotifyInferior) { scalePtr->flags |= GOT_FOCUS; if (scalePtr->highlightWidth > 0) { TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); } } } else if (eventPtr->type == FocusOut) { if (eventPtr->xfocus.detail != NotifyInferior) { scalePtr->flags &= ~GOT_FOCUS; if (scalePtr->highlightWidth > 0) { TkEventuallyRedrawScale(scalePtr, REDRAW_ALL); } } }}/* *---------------------------------------------------------------------- * * ScaleCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */static voidScaleCmdDeletedProc(clientData) ClientData clientData; /* Pointer to widget record for widget. */{ TkScale *scalePtr = (TkScale *) clientData; Tk_Window tkwin = scalePtr->tkwin; /* * This procedure could be invoked either because the window was * destroyed and the command was then deleted (in which case tkwin * is NULL) or because the command was deleted, and then this procedure * destroys the widget. */ if (tkwin != NULL) { scalePtr->tkwin = NULL; Tk_DestroyWindow(tkwin); }}/* *-------------------------------------------------------------- * * TkEventuallyRedrawScale -- * * Arrange for part or all of a scale widget to redrawn at * the next convenient time in the future. * * Results: * None. * * Side effects: * If "what" is REDRAW_SLIDER then just the slider and the * value readout will be redrawn; if "what" is REDRAW_ALL * then the entire widget will be redrawn. * *-------------------------------------------------------------- */voidTkEventuallyRedrawScale(scalePtr, what) register TkScale *scalePtr; /* Information about widget. */ int what; /* What to redraw: REDRAW_SLIDER * or REDRAW_ALL. */{ if ((what == 0) || (scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) { return; } if ((scalePtr->flags & REDRAW_ALL) == 0) { Tcl_DoWhenIdle(TkpDisplayScale, (ClientData) scalePtr); } scalePtr->flags |= what;}/* *-------------------------------------------------------------- * * TkRoundToResolution -- * * Round a given floating-point value to the nearest multiple * of the scale's resolution. * * Results: * The return value is the rounded result. * * Side effects: * None. * *-------------------------------------------------------------- */doubleTkRoundToResolution(scalePtr, value) TkScale *scalePtr; /* Information about scale widget. */ double value; /* Value to round. */{ double rem, new; if (scalePtr->resolution <= 0) { return value; } new = scalePtr->resolution * floor(value/scalePtr->resolution); rem = value - new; if (rem < 0) { if (rem <= -scalePtr->resolution/2) { new -= scalePtr->resolution; } } else { if (rem >= scalePtr->resolution/2) { new += scalePtr->resolution; } } return new;}/* *---------------------------------------------------------------------- * * ScaleVarProc -- * * This procedure is invoked by Tcl whenever someone modifies a * variable associated with a scale widget. * * Results: * NULL is always returned. * * Side effects: * The value displayed in the scale will change to match the * variable's new value. If the variable has a bogus value then * it is reset to the value of the scale. * *---------------------------------------------------------------------- */ /* ARGSUSED */static char *ScaleVarProc(clientData, interp, name1, name2, flags) ClientData clientData; /* Information about button. */ Tcl_Interp *interp; /* Interpreter containing variable. */ char *name1; /* Name of variable. */ char *name2; /* Second part of variable name. */ int flags; /* Information about what happened. */{ register TkScale *scalePtr = (TkScale *) clientData; char *stringValue, *end, *result; double value; /* * If the variable is unset, then immediately recreate it unless * the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { Tcl_TraceVar(interp, scalePtr->varName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, ScaleVarProc, clientData); scalePtr->flags |= NEVER_SET; TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); } return (char *) NULL; } /* * If we came here because we updated the variable (in TkpSetScaleValue), * then ignore the trace. Otherwise update the scale with the value * of the variable. */ if (scalePtr->flags & SETTING_VAR) { return (char *) NULL; } result = NULL; stringValue = Tcl_GetVar(interp, scalePtr->varName, TCL_GLOBAL_ONLY); if (stringValue != NULL) { value = strtod(stringValue, &end); if ((end == stringValue) || (*end != 0)) { result = "can't assign non-numeric value to scale variable"; } else { scalePtr->value = TkRoundToResolution(scalePtr, value); } /* * This code is a bit tricky because it sets the scale's value before * calling TkpSetScaleValue. This way, TkpSetScaleValue won't bother * to set the variable again or to invoke the -command. However, it * also won't redisplay the scale, so we have to ask for that * explicitly. */ TkpSetScaleValue(scalePtr, scalePtr->value, 1, 0); TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -