@@ -98,8 +98,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
9898
9999 const char * ptr = caption ;
100100 int nCols = String_mbswidth (& ptr , 256 , captionWidth );
101- int len = (int )(ptr - caption );
102- mvprintw (y , x , "%-*.*s" , len + captionWidth - nCols , len , caption );
101+ int captionLen = (int )(ptr - caption );
102+ mvprintw (y , x , "%-*.*s" , captionLen + captionWidth - nCols , captionLen , caption );
103103 }
104104 w -= captionWidth ;
105105
@@ -125,71 +125,94 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
125125 attrset (CRT_colors [RESET_COLOR ]); // Clear the bold attribute
126126 x ++ ;
127127
128- // The text in the bar is right aligned;
129- // Pad with maximal spaces and then calculate needed starting position offset
130- RichString_begin (bar );
131- RichString_appendChr (& bar , 0 , ' ' , w );
132- RichString_appendWide (& bar , 0 , this -> txtBuffer );
133-
134- int startPos = RichString_sizeVal (bar ) - w ;
135- if (startPos > w ) {
136- // Text is too large for bar
137- // Truncate meter text at a space character
138- for (int pos = 2 * w ; pos > w ; pos -- ) {
139- if (RichString_getCharVal (bar , pos ) == ' ' ) {
140- while (pos > w && RichString_getCharVal (bar , pos - 1 ) == ' ' )
141- pos -- ;
142- startPos = pos - w ;
143- break ;
144- }
145- }
128+ // Calculate the number of terminal columns needed for the meter text.
129+ // The text in the bar is right aligned
146130
147- // If still too large, print the start not the end
148- startPos = MINIMUM (startPos , w );
131+ RichString_begin (bar );
132+ {
133+ const char * ptr = this -> txtBuffer ;
134+ int padWidth = w - String_lineBreakWidth (& ptr , sizeof (this -> txtBuffer ) - 1 , w , ' ' );
135+ RichString_appendChr (& bar , 0 , ' ' , padWidth );
136+ RichString_appendnWide (& bar , 0 , this -> txtBuffer , (size_t )(ptr - this -> txtBuffer ));
149137 }
150138
151- assert (startPos >= 0 );
152- assert (startPos <= w );
153- assert (startPos + w <= RichString_sizeVal (bar ));
154-
155- int blockSizes [10 ];
139+ #ifdef HAVE_LIBNCURSESW
140+ // If the character takes zero columns, include the character in the
141+ // substring if the working encoding is UTF-8, and ignore it otherwise.
142+ // In Unicode, combining characters are always placed after the base
143+ // character, but some legacy 8-bit encodings instead place combining
144+ // characters before the base character.
145+ const bool isUnicode = CRT_utf8 ;
146+ #else
147+ const bool isUnicode = false;
148+ #endif
156149
157- // First draw in the bar[] buffer...
158150 int offset = 0 ;
151+ size_t charPos = 0 ;
159152 for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
153+ if (!(this -> total > 0.0 ))
154+ break ;
155+ if (offset >= w )
156+ break ;
157+
160158 double value = this -> values [i ];
161- if (isPositive (value ) && this -> total > 0.0 ) {
162- value = MINIMUM (value , this -> total );
163- blockSizes [i ] = ceil ((value / this -> total ) * w );
164- blockSizes [i ] = MINIMUM (blockSizes [i ], w - offset );
165- } else {
166- blockSizes [i ] = 0 ;
167- }
168- int nextOffset = offset + blockSizes [i ];
169- for (int j = offset ; j < nextOffset ; j ++ )
170- if (RichString_getCharVal (bar , startPos + j ) == ' ' ) {
159+ if (!isPositive (value ))
160+ continue ;
161+ value = MINIMUM (value , this -> total );
162+ int blockSize = ceil ((value / this -> total ) * w );
163+ blockSize = MINIMUM (blockSize , w - offset );
164+ if (blockSize < 1 )
165+ continue ;
166+
167+ int nextOffset = offset + blockSize ;
168+
169+ size_t startPos = charPos ;
170+ do {
171+ assert (offset <= nextOffset );
172+
173+ #ifdef HAVE_LIBNCURSESW
174+ wchar_t ch = RichString_getCharVal (bar , charPos );
175+ #else
176+ char ch = RichString_getCharVal (bar , charPos );
177+ #endif
178+ if (ch == 0 )
179+ break ;
180+
181+ #ifdef HAVE_LIBNCURSESW
182+ int nCols = wcwidth (ch );
183+ assert (nCols >= 0 );
184+
185+ if (offset >= nextOffset && nCols > 0 ) {
186+ // This break condition is for UTF-8.
187+ break ;
188+ }
189+ #else
190+ const int nCols = 1 ;
191+ #endif
192+ if (ch == ' ' ) {
171193 if (CRT_colorScheme == COLORSCHEME_MONOCHROME ) {
172194 assert (i < strlen (BarMeterMode_characters ));
173- RichString_setChar (& bar , startPos + j , BarMeterMode_characters [i ]);
195+ RichString_setChar (& bar , charPos , BarMeterMode_characters [i ]);
174196 } else {
175- RichString_setChar (& bar , startPos + j , '|' );
197+ RichString_setChar (& bar , charPos , '|' );
176198 }
177199 }
178- offset = nextOffset ;
179- }
180200
181- // ...then print the buffer.
182- offset = 0 ;
183- for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
201+ offset += nCols ;
202+ charPos ++ ;
203+ } while (offset < nextOffset || isUnicode );
204+
184205 int attr = this -> curAttributes ? this -> curAttributes [i ] : Meter_attributes (this )[i ];
185- RichString_setAttrn (& bar , CRT_colors [attr ], startPos + offset , blockSizes [i ]);
186- RichString_printoffnVal (bar , y , x + offset , startPos + offset , blockSizes [i ]);
187- offset += blockSizes [i ];
206+ RichString_setAttrn (& bar , CRT_colors [attr ], startPos , charPos - startPos );
188207 }
189- if (offset < w ) {
190- RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], startPos + offset , w - offset );
191- RichString_printoffnVal (bar , y , x + offset , startPos + offset , w - offset );
208+
209+ {
210+ size_t len = RichString_sizeVal (bar );
211+ if (charPos < len ) {
212+ RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], charPos , len - charPos );
213+ }
192214 }
215+ RichString_printVal (bar , y , x );
193216
194217 RichString_delete (& bar );
195218
0 commit comments