From 6f3fdbf13c1ca71c85990b58d86b6e06fdba9a0f Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Sun, 25 Aug 2024 04:42:51 +0800 Subject: [PATCH] Graph meter dynamic scaling Signed-off-by: Kang-Che Sung --- Meter.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/Meter.c b/Meter.c index a3d3596ebc..584c081458 100644 --- a/Meter.c +++ b/Meter.c @@ -206,12 +206,36 @@ static const char* const GraphMeterMode_dotsAscii[] = { /*20*/":", /*21*/":", /*22*/":" }; +static void GraphMeterMode_printScale(int exponent) { + if (exponent < 10) { + // "1" to "512"; the (exponent < 0) case is not implemented. + assert(exponent >= 0); + printw("%3u", 1U << exponent); + } else if (exponent > (int)ARRAYSIZE(unitPrefixes) * 10 + 6) { + addstr("inf"); + } else if (exponent % 10 < 7) { + // "1K" to "64K", "1M" to "64M", "1G" to "64G", etc. + printw("%2u%c", 1U << (exponent % 10), unitPrefixes[exponent / 10 - 1]); + } else { + // "M/8" (=128K), "M/4" (=256K), "M/2" (=512K), "G/8" (=128M), etc. + printw("%c/%u", unitPrefixes[exponent / 10], 1U << (10 - exponent % 10)); + } +} + static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { // Draw the caption const char* caption = Meter_getCaption(this); attrset(CRT_colors[METER_TEXT]); const int captionLen = 3; mvaddnstr(y, x, caption, captionLen); + + // Prepare parameters for drawing + uint8_t maxItems = Meter_maxItems(this); + bool isPercentChart = Meter_isPercentChart(this); + bool needsScaleDisplay = maxItems > 0 && GRAPH_HEIGHT >= 2; + if (needsScaleDisplay) { + move(y + 1, x); // Cursor position for printing the scale + } x += captionLen; w -= captionLen; @@ -243,8 +267,10 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { data->values[nValues - 1] = 0.0; if (this->curItems > 0) { - assert(this->values); - data->values[nValues - 1] = sumPositiveValues(this->values, this->curItems); + data->values[nValues - 1] = Meter_computeSum(this); + if (isPercentChart && this->total > 0.0) { + data->values[nValues - 1] /= this->total; + } } } @@ -272,10 +298,38 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { } size_t i = nValues - (size_t)w * 2; + // Determine and print the graph scale + double total = 1.0; + int scaleExp = 0; + if (maxItems > 0 && !isPercentChart) { + total = 0.0; + for (size_t j = i; j < nValues; j++) { + if (total < data->values[j]) { + total = data->values[j]; + } + } + assert(total <= DBL_MAX); + (void)frexp(total, &scaleExp); + if (scaleExp < 0) { + scaleExp = 0; + } + total = ldexp(1.0, scaleExp); + if (total > DBL_MAX) { + total = DBL_MAX; + } + } + assert(total >= 1.0); + if (needsScaleDisplay) { + if (isPercentChart) { + addstr(" %"); + } else { + GraphMeterMode_printScale(scaleExp); + } + } + // Draw the actual graph for (int col = 0; i < nValues - 1; i += 2, col++) { int pix = GraphMeterMode_pixPerRow * GRAPH_HEIGHT; - double total = MAXIMUM(this->total, 1); int v1 = (int) lround(CLAMP(data->values[i] / total * pix, 1.0, pix)); int v2 = (int) lround(CLAMP(data->values[i + 1] / total * pix, 1.0, pix));