@@ -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
10761165cellIsEmpty :
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 */
0 commit comments