@@ -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.
@@ -1028,6 +1053,65 @@ static int GraphMeterMode_lookupCell(const Meter* this, const GraphDrawContext*
10281053 const GraphDataCell * valueStart = (const GraphDataCell * )data -> buffer ;
10291054 valueStart = & valueStart [valueIndex * nCellsPerValue ];
10301055
1056+ if (this -> mode == GRAPH2_METERMODE ) {
1057+ int deltaExp = isPercentChart ? 0 : scaleExp - valueStart [0 ].scaleExp ;
1058+ assert (deltaExp >= 0 );
1059+
1060+ unsigned int numDots = valueStart [(isPercentChart ? 0 : 1 ) + 0 ].numDots ;
1061+ if (numDots >= 1 ) {
1062+ if (deltaExp + 1 < UINT16_WIDTH ) {
1063+ numDots = ((numDots - 1 ) >> (deltaExp + 1 )) + 1 ;
1064+ } else {
1065+ numDots = 1 ;
1066+ }
1067+ }
1068+ unsigned int blanksAtEnd = h * 4 - numDots ;
1069+
1070+ numDots = valueStart [(isPercentChart ? 0 : 1 ) + 1 ].numDots ;
1071+ if (numDots >= 1 ) {
1072+ if (deltaExp + 1 < UINT16_WIDTH ) {
1073+ numDots = ((numDots - 1 ) >> (deltaExp + 1 )) + 1 ;
1074+ } else {
1075+ numDots = 1 ;
1076+ }
1077+ }
1078+ unsigned int blanksAtStart = h * 4 - numDots ;
1079+
1080+ if (h - 1 - y < blanksAtEnd / 8 )
1081+ goto cellIsEmpty ;
1082+ if (y < blanksAtStart / 8 )
1083+ goto cellIsEmpty ;
1084+
1085+ if (y * 2 == h - 1 && !(valueStart [(isPercentChart ? 0 : 1 ) + 0 ].numDots || valueStart [(isPercentChart ? 0 : 1 ) + 1 ].numDots ))
1086+ goto cellIsEmpty ;
1087+
1088+ if (maxItems <= 1 || y * 2 > h - 1 ) {
1089+ itemIndex = 0 ;
1090+ } else if (y * 2 < h - 1 ) {
1091+ itemIndex = 1 ;
1092+ } else {
1093+ itemIndex = valueStart [(isPercentChart ? 0 : 1 ) + 0 ].numDots >= valueStart [(isPercentChart ? 0 : 1 ) + 1 ].numDots ? 0 : 1 ;
1094+ }
1095+
1096+ if (y * 2 == h - 1 && valueStart [(isPercentChart ? 0 : 1 ) + 0 ].numDots > 8 && valueStart [(isPercentChart ? 0 : 1 ) + 1 ].numDots > 8 ) {
1097+ * details = valueStart [(isPercentChart ? 0 : 1 ) + 0 ].numDots >= valueStart [(isPercentChart ? 0 : 1 ) + 1 ].numDots ? 0x0F : 0xF0 ;
1098+ } else {
1099+ * details = 0xFF ;
1100+ const uint8_t dotAlignment = 2 ;
1101+ if (y == blanksAtStart / 8 ) {
1102+ blanksAtStart = (blanksAtStart % 8 ) / dotAlignment * dotAlignment ;
1103+ * details >>= blanksAtStart ;
1104+ }
1105+ if ((h - 1 - y ) == blanksAtEnd / 8 ) {
1106+ blanksAtEnd = (blanksAtEnd % 8 ) / dotAlignment * dotAlignment ;
1107+ * details = (uint8_t )((* details >> blanksAtEnd ) << blanksAtEnd );
1108+ }
1109+ }
1110+
1111+ /* fallthrough */
1112+ goto cellIsEmpty ;
1113+ }
1114+
10311115 int deltaExp = 0 ;
10321116 if (!isPercentChart ) {
10331117 // The "scaleExp" member exists only for "dynamic scale" meters (i.e.
@@ -1077,7 +1161,7 @@ static int GraphMeterMode_lookupCell(const Meter* this, const GraphDrawContext*
10771161 /* fallthrough */
10781162
10791163cellIsEmpty :
1080- if (y == 0 )
1164+ if (this -> mode != GRAPH2_METERMODE && y == 0 )
10811165 * details |= 0xC0 ;
10821166
10831167 if (itemIndex == (uint8_t )-1 )
@@ -1185,11 +1269,31 @@ static void GraphMeterMode_draw(Meter* this, int x, int y, int w) {
11851269 unsigned int h = (unsigned int )this -> h ;
11861270
11871271 uint8_t maxItems = Meter_maxItems (this );
1272+ if (this -> mode == GRAPH2_METERMODE && maxItems > 2 ) {
1273+ // Items other than the first two are always hidden in "Graph2" mode.
1274+ maxItems = 2 ;
1275+ }
1276+
11881277 bool isPercentChart = Meter_isPercentChart (this );
11891278
1190- size_t nCellsPerValue = maxItems <= 1 ? maxItems : h ;
1191- if (!isPercentChart )
1192- nCellsPerValue *= 2 ;
1279+ size_t nCellsPerValue ;
1280+ if (this -> mode == GRAPH2_METERMODE ) {
1281+ if (isPercentChart ) {
1282+ nCellsPerValue = maxItems ;
1283+ } else if (maxItems > 0 ) {
1284+ nCellsPerValue = 1 + maxItems ;
1285+ } else {
1286+ nCellsPerValue = 0 ;
1287+ }
1288+ } else {
1289+ if (maxItems <= 1 ) {
1290+ nCellsPerValue = maxItems ;
1291+ } else {
1292+ nCellsPerValue = h ;
1293+ }
1294+ if (!isPercentChart )
1295+ nCellsPerValue *= 2 ;
1296+ }
11931297
11941298 GraphDrawContext context = {
11951299 .maxItems = maxItems ,
@@ -1381,6 +1485,11 @@ static const MeterMode Meter_modes[] = {
13811485 .h = 3 ,
13821486 .draw = LEDMeterMode_draw ,
13831487 },
1488+ [GRAPH2_METERMODE ] = {
1489+ .uiName = "Graph2" ,
1490+ .h = DEFAULT_GRAPH_HEIGHT ,
1491+ .draw = GraphMeterMode_draw ,
1492+ },
13841493};
13851494
13861495/* Meter class and methods */
0 commit comments