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