@@ -89,15 +89,21 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
8989
9090 // Draw the caption
9191 const int captionWidth = 3 ;
92+ if (w < captionWidth )
93+ return ;
94+
9295 Meter_drawCaptionFixedWidth (this , x , y , captionWidth );
9396 x += captionWidth ;
9497 w -= captionWidth ;
9598
9699 // Draw the bar borders
100+ if (w < 1 )
101+ return ;
102+
97103 attrset (CRT_colors [BAR_BORDER ]);
98104 mvaddch (y , x , '[' );
99105 w -- ;
100- mvaddch (y , x + MAXIMUM ( w , 0 ) , ']' );
106+ mvaddch (y , x + w , ']' );
101107 w -- ;
102108 attrset (CRT_colors [RESET_COLOR ]);
103109
@@ -107,71 +113,146 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
107113 return ;
108114 }
109115
110- // The text in the bar is right aligned;
111- // Pad with maximal spaces and then calculate needed starting position offset
112- RichString_begin (bar );
113- RichString_appendChr (& bar , 0 , ' ' , w );
114- RichString_appendWide (& bar , 0 , this -> txtBuffer );
115-
116- int startPos = RichString_sizeVal (bar ) - w ;
117- if (startPos > w ) {
118- // Text is too large for bar
119- // Truncate meter text at a space character
120- for (int pos = 2 * w ; pos > w ; pos -- ) {
121- if (RichString_getCharVal (bar , pos ) == ' ' ) {
122- while (pos > w && RichString_getCharVal (bar , pos - 1 ) == ' ' )
123- pos -- ;
124- startPos = pos - w ;
125- break ;
116+ // Calculate the number of terminal columns needed for the meter text.
117+
118+ // The text in the bar is right aligned
119+
120+ MBStringDecoderState state ;
121+ memset (& state , 0 , sizeof (state ));
122+ state .str = this -> txtBuffer ;
123+ state .maxLen = sizeof (this -> txtBuffer ) - 1 ;
124+
125+ int nColsLeft = w ; // pun intended
126+ int savedCols = nColsLeft ;
127+ size_t len = 0 ;
128+ size_t savedLen = 0 ;
129+
130+ while (String_decodeNextWChar (& state )) {
131+ if (state .ch == 0 )
132+ break ;
133+
134+ if (state .ch == ' ' ) {
135+ savedLen = len ;
136+ savedCols = nColsLeft ;
137+ }
138+
139+ #ifdef HAVE_LIBNCURSESW
140+ int nCols = wcwidth ((wchar_t )state .ch );
141+ if (nCols < 0 ) {
142+ assert (nCols >= 0 );
143+ break ;
144+ }
145+ #else
146+ int nCols = 1 ;
147+ #endif
148+
149+ if (nCols > nColsLeft ) {
150+ // Text is too large for bar
151+ // Truncate meter text at a space character
152+ if (savedLen > 0 ) {
153+ len = savedLen ;
154+ nColsLeft = savedCols ;
126155 }
156+ break ;
127157 }
128158
129- // If still too large, print the start not the end
130- startPos = MINIMUM (startPos , w );
131- }
159+ nColsLeft -= nCols ;
132160
133- assert ( startPos >= 0 );
134- assert ( startPos <= w ) ;
135- assert ( startPos + w <= RichString_sizeVal ( bar ));
161+ if ( state . ch == ' ' ) {
162+ continue ;
163+ }
136164
137- int blockSizes [10 ];
165+ #ifdef HAVE_LIBNCURSESW
166+ // If the character takes zero columns, include the character in the
167+ // substring if the working encoding is UTF-8, and ignore it otherwise.
168+ if (nCols <= 0 && !CRT_utf8 ) {
169+ continue ;
170+ }
171+ #endif
172+
173+ len = (size_t )(state .str - this -> txtBuffer );
174+ }
175+
176+ RichString_begin (bar );
177+ RichString_appendChr (& bar , 0 , ' ' , nColsLeft );
178+ RichString_appendnWide (& bar , 0 , this -> txtBuffer , len );
138179
139- // First draw in the bar[] buffer...
180+ size_t charPos = 0 ;
140181 int offset = 0 ;
141182 for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
183+ if (!(this -> total > 0.0 )) {
184+ break ;
185+ }
186+ if (offset >= w ) {
187+ break ;
188+ }
189+
142190 double value = this -> values [i ];
143- if (isPositive (value ) && this -> total > 0.0 ) {
144- value = MINIMUM (value , this -> total );
145- blockSizes [i ] = ceil ((value / this -> total ) * w );
146- blockSizes [i ] = MINIMUM (blockSizes [i ], w - offset );
147- } else {
148- blockSizes [i ] = 0 ;
191+ if (!isPositive (value )) {
192+ continue ;
149193 }
150- int nextOffset = offset + blockSizes [i ];
151- for (int j = offset ; j < nextOffset ; j ++ )
152- if (RichString_getCharVal (bar , startPos + j ) == ' ' ) {
194+ value = MINIMUM (value , this -> total );
195+ int blockSize = ceil ((value / this -> total ) * w );
196+ blockSize = MINIMUM (blockSize , w - offset );
197+ if (blockSize < 1 ) {
198+ continue ;
199+ }
200+
201+ int nextOffset = offset + blockSize ;
202+ assert (offset < nextOffset );
203+
204+ size_t startPos = charPos ;
205+ while (true) {
206+ if (offset >= nextOffset ) {
207+ #ifdef HAVE_LIBNCURSESW
208+ if (!CRT_utf8 ) {
209+ break ;
210+ }
211+ #else
212+ break ;
213+ #endif
214+ }
215+
216+ #ifdef HAVE_LIBNCURSESW
217+ wchar_t ch = RichString_getCharVal (bar , charPos );
218+ if (ch == 0 )
219+ break ;
220+
221+ int nCols = wcwidth (ch );
222+ assert (nCols >= 0 );
223+
224+ if (offset >= nextOffset && nCols > 0 ) {
225+ // This break condition is for UTF-8.
226+ break ;
227+ }
228+ #else
229+ char ch = RichString_getCharVal (bar , charPos );
230+ int nCols = 1 ;
231+
232+ assert (offset < nextOffset );
233+ #endif
234+ if (ch == ' ' ) {
153235 if (CRT_colorScheme == COLORSCHEME_MONOCHROME ) {
154236 assert (i < strlen (BarMeterMode_characters ));
155- RichString_setChar (& bar , startPos + j , BarMeterMode_characters [i ]);
237+ RichString_setChar (& bar , charPos , BarMeterMode_characters [i ]);
156238 } else {
157- RichString_setChar (& bar , startPos + j , '|' );
239+ RichString_setChar (& bar , charPos , '|' );
158240 }
159241 }
160- offset = nextOffset ;
161- }
162242
163- // ...then print the buffer.
164- offset = 0 ;
165- for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
243+ offset += nCols ;
244+ charPos ++ ;
245+ }
246+
166247 int attr = this -> curAttributes ? this -> curAttributes [i ] : Meter_attributes (this )[i ];
167- RichString_setAttrn (& bar , CRT_colors [attr ], startPos + offset , blockSizes [i ]);
168- RichString_printoffnVal (bar , y , x + offset , startPos + offset , blockSizes [i ]);
169- offset += blockSizes [i ];
248+ RichString_setAttrn (& bar , CRT_colors [attr ], startPos , charPos - startPos );
170249 }
171- if (offset < w ) {
172- RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], startPos + offset , w - offset );
173- RichString_printoffnVal (bar , y , x + offset , startPos + offset , w - offset );
250+
251+ len = RichString_sizeVal (bar );
252+ if (charPos < len ) {
253+ RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], charPos , len - charPos );
174254 }
255+ RichString_printVal (bar , y , x );
175256
176257 RichString_delete (& bar );
177258
0 commit comments