From 31b66a6295cd71b19bc085fd8c1b6b660c327ad3 Mon Sep 17 00:00:00 2001 From: jal_frezie Date: Wed, 20 Feb 2019 11:51:53 +0000 Subject: Eliminate trailing zeros from scale tick values. This is done by calculating a separate format string for these values, rather than using the same format string as for the current value. The basis is the same, i.e., enough digits are displayed to distinguish any pair of adjacent tick values, and all tick values have the same number of decimals so some may still have trailing zeros. Code for laying out vertical scales has been adjusted to take account of the fact that the tick column may now be narrower than the value column. --- generic/tkScale.c | 148 ++++++++++++++++++++++++++++++++++------------------- generic/tkScale.h | 4 +- unix/tkUnixScale.c | 28 +++++----- 3 files changed, 114 insertions(+), 66 deletions(-) diff --git a/generic/tkScale.c b/generic/tkScale.c index 29f8722..455c656 100644 --- a/generic/tkScale.c +++ b/generic/tkScale.c @@ -157,7 +157,7 @@ enum command { * Forward declarations for procedures defined later in this file: */ -static void ComputeFormat(TkScale *scalePtr); +static void ComputeFormat(TkScale *scalePtr, int forTicks); static void ComputeScaleGeometry(TkScale *scalePtr); static int ConfigureScale(Tcl_Interp *interp, TkScale *scalePtr, int objc, Tcl_Obj *const objv[]); @@ -430,7 +430,7 @@ ScaleWidgetObjCmd( } value = TkScalePixelToValue(scalePtr, x, y); } - Tcl_SetObjResult(interp, Tcl_ObjPrintf(scalePtr->format, value)); + Tcl_SetObjResult(interp, Tcl_ObjPrintf(scalePtr->valueFormat, value)); break; } case COMMAND_IDENTIFY: { @@ -636,7 +636,8 @@ ConfigureScale( scalePtr->tickInterval = -scalePtr->tickInterval; } - ComputeFormat(scalePtr); + ComputeFormat(scalePtr, 0); + ComputeFormat(scalePtr, 1); scalePtr->labelLength = scalePtr->label ? (int)strlen(scalePtr->label) : 0; @@ -764,22 +765,22 @@ ScaleWorldChanged( * * ComputeFormat -- * - * This procedure is invoked to recompute the "format" field of a scale's - * widget record, which determines how the value of the scale is - * converted to a string. + * This procedure is invoked to recompute the "valueFormat" or + * "tickFormat" field of a scale's widget record, which determines how + * the value of the scale or one of its ticks is converted to a string. * * Results: * None. * - * Side effects: - * The format field of scalePtr is modified. + * Side effects: The valueFormat or tickFormat field of scalePtr is modified. * *---------------------------------------------------------------------- */ static void ComputeFormat( - TkScale *scalePtr) /* Information about scale widget. */ + TkScale *scalePtr, /* Information about scale widget. */ + int forTicks) /* Do for ticks rather than value */ { double maxValue, x; int mostSigDigit, numDigits, leastSigDigit, afterDecimal; @@ -800,46 +801,60 @@ ComputeFormat( } mostSigDigit = (int) floor(log10(maxValue)); - /* - * If the number of significant digits wasn't specified explicitly, - * compute it. It's the difference between the most significant digit - * needed to represent any number on the scale and the most significant - * digit of the smallest difference between numbers on the scale. In other - * words, display enough digits so that at least one digit will be - * different between any two adjacent positions of the scale. - */ - - numDigits = scalePtr->digits; - if (numDigits > TCL_MAX_PREC) { - numDigits = 0; - } - if (numDigits <= 0) { - if (scalePtr->resolution > 0) { - /* - * A resolution was specified for the scale, so just use it. - */ + if (forTicks) { + /* + * Display only enough digits to ensure adjacent ticks have different + * values + */ - leastSigDigit = (int) floor(log10(scalePtr->resolution)); + if (scalePtr->tickInterval > 0) { + numDigits = 1 + mostSigDigit - (int) floor(log10(scalePtr->tickInterval)); } else { - /* - * No resolution was specified, so compute the difference in value - * between adjacent pixels and use it for the least significant - * digit. - */ + numDigits = 1; + } + } else { + /* + * If the number of significant digits wasn't specified explicitly, + * compute it. It's the difference between the most significant digit + * needed to represent any number on the scale and the most + * significant digit of the smallest difference between numbers on the + * scale. In other words, display enough digits so that at least one + * digit will be different between any two adjacent positions of the + * scale. + */ - x = fabs(scalePtr->fromValue - scalePtr->toValue); - if (scalePtr->length > 0) { - x /= scalePtr->length; - } - if (x > 0){ - leastSigDigit = (int) floor(log10(x)); + numDigits = scalePtr->digits; + if (numDigits > TCL_MAX_PREC) { + numDigits = 0; + } + if (numDigits <= 0) { + if (scalePtr->resolution > 0) { + /* + * A resolution was specified for the scale, so just use it. + */ + + leastSigDigit = (int) floor(log10(scalePtr->resolution)); } else { - leastSigDigit = 0; + /* + * No resolution was specified, so compute the difference in + * value between adjacent pixels and use it for the least + * significant digit. + */ + + x = fabs(scalePtr->fromValue - scalePtr->toValue); + if (scalePtr->length > 0) { + x /= scalePtr->length; + } + if (x > 0){ + leastSigDigit = (int) floor(log10(x)); + } else { + leastSigDigit = 0; + } + } + numDigits = mostSigDigit - leastSigDigit + 1; + if (numDigits < 1) { + numDigits = 1; } - } - numDigits = mostSigDigit - leastSigDigit + 1; - if (numDigits < 1) { - numDigits = 1; } } @@ -863,10 +878,18 @@ ComputeFormat( if (mostSigDigit < 0) { fDigits++; /* Zero to left of decimal point. */ } - if (fDigits <= eDigits) { - sprintf(scalePtr->format, "%%.%df", afterDecimal); + if (forTicks) { + if (fDigits <= eDigits) { + sprintf(scalePtr->tickFormat, "%%.%df", afterDecimal); + } else { + sprintf(scalePtr->tickFormat, "%%.%de", numDigits-1); + } } else { - sprintf(scalePtr->format, "%%.%de", numDigits-1); + if (fDigits <= eDigits) { + sprintf(scalePtr->valueFormat, "%%.%df", afterDecimal); + } else { + sprintf(scalePtr->valueFormat, "%%.%de", numDigits-1); + } } } @@ -894,7 +917,7 @@ ComputeScaleGeometry( register TkScale *scalePtr) /* Information about widget. */ { char valueString[TCL_DOUBLE_SPACE]; - int tmp, valuePixels, x, y, extraSpace; + int tmp, valuePixels, tickPixels, x, y, extraSpace; Tk_FontMetrics fm; Tk_GetFontMetrics(scalePtr->tkfont, &fm); @@ -940,13 +963,13 @@ ComputeScaleGeometry( * whichever length is longer. */ - if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->format, + if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->valueFormat, scalePtr->fromValue) < 0) { valueString[TCL_DOUBLE_SPACE - 1] = '\0'; } valuePixels = Tk_TextWidth(scalePtr->tkfont, valueString, -1); - if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->format, + if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->valueFormat, scalePtr->toValue) < 0) { valueString[TCL_DOUBLE_SPACE - 1] = '\0'; } @@ -956,18 +979,37 @@ ComputeScaleGeometry( } /* + * Now do the same thing for the tick values + */ + + if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->tickFormat, + scalePtr->fromValue) < 0) { + valueString[TCL_DOUBLE_SPACE - 1] = '\0'; + } + tickPixels = Tk_TextWidth(scalePtr->tkfont, valueString, -1); + + if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->tickFormat, + scalePtr->toValue) < 0) { + valueString[TCL_DOUBLE_SPACE - 1] = '\0'; + } + tmp = Tk_TextWidth(scalePtr->tkfont, valueString, -1); + if (tickPixels < tmp) { + tickPixels = 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->vertTickRightX = x + SPACING + tickPixels; scalePtr->vertValueRightX = scalePtr->vertTickRightX + valuePixels + fm.ascent/2; x = scalePtr->vertValueRightX + SPACING; } else if (scalePtr->tickInterval != 0) { - scalePtr->vertTickRightX = x + SPACING + valuePixels; + scalePtr->vertTickRightX = x + SPACING + tickPixels; scalePtr->vertValueRightX = scalePtr->vertTickRightX; x = scalePtr->vertTickRightX + SPACING; } else if (scalePtr->showValue) { @@ -1350,7 +1392,7 @@ ScaleSetVariable( if (scalePtr->varNamePtr != NULL) { char string[TCL_DOUBLE_SPACE]; - if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format, + if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->valueFormat, scalePtr->value) < 0) { string[TCL_DOUBLE_SPACE - 1] = '\0'; } diff --git a/generic/tkScale.h b/generic/tkScale.h index d44e65b..4250b06 100644 --- a/generic/tkScale.h +++ b/generic/tkScale.h @@ -73,8 +73,10 @@ typedef struct TkScale { * values. 0 means we get to choose the number * based on resolution and/or the range of the * scale. */ - char format[16]; /* Sprintf conversion specifier computed from + char valueFormat[16]; /* Sprintf conversion specifier computed from * digits and other information. */ + char tickFormat[16]; /* Sprintf conversion specifier computed from + * tick interval. */ double bigIncrement; /* Amount to use for large increments to scale * value. (0 means we pick a value). */ char *command; /* Command prefix to use when invoking Tcl diff --git a/unix/tkUnixScale.c b/unix/tkUnixScale.c index 2009288..f5e3fc2 100644 --- a/unix/tkUnixScale.c +++ b/unix/tkUnixScale.c @@ -24,11 +24,13 @@ static void DisplayHorizontalScale(TkScale *scalePtr, Drawable drawable, XRectangle *drawnAreaPtr); static void DisplayHorizontalValue(TkScale *scalePtr, - Drawable drawable, double value, int top); + Drawable drawable, double value, + int top, char* format); static void DisplayVerticalScale(TkScale *scalePtr, Drawable drawable, XRectangle *drawnAreaPtr); static void DisplayVerticalValue(TkScale *scalePtr, - Drawable drawable, double value, int rightEdge); + Drawable drawable, double value, + int rightEdge, char* format); /* *---------------------------------------------------------------------- @@ -165,7 +167,7 @@ DisplayVerticalScale( } } DisplayVerticalValue(scalePtr, drawable, tickValue, - scalePtr->vertTickRightX); + scalePtr->vertTickRightX, scalePtr->tickFormat); } } } @@ -176,7 +178,7 @@ DisplayVerticalScale( if (scalePtr->showValue) { DisplayVerticalValue(scalePtr, drawable, scalePtr->value, - scalePtr->vertValueRightX); + scalePtr->vertValueRightX, scalePtr->valueFormat); } /* @@ -261,8 +263,9 @@ DisplayVerticalValue( 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, + int rightEdge, /* X-coordinate of right edge of text, * specified in pixels. */ + char* format) /* Format string to use for the value */ { register Tk_Window tkwin = scalePtr->tkwin; int y, width, length; @@ -271,7 +274,7 @@ DisplayVerticalValue( Tk_GetFontMetrics(scalePtr->tkfont, &fm); y = TkScaleValueToPixel(scalePtr, value) + fm.ascent/2; - if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->format, value) < 0) { + if (snprintf(valueString, TCL_DOUBLE_SPACE, format, value) < 0) { valueString[TCL_DOUBLE_SPACE - 1] = '\0'; } length = (int) strlen(valueString); @@ -358,7 +361,7 @@ DisplayHorizontalScale( ticks = fabs((scalePtr->toValue - scalePtr->fromValue) / tickInterval); - if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->format, + if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->tickFormat, scalePtr->fromValue) < 0) { valueString[TCL_DOUBLE_SPACE - 1] = '\0'; } @@ -385,7 +388,7 @@ DisplayHorizontalScale( } } DisplayHorizontalValue(scalePtr, drawable, tickValue, - scalePtr->horizTickY); + scalePtr->horizTickY, scalePtr->tickFormat); } } } @@ -396,7 +399,7 @@ DisplayHorizontalScale( if (scalePtr->showValue) { DisplayHorizontalValue(scalePtr, drawable, scalePtr->value, - scalePtr->horizValueY); + scalePtr->horizValueY, scalePtr->valueFormat); } /* @@ -482,8 +485,9 @@ DisplayHorizontalValue( 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 + int top, /* Y-coordinate of top edge of text, specified * in pixels. */ + char* format) /* Format string to use for the value */ { register Tk_Window tkwin = scalePtr->tkwin; int x, y, length, width; @@ -493,7 +497,7 @@ DisplayHorizontalValue( x = TkScaleValueToPixel(scalePtr, value); Tk_GetFontMetrics(scalePtr->tkfont, &fm); y = top + fm.ascent; - if (snprintf(valueString, TCL_DOUBLE_SPACE, scalePtr->format, value) < 0) { + if (snprintf(valueString, TCL_DOUBLE_SPACE, format, value) < 0) { valueString[TCL_DOUBLE_SPACE - 1] = '\0'; } length = (int) strlen(valueString); @@ -562,7 +566,7 @@ TkpDisplayScale( Tcl_Preserve(scalePtr); if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) { Tcl_Preserve(interp); - if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->format, + if (snprintf(string, TCL_DOUBLE_SPACE, scalePtr->valueFormat, scalePtr->value) < 0) { string[TCL_DOUBLE_SPACE - 1] = '\0'; } -- cgit v0.12