diff --git a/DiskIOMeter.c b/DiskIOMeter.c index 4bb689fac..8a2dd14d5 100644 --- a/DiskIOMeter.c +++ b/DiskIOMeter.c @@ -72,6 +72,7 @@ static void DiskIOMeter_updateValues(Meter* this) { } else { diff = 0; } + this->values[1] = diff; Meter_humanUnit(cached_read_diff_str, diff, sizeof(cached_read_diff_str)); if (data.totalBytesWritten > cached_write_total) { @@ -81,6 +82,7 @@ static void DiskIOMeter_updateValues(Meter* this) { } else { diff = 0; } + this->values[2] = diff; Meter_humanUnit(cached_write_diff_str, diff, sizeof(cached_write_diff_str)); cached_utilisation_diff = 0.0; @@ -156,8 +158,13 @@ const MeterClass DiskIOMeter_class = { }, .updateValues = DiskIOMeter_updateValues, .defaultMode = TEXT_METERMODE, - .supportedModes = METERMODE_DEFAULT_SUPPORTED, - .maxItems = 1, + .supportedModes = + (1 << BAR_METERMODE) | + (1 << TEXT_METERMODE) | + (1 << GRAPH_METERMODE) | + (1 << LED_METERMODE) | + (1 << BIPOLAR_METERMODE), + .maxItems = 3, .total = 1.0, .attributes = DiskIOMeter_attributes, .name = "DiskIO", diff --git a/Meter.c b/Meter.c index 59031d54c..d5ad831b9 100644 --- a/Meter.c +++ b/Meter.c @@ -185,7 +185,7 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { #ifdef HAVE_LIBNCURSESW #define PIXPERROW_UTF8 4 -static const char* const GraphMeterMode_dotsUtf8[] = { +static const char* const GraphMeterMode_top_dotsUtf8[] = { /*00*/" ", /*01*/"⢀", /*02*/"⢠", /*03*/"⢰", /*04*/ "⢸", /*10*/"⡀", /*11*/"⣀", /*12*/"⣠", /*13*/"⣰", /*14*/ "⣸", /*20*/"⡄", /*21*/"⣄", /*22*/"⣤", /*23*/"⣴", /*24*/ "⣼", @@ -193,32 +193,45 @@ static const char* const GraphMeterMode_dotsUtf8[] = { /*40*/"⡇", /*41*/"⣇", /*42*/"⣧", /*43*/"⣷", /*44*/ "⣿" }; +static const char* const GraphMeterMode_bottom_dotsUtf8[] = { + /*00*/" ", /*01*/"⠈", /*02*/"⠘", /*03*/"⠸", /*04*/ "⢸", + /*10*/"⠁", /*11*/"⠉", /*12*/"⠙", /*13*/"⠹", /*14*/ "⢹", + /*20*/"⠃", /*21*/"⠋", /*22*/"⠛", /*23*/"⠻", /*24*/ "⢻", + /*30*/"⠇", /*31*/"⠏", /*32*/"⠟", /*33*/"⠿", /*34*/ "⢿", + /*40*/"⡇", /*41*/"⡏", /*42*/"⡟", /*43*/"⡿", /*44*/ "⣿" +}; + +static const char* const* const GraphMeterMode_dotsUtf8[2] = { + GraphMeterMode_top_dotsUtf8, + GraphMeterMode_bottom_dotsUtf8 +}; #endif #define PIXPERROW_ASCII 2 -static const char* const GraphMeterMode_dotsAscii[] = { +static const char* const GraphMeterMode_top_dotsAscii[] = { /*00*/" ", /*01*/".", /*02*/":", /*10*/".", /*11*/".", /*12*/":", /*20*/":", /*21*/":", /*22*/":" }; -static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { - assert(x >= 0); - assert(w <= INT_MAX - x); +static const char* const GraphMeterMode_bottom_dotsAscii[] = { + /*00*/" ", /*01*/"'", /*02*/":", + /*10*/"'", /*11*/"'", /*12*/":", + /*20*/":", /*21*/":", /*22*/":" +}; - // Draw the caption - const int captionLen = 3; - const char* caption = Meter_getCaption(this); - if (w >= captionLen) { - attrset(CRT_colors[METER_TEXT]); - mvaddnstr(y, x, caption, captionLen); - } - w -= captionLen; +static const char* const* const GraphMeterMode_dotsAscii[2] = { + GraphMeterMode_top_dotsAscii, + GraphMeterMode_bottom_dotsAscii +}; - assert(this->h >= 1); - int h = this->h; +static void GraphMeterMode_drawGraph(Meter* this, int x, int y, int w, int h, int channel) { + assert(x >= 0); + assert(y >= 0); + assert(w > 0 && w <= INT_MAX - x); + assert(h > 0 && h <= INT_MAX - y); - GraphData* data = &this->drawData; + GraphData* data = &this->drawData[channel+1]; // Expand the graph data buffer if necessary assert(data->nValues / 2 <= INT_MAX); @@ -247,28 +260,35 @@ 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); + if (channel < 0) { + data->values[nValues - 1] = sumPositiveValues(this->values, this->curItems); + } else { + assert(this->curItems > channel); + data->values[nValues - 1] = this->values[channel]; + } } } if (w < 1) { goto end; } - x += captionLen; // Graph drawing style (character set, etc.) - const char* const* GraphMeterMode_dots; - int GraphMeterMode_pixPerRow; + const char* const* GraphMeterMode_dots = NULL; + int GraphMeterMode_pixPerRow = 0; + int GraphMeterMode_dotSet = channel >= 0 ? channel : 0; #ifdef HAVE_LIBNCURSESW if (CRT_utf8) { - GraphMeterMode_dots = GraphMeterMode_dotsUtf8; + GraphMeterMode_dots = GraphMeterMode_dotsUtf8[GraphMeterMode_dotSet]; GraphMeterMode_pixPerRow = PIXPERROW_UTF8; } else #endif { - GraphMeterMode_dots = GraphMeterMode_dotsAscii; + GraphMeterMode_dots = GraphMeterMode_dotsAscii[GraphMeterMode_dotSet]; GraphMeterMode_pixPerRow = PIXPERROW_ASCII; } + assert(GraphMeterMode_dots); + assert(GraphMeterMode_pixPerRow > 0); // Starting positions of graph data and terminal column if ((size_t)w > nValues / 2) { @@ -290,7 +310,8 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { int line2 = CLAMP(v2 - (GraphMeterMode_pixPerRow * (h - 1 - line)), 0, GraphMeterMode_pixPerRow); attrset(CRT_colors[colorIdx]); - mvaddstr(y + line, x + col, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]); + int screen_row = GraphMeterMode_dotSet == 0 ? y + line : y + h - line - 1; + mvaddstr(screen_row, x + col, GraphMeterMode_dots[line1 * (GraphMeterMode_pixPerRow + 1) + line2]); colorIdx = GRAPH_2; } } @@ -299,6 +320,44 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { attrset(CRT_colors[RESET_COLOR]); } +static void GraphMeterMode_draw(Meter* this, int x, int y, int w) { + assert(x >= 0); + assert(w <= INT_MAX - x); + + // Draw the caption + const int captionLen = 3; + const char* caption = Meter_getCaption(this); + if (w >= captionLen) { + attrset(CRT_colors[METER_TEXT]); + mvaddnstr(y, x, caption, captionLen); + } + w -= captionLen; + + // Draw the graph + GraphMeterMode_drawGraph(this, x + captionLen, y, w, this->h, -1); +} + +static void BipolarMeterMode_draw(Meter* this, int x, int y, int w) { + assert(x >= 0); + assert(w <= INT_MAX - x); + + // Draw the caption + const int captionLen = 3; + const char* caption = Meter_getCaption(this); + if (w >= captionLen) { + attrset(CRT_colors[METER_TEXT]); + mvaddnstr(y, x, caption, captionLen); + } + w -= captionLen; + + // Draw the top graph, half height + GraphMeterMode_drawGraph(this, x + captionLen, y, w, this->h / 2, 0); + + // Draw the bottom graph, half height + y += this->h / 2; + GraphMeterMode_drawGraph(this, x + captionLen, y, w, this->h / 2, 1); +} + /* ---------- LEDMeterMode ---------- */ static const char* const LEDMeterMode_digitsAscii[] = { @@ -404,6 +463,11 @@ static const MeterMode Meter_modes[] = { .h = DEFAULT_GRAPH_HEIGHT, .draw = GraphMeterMode_draw, }, + [BIPOLAR_METERMODE] = { + .uiName = "Bipolar", + .h = DEFAULT_GRAPH_HEIGHT, + .draw = BipolarMeterMode_draw, + }, [LED_METERMODE] = { .uiName = "LED", .h = 3, @@ -483,7 +547,9 @@ void Meter_delete(Object* cast) { if (Meter_doneFn(this)) { Meter_done(this); } - free(this->drawData.values); + for (size_t i = 0; i < ARRAYSIZE(this->drawData); i++) { + free(this->drawData[i].values); + } free(this->caption); free(this->values); free(this); @@ -513,9 +579,10 @@ void Meter_setMode(Meter* this, MeterModeId modeIndex) { this->draw = Meter_drawFn(this); Meter_updateMode(this, modeIndex); } else { - free(this->drawData.values); - this->drawData.values = NULL; - this->drawData.nValues = 0; + for (size_t i = 0; i < ARRAYSIZE(this->drawData); i++) { + free(this->drawData[i].values); + this->drawData[i] = (GraphData) { .values = NULL }; + } const MeterMode* mode = &Meter_modes[modeIndex]; this->draw = mode->draw; diff --git a/Meter.h b/Meter.h index b53a82324..89ebab797 100644 --- a/Meter.h +++ b/Meter.h @@ -110,7 +110,7 @@ struct Meter_ { char* caption; MeterModeId mode; unsigned int param; - GraphData drawData; + GraphData drawData[3]; int h; int columnWidthCount; /**< only used internally by the Header */ uint8_t curItems; diff --git a/MeterMode.h b/MeterMode.h index 8a4355417..03e09c392 100644 --- a/MeterMode.h +++ b/MeterMode.h @@ -13,6 +13,7 @@ enum MeterModeId_ { BAR_METERMODE = 1, TEXT_METERMODE, GRAPH_METERMODE, + BIPOLAR_METERMODE, LED_METERMODE, LAST_METERMODE }; diff --git a/NetworkIOMeter.c b/NetworkIOMeter.c index 784c90ac3..8ff54ed21 100644 --- a/NetworkIOMeter.c +++ b/NetworkIOMeter.c @@ -109,8 +109,9 @@ static void NetworkIOMeter_updateValues(Meter* this) { cached_txp_total = data.packetsTransmitted; } - this->values[0] = cached_rxb_diff; - this->values[1] = cached_txb_diff; + this->values[0] = cached_rxb_diff + cached_txb_diff; + this->values[1] = cached_rxb_diff; + this->values[2] = cached_txb_diff; if (cached_rxb_diff + cached_txb_diff > this->total) { this->total = cached_rxb_diff + cached_txb_diff; } @@ -169,8 +170,13 @@ const MeterClass NetworkIOMeter_class = { }, .updateValues = NetworkIOMeter_updateValues, .defaultMode = TEXT_METERMODE, - .supportedModes = METERMODE_DEFAULT_SUPPORTED, - .maxItems = 2, + .supportedModes = + (1 << BAR_METERMODE) | + (1 << TEXT_METERMODE) | + (1 << GRAPH_METERMODE) | + (1 << LED_METERMODE) | + (1 << BIPOLAR_METERMODE), + .maxItems = 3, .total = 100.0, .attributes = NetworkIOMeter_attributes, .name = "NetworkIO",