Skip to content

Commit b544e39

Browse files
committed
Introduce "Graph2" meter style (two-channel graph)
Introduce a new meter mode (meter style) called "Graph2". The "Graph2" name stands for "two-channel graph" or "two-quadrant graph". This meter mode is not in the list of default supported modes. This "Graph2" mode is intended for meters with two item values. It plots the first item above the x-axis and the second item below the x-axis. Items other than the first two are always hidden. This code is written with the intention to share as much code with the Graph meter mode as possible. Signed-off-by: Kang-Che Sung <[email protected]>
1 parent d53627a commit b544e39

File tree

2 files changed

+106
-23
lines changed

2 files changed

+106
-23
lines changed

Meter.c

Lines changed: 105 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
873873

874874
// Sum the values of all items
875875
double sum = 0.0;
876-
if (this->curItems > 0) {
876+
if (this->mode != GRAPH2_METERMODE && this->curItems > 0) {
877877
sum = Meter_computeSum(this);
878878
assert(sum >= 0.0);
879879
assert(sum <= DBL_MAX);
@@ -887,6 +887,17 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
887887
// Dynamic scale. "this->total" is ignored.
888888
// Determine the scale and "total" that we need afterward. The "total" is
889889
// rounded up to a power of 2.
890+
891+
if (this->mode == GRAPH2_METERMODE) {
892+
// Find the greatest value in this->values array
893+
for (uint8_t i = 0; i < maxItems && i < this->curItems; i++) {
894+
if (isgreater(this->values[i], total)) {
895+
total = this->values[i];
896+
}
897+
}
898+
total = MINIMUM(DBL_MAX, total);
899+
}
900+
890901
int scaleExp = 0;
891902
(void)frexp(total, &scaleExp);
892903
scaleExp = MAXIMUM(0, scaleExp);
@@ -906,6 +917,23 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
906917
assert(h <= UINT16_MAX / 8);
907918
double maxDots = (double)(int32_t)(h * 8);
908919

920+
if (maxItems == 1 || this->mode == GRAPH2_METERMODE) {
921+
// We just need to record the number of dots in the graph data buffer.
922+
for (uint8_t i = 0; i < maxItems; i++) {
923+
unsigned int numDots = 0;
924+
if (total > 0.0 && i < this->curItems && isPositive(this->values[i])) {
925+
double value = MINIMUM(total, this->values[i]);
926+
927+
numDots = (unsigned int)(int32_t)ceil((value / total) * maxDots);
928+
// Division of (value / total) can underflow
929+
numDots = MAXIMUM(1, numDots);
930+
}
931+
assert(numDots <= UINT16_MAX - (8 - 1));
932+
valueStart[(isPercentChart ? 0 : 1) + i].numDots = (uint16_t)numDots;
933+
}
934+
return;
935+
}
936+
909937
// The total number of dots that we would draw for this record
910938
unsigned int numDots = 0;
911939
if (total > 0.0 && sum > 0.0) {
@@ -914,12 +942,6 @@ static void GraphMeterMode_recordNewValue(Meter* this, const GraphDrawContext* c
914942
}
915943
assert(numDots <= UINT16_MAX - (8 - 1));
916944

917-
if (maxItems == 1) {
918-
// We just need to record the number of dots in the graph data buffer.
919-
valueStart[isPercentChart ? 0 : 1].numDots = (uint16_t)numDots;
920-
return;
921-
}
922-
923945
// This is a meter of multiple items.
924946
// First clear the cells, which might contain data of the previous record.
925947
unsigned int y = (numDots + (8 - 1)) / 8; // Round up
@@ -1021,25 +1043,71 @@ static int GraphMeterMode_lookupCell(const Meter* this, const GraphDrawContext*
10211043
deltaExp = scaleExp - valueStart[0].scaleExp;
10221044
}
10231045

1024-
if (maxItems == 1) {
1025-
unsigned int numDots = valueStart[isPercentChart ? 0 : 1].numDots;
1046+
if (this->mode == GRAPH2_METERMODE || maxItems == 1) {
1047+
assert(maxItems <= 2);
10261048

1027-
if (numDots < 1)
1028-
goto cellIsEmpty;
1049+
unsigned int numBlanks[2];
1050+
numBlanks[1] = 0;
1051+
1052+
const GraphDataCell* itemStart = &valueStart[isPercentChart ? 0 : 1];
10291053

1030-
// Scale according to exponent difference. Round up.
1031-
numDots = deltaExp < UINT16_WIDTH ? ((numDots - 1) >> deltaExp) : 0;
1032-
numDots++;
1054+
uint8_t i = 0;
1055+
do {
1056+
unsigned int numDots = itemStart[i].numDots;
1057+
if (numDots >= 1) {
1058+
// Scale according to exponent difference. Round up.
1059+
numDots = deltaExp < UINT16_WIDTH ? ((numDots - 1) >> deltaExp) : 0;
1060+
numDots++;
1061+
}
1062+
1063+
numBlanks[i] = h * 8 - numDots;
1064+
if (this->mode == GRAPH2_METERMODE) {
1065+
numBlanks[i] /= 2;
1066+
}
1067+
} while (++i < maxItems);
10331068

1034-
if (y > (numDots - 1) / 8)
1069+
const uint8_t dotAlignment = 2;
1070+
bool canShowHalfCell = true;
1071+
1072+
unsigned int blanksAtEnd = numBlanks[0];
1073+
if (h - 1 - y < blanksAtEnd / 8)
1074+
goto cellIsEmpty;
1075+
if (h - 1 - y == blanksAtEnd / 8) {
1076+
blanksAtEnd = (blanksAtEnd % 8) / dotAlignment * dotAlignment;
1077+
canShowHalfCell = false;
1078+
} else {
1079+
blanksAtEnd = 0;
1080+
}
1081+
1082+
unsigned int blanksAtStart = numBlanks[1];
1083+
if (y < blanksAtStart / 8)
10351084
goto cellIsEmpty;
1085+
if (y == blanksAtStart / 8) {
1086+
blanksAtStart = (blanksAtStart % 8) / dotAlignment * dotAlignment;
1087+
if (blanksAtEnd + blanksAtStart >= 8) {
1088+
// Happens only if numDots of both items are 0
1089+
goto cellIsEmpty;
1090+
}
1091+
canShowHalfCell = false;
1092+
} else {
1093+
blanksAtStart = 0;
1094+
}
10361095

10371096
itemIndex = 0;
1038-
*details = 0xFF;
1039-
if (y == (numDots - 1) / 8) {
1040-
const uint8_t dotAlignment = 2;
1041-
unsigned int blanksAtTopCell = (8 - 1 - (numDots - 1) % 8) / dotAlignment * dotAlignment;
1042-
*details <<= blanksAtTopCell;
1097+
if (this->mode == GRAPH2_METERMODE) {
1098+
if (y * 2 < h - 1) {
1099+
itemIndex = 1;
1100+
} else if (y * 2 == h - 1 && itemStart[1].numDots > itemStart[0].numDots) {
1101+
itemIndex = 1;
1102+
}
1103+
}
1104+
1105+
if (this->mode == GRAPH2_METERMODE && y * 2 == h - 1 && canShowHalfCell) {
1106+
*details = itemStart[1].numDots > itemStart[0].numDots ? 0xF0 : 0x0F;
1107+
} else {
1108+
*details = 0xFF;
1109+
*details >>= blanksAtStart;
1110+
*details = (uint8_t)((*details >> blanksAtEnd) << blanksAtEnd);
10431111
}
10441112
} else {
10451113
int deltaExpArg = MINIMUM(UINT16_WIDTH - 1, deltaExp);
@@ -1062,13 +1130,14 @@ static int GraphMeterMode_lookupCell(const Meter* this, const GraphDrawContext*
10621130
/* fallthrough */
10631131

10641132
cellIsEmpty:
1065-
if (y == 0)
1133+
if (this->mode != GRAPH2_METERMODE && y == 0)
10661134
*details |= 0xC0;
10671135

10681136
if (itemIndex == (uint8_t)-1)
10691137
return BAR_SHADOW;
10701138

10711139
assert(itemIndex < maxItems);
1140+
assert(itemIndex < Meter_maxItems(this));
10721141
return Meter_attributes(this)[itemIndex];
10731142
}
10741143

@@ -1171,12 +1240,20 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
11711240

11721241
uint8_t maxItems = Meter_maxItems(this);
11731242
assert(this->curItems <= maxItems);
1243+
if (this->mode == GRAPH2_METERMODE) {
1244+
// Items other than the first two are always hidden in "Graph2" mode.
1245+
maxItems = 2;
1246+
}
11741247

11751248
bool isPercentChart = Meter_isPercentChart(this);
11761249

1177-
size_t nCellsPerValue = maxItems == 1 ? maxItems : h;
1178-
if (!isPercentChart)
1250+
size_t nCellsPerValue = this->mode == GRAPH2_METERMODE || maxItems == 1 ? maxItems : h;
1251+
if (!isPercentChart) {
11791252
nCellsPerValue *= 2;
1253+
if (this->mode == GRAPH2_METERMODE) {
1254+
nCellsPerValue--;
1255+
}
1256+
}
11801257

11811258
GraphDrawContext context = {
11821259
.maxItems = maxItems,
@@ -1368,6 +1445,11 @@ static const MeterMode Meter_modes[] = {
13681445
.h = 3,
13691446
.draw = LEDMeterMode_draw,
13701447
},
1448+
[GRAPH2_METERMODE] = {
1449+
.uiName = "Graph2",
1450+
.h = DEFAULT_GRAPH_HEIGHT,
1451+
.draw = GraphMeterMode_draw,
1452+
},
13711453
};
13721454

13731455
/* 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

0 commit comments

Comments
 (0)