@@ -109,71 +109,146 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
109109 }
110110 x ++ ;
111111
112- // The text in the bar is right aligned;
113- // Pad with maximal spaces and then calculate needed starting position offset
114- RichString_begin (bar );
115- RichString_appendChr (& bar , 0 , ' ' , w );
116- RichString_appendWide (& bar , 0 , this -> txtBuffer );
117-
118- int startPos = RichString_sizeVal (bar ) - w ;
119- if (startPos > w ) {
120- // Text is too large for bar
121- // Truncate meter text at a space character
122- for (int pos = 2 * w ; pos > w ; pos -- ) {
123- if (RichString_getCharVal (bar , pos ) == ' ' ) {
124- while (pos > w && RichString_getCharVal (bar , pos - 1 ) == ' ' )
125- pos -- ;
126- startPos = pos - w ;
127- break ;
112+ // Calculate the number of terminal columns needed for the meter text.
113+
114+ // The text in the bar is right aligned
115+
116+ MBStringDecoderState state ;
117+ memset (& state , 0 , sizeof (state ));
118+ state .str = this -> txtBuffer ;
119+ state .maxLen = sizeof (this -> txtBuffer ) - 1 ;
120+
121+ int nColsLeft = w ; // pun intended
122+ int savedCols = nColsLeft ;
123+ size_t len = 0 ;
124+ size_t savedLen = 0 ;
125+
126+ while (String_decodeNextWChar (& state )) {
127+ if (state .ch == 0 )
128+ break ;
129+
130+ if (state .ch == ' ' ) {
131+ savedLen = len ;
132+ savedCols = nColsLeft ;
133+ }
134+
135+ #ifdef HAVE_LIBNCURSESW
136+ int nCols = wcwidth ((wchar_t )state .ch );
137+ if (nCols < 0 ) {
138+ assert (nCols >= 0 );
139+ break ;
140+ }
141+ #else
142+ int nCols = 1 ;
143+ #endif
144+
145+ if (nCols > nColsLeft ) {
146+ // Text is too large for bar
147+ // Truncate meter text at a space character
148+ if (savedLen > 0 ) {
149+ len = savedLen ;
150+ nColsLeft = savedCols ;
128151 }
152+ break ;
129153 }
130154
131- // If still too large, print the start not the end
132- startPos = MINIMUM (startPos , w );
133- }
155+ nColsLeft -= nCols ;
156+
157+ if (state .ch == ' ' ) {
158+ continue ;
159+ }
160+
161+ #ifdef HAVE_LIBNCURSESW
162+ // If the character takes zero columns, include the character in the
163+ // substring if the working encoding is UTF-8, and ignore it otherwise.
164+ if (nCols <= 0 && !CRT_utf8 ) {
165+ continue ;
166+ }
167+ #endif
134168
135- assert (startPos >= 0 );
136- assert (startPos <= w );
137- assert (startPos + w <= RichString_sizeVal (bar ));
169+ len = (size_t )(state .str - this -> txtBuffer );
170+ }
138171
139- int blockSizes [10 ];
172+ RichString_begin (bar );
173+ RichString_appendChr (& bar , 0 , ' ' , nColsLeft );
174+ RichString_appendnWide (& bar , 0 , this -> txtBuffer , len );
140175
141- // First draw in the bar[] buffer...
176+ size_t charPos = 0 ;
142177 int offset = 0 ;
143178 for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
179+ if (!(this -> total > 0.0 )) {
180+ break ;
181+ }
182+ if (offset >= w ) {
183+ break ;
184+ }
185+
144186 double value = this -> values [i ];
145- if (isPositive (value ) && this -> total > 0.0 ) {
146- value = MINIMUM (value , this -> total );
147- blockSizes [i ] = ceil ((value / this -> total ) * w );
148- blockSizes [i ] = MINIMUM (blockSizes [i ], w - offset );
149- } else {
150- blockSizes [i ] = 0 ;
187+ if (!isPositive (value )) {
188+ continue ;
151189 }
152- int nextOffset = offset + blockSizes [i ];
153- for (int j = offset ; j < nextOffset ; j ++ )
154- if (RichString_getCharVal (bar , startPos + j ) == ' ' ) {
190+ value = MINIMUM (value , this -> total );
191+ int blockSize = ceil ((value / this -> total ) * w );
192+ blockSize = MINIMUM (blockSize , w - offset );
193+ if (blockSize < 1 ) {
194+ continue ;
195+ }
196+
197+ int nextOffset = offset + blockSize ;
198+ assert (offset < nextOffset );
199+
200+ size_t startPos = charPos ;
201+ while (true) {
202+ if (offset >= nextOffset ) {
203+ #ifdef HAVE_LIBNCURSESW
204+ if (!CRT_utf8 ) {
205+ break ;
206+ }
207+ #else
208+ break ;
209+ #endif
210+ }
211+
212+ #ifdef HAVE_LIBNCURSESW
213+ wchar_t ch = RichString_getCharVal (bar , charPos );
214+ if (ch == 0 )
215+ break ;
216+
217+ int nCols = wcwidth (ch );
218+ assert (nCols >= 0 );
219+
220+ if (offset >= nextOffset && nCols > 0 ) {
221+ // This break condition is for UTF-8.
222+ break ;
223+ }
224+ #else
225+ char ch = RichString_getCharVal (bar , charPos );
226+ int nCols = 1 ;
227+
228+ assert (offset < nextOffset );
229+ #endif
230+ if (ch == ' ' ) {
155231 if (CRT_colorScheme == COLORSCHEME_MONOCHROME ) {
156232 assert (i < strlen (BarMeterMode_characters ));
157- RichString_setChar (& bar , startPos + j , BarMeterMode_characters [i ]);
233+ RichString_setChar (& bar , charPos , BarMeterMode_characters [i ]);
158234 } else {
159- RichString_setChar (& bar , startPos + j , '|' );
235+ RichString_setChar (& bar , charPos , '|' );
160236 }
161237 }
162- offset = nextOffset ;
163- }
164238
165- // ...then print the buffer.
166- offset = 0 ;
167- for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
239+ offset += nCols ;
240+ charPos ++ ;
241+ }
242+
168243 int attr = this -> curAttributes ? this -> curAttributes [i ] : Meter_attributes (this )[i ];
169- RichString_setAttrn (& bar , CRT_colors [attr ], startPos + offset , blockSizes [i ]);
170- RichString_printoffnVal (bar , y , x + offset , startPos + offset , blockSizes [i ]);
171- offset += blockSizes [i ];
244+ RichString_setAttrn (& bar , CRT_colors [attr ], startPos , charPos - startPos );
172245 }
173- if (offset < w ) {
174- RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], startPos + offset , w - offset );
175- RichString_printoffnVal (bar , y , x + offset , startPos + offset , w - offset );
246+
247+ len = RichString_sizeVal (bar );
248+ if (charPos < len ) {
249+ RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], charPos , len - charPos );
176250 }
251+ RichString_printVal (bar , y , x );
177252
178253 RichString_delete (& bar );
179254
0 commit comments