Skip to content

Commit 8ff19fc

Browse files
committed
(draft) Introduce "Graph2" meter style
Signed-off-by: Kang-Che Sung <[email protected]>
1 parent 30586c8 commit 8ff19fc

File tree

3 files changed

+116
-12
lines changed

3 files changed

+116
-12
lines changed

Meter.c

Lines changed: 114 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
876876

877877
// Sum the values of all items
878878
double sum = 0.0;
879-
if (this->curItems > 0) {
879+
if (this->mode != GRAPH2_METERMODE && this->curItems > 0) {
880880
sum = Meter_computeSum(this);
881881
assert(sum >= 0.0);
882882
assert(sum <= DBL_MAX);
@@ -890,6 +890,17 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
890890
// Dynamic scale. "this->total" is ignored.
891891
// Determine the scale and "total" that we need afterward. The "total" is
892892
// rounded up to a power of 2.
893+
894+
if (this->mode == GRAPH2_METERMODE) {
895+
// Find the greatest value in this->values array
896+
for (uint8_t i = 0; i < maxItems && i < this->curItems; i++) {
897+
if (isgreater(this->values[i], total)) {
898+
total = this->values[i];
899+
}
900+
}
901+
total = MINIMUM(DBL_MAX, total);
902+
}
903+
893904
int scaleExp = 0;
894905
(void)frexp(total, &scaleExp);
895906
scaleExp = MAXIMUM(0, scaleExp);
@@ -910,6 +921,27 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
910921
double maxDots = (double)(int32_t)(h * 8);
911922

912923
// The total number of dots that we would draw for this record
924+
925+
if (maxItems == 1 || this->mode == GRAPH2_METERMODE) {
926+
// We just need to record the number of dots in the graph data buffer.
927+
for (uint8_t i = 0; i < maxItems; i++) {
928+
int numDots = 0;
929+
if (total > 0.0 && i < this->curItems && isPositive(this->values[i])) {
930+
double value = MINIMUM(total, this->values[i]);
931+
932+
numDots = (int)ceil((value / total) * maxDots);
933+
assert(numDots >= 0);
934+
if (numDots <= 0) {
935+
numDots = 1; // Division of (value / total) underflows
936+
}
937+
}
938+
939+
assert(numDots <= UINT16_MAX);
940+
valueStart[(isPercentChart ? 0 : 1) + i].numDots = (uint16_t)numDots;
941+
}
942+
return;
943+
}
944+
913945
int numDots = 0;
914946
if (total > 0.0) {
915947
numDots = (int)ceil((sum / total) * maxDots);
@@ -919,13 +951,6 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
919951
}
920952
}
921953

922-
if (maxItems == 1) {
923-
// We just need to record the number of dots in the graph data buffer.
924-
assert(numDots <= UINT16_MAX);
925-
valueStart[isPercentChart ? 0 : 1].numDots = (uint16_t)numDots;
926-
return;
927-
}
928-
929954
// For a meter of multiple items, we will precompute the colors of each cell
930955
// and store them in a record. First clear the cells, which might contain
931956
// data of the previous record.
@@ -1025,6 +1050,70 @@ static int GraphMeterMode_lookupCell(const Meter* this, const GraphDrawContext*
10251050
const GraphDataCell* valueStart = (const GraphDataCell*)data->buffer;
10261051
valueStart = &valueStart[valueIndex * nCellsPerValue];
10271052

1053+
if (this->mode == GRAPH2_METERMODE) {
1054+
int deltaExp = 0;
1055+
if (!isPercentChart) {
1056+
// The "scaleExp" member exists only for "dynamic scale" meters (i.e.
1057+
// "isPercentChart" being false).
1058+
assert(scaleExp >= valueStart[0].scaleExp);
1059+
deltaExp = scaleExp - valueStart[0].scaleExp;
1060+
}
1061+
1062+
unsigned int numDots = valueStart[(isPercentChart ? 0 : 1) + 0].numDots;
1063+
if (numDots >= 1) {
1064+
if (deltaExp + 1 < UINT16_WIDTH) {
1065+
numDots = ((numDots - 1) >> (deltaExp + 1)) + 1;
1066+
} else {
1067+
numDots = 1;
1068+
}
1069+
}
1070+
unsigned int blanksAtEnd = h * 4 - numDots;
1071+
1072+
numDots = valueStart[(isPercentChart ? 0 : 1) + 1].numDots;
1073+
if (numDots >= 1) {
1074+
if (deltaExp + 1 < UINT16_WIDTH) {
1075+
numDots = ((numDots - 1) >> (deltaExp + 1)) + 1;
1076+
} else {
1077+
numDots = 1;
1078+
}
1079+
}
1080+
unsigned int blanksAtStart = h * 4 - numDots;
1081+
1082+
if (h - 1 - y < blanksAtEnd / 8)
1083+
goto cellIsEmpty;
1084+
if (y < blanksAtStart / 8)
1085+
goto cellIsEmpty;
1086+
1087+
if (y * 2 == h - 1 && !(valueStart[(isPercentChart ? 0 : 1) + 0].numDots || valueStart[(isPercentChart ? 0 : 1) + 1].numDots))
1088+
goto cellIsEmpty;
1089+
1090+
if (maxItems <= 1 || y * 2 > h - 1) {
1091+
itemIndex = 0;
1092+
} else if (y * 2 < h - 1) {
1093+
itemIndex = 1;
1094+
} else {
1095+
itemIndex = valueStart[(isPercentChart ? 0 : 1) + 0].numDots >= valueStart[(isPercentChart ? 0 : 1) + 1].numDots ? 0 : 1;
1096+
}
1097+
1098+
if (y * 2 == h - 1 && valueStart[(isPercentChart ? 0 : 1) + 0].numDots > 8 && valueStart[(isPercentChart ? 0 : 1) + 1].numDots > 8) {
1099+
*details = valueStart[(isPercentChart ? 0 : 1) + 0].numDots >= valueStart[(isPercentChart ? 0 : 1) + 1].numDots ? 0x0F : 0xF0;
1100+
} else {
1101+
*details = 0xFF;
1102+
const uint8_t dotAlignment = 2;
1103+
if (y == blanksAtStart / 8) {
1104+
blanksAtStart = (blanksAtStart % 8) / dotAlignment * dotAlignment;
1105+
*details >>= blanksAtStart;
1106+
}
1107+
if ((h - 1 - y) == blanksAtEnd / 8) {
1108+
blanksAtEnd = (blanksAtEnd % 8) / dotAlignment * dotAlignment;
1109+
*details = (uint8_t)((*details >> blanksAtEnd) << blanksAtEnd);
1110+
}
1111+
}
1112+
1113+
/* fallthrough */
1114+
goto cellIsEmpty;
1115+
}
1116+
10281117
int deltaExp = 0;
10291118
if (!isPercentChart) {
10301119
// The "scaleExp" member exists only for "dynamic scale" meters (i.e.
@@ -1074,13 +1163,14 @@ static int GraphMeterMode_lookupCell(const Meter* this, const GraphDrawContext*
10741163
/* fallthrough */
10751164

10761165
cellIsEmpty:
1077-
if (y == 0)
1166+
if (this->mode != GRAPH2_METERMODE && y == 0)
10781167
*details |= 0xC0;
10791168

10801169
if (itemIndex == (uint8_t)-1)
10811170
return BAR_SHADOW;
10821171

10831172
assert(itemIndex < maxItems);
1173+
assert(itemIndex < Meter_maxItems(this));
10841174
return Meter_attributes(this)[itemIndex];
10851175
}
10861176

@@ -1183,12 +1273,20 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
11831273

11841274
uint8_t maxItems = Meter_maxItems(this);
11851275
assert(this->curItems <= maxItems);
1276+
if (this->mode == GRAPH2_METERMODE) {
1277+
// Items other than the first two are always hidden in "Graph2" mode.
1278+
maxItems = 2;
1279+
}
11861280

11871281
bool isPercentChart = Meter_isPercentChart(this);
11881282

1189-
size_t nCellsPerValue = maxItems == 1 ? maxItems : h;
1190-
if (!isPercentChart)
1283+
size_t nCellsPerValue = this->mode == GRAPH2_METERMODE || maxItems == 1 ? maxItems : h;
1284+
if (!isPercentChart) {
11911285
nCellsPerValue *= 2;
1286+
if (this->mode == GRAPH2_METERMODE) {
1287+
nCellsPerValue--;
1288+
}
1289+
}
11921290

11931291
GraphDrawContext context = {
11941292
.maxItems = maxItems,
@@ -1380,6 +1478,11 @@ static const MeterMode Meter_modes[] = {
13801478
.h = 3,
13811479
.draw = LEDMeterMode_draw,
13821480
},
1481+
[GRAPH2_METERMODE] = {
1482+
.uiName = "Graph2",
1483+
.h = DEFAULT_GRAPH_HEIGHT,
1484+
.draw = GraphMeterMode_draw,
1485+
},
13831486
};
13841487

13851488
/* Meter class and methods */

MeterMode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum MeterModeId_ {
1414
TEXT_METERMODE,
1515
GRAPH_METERMODE,
1616
LED_METERMODE,
17+
GRAPH2_METERMODE /* Not default supported */,
1718
LAST_METERMODE
1819
};
1920

NetworkIOMeter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ const MeterClass NetworkIOMeter_class = {
166166
},
167167
.updateValues = NetworkIOMeter_updateValues,
168168
.defaultMode = TEXT_METERMODE,
169-
.supportedModes = METERMODE_DEFAULT_SUPPORTED,
169+
.supportedModes = METERMODE_DEFAULT_SUPPORTED | (1 << GRAPH2_METERMODE),
170170
.maxItems = 2,
171171
.isPercentChart = false,
172172
.total = 1.0,

0 commit comments

Comments
 (0)