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