@@ -109,71 +109,146 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
109
109
}
110
110
x ++ ;
111
111
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 ;
128
151
}
152
+ break ;
129
153
}
130
154
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
134
168
135
- assert (startPos >= 0 );
136
- assert (startPos <= w );
137
- assert (startPos + w <= RichString_sizeVal (bar ));
169
+ len = (size_t )(state .str - this -> txtBuffer );
170
+ }
138
171
139
- int blockSizes [10 ];
172
+ RichString_begin (bar );
173
+ RichString_appendChr (& bar , 0 , ' ' , nColsLeft );
174
+ RichString_appendnWide (& bar , 0 , this -> txtBuffer , len );
140
175
141
- // First draw in the bar[] buffer...
176
+ size_t charPos = 0 ;
142
177
int offset = 0 ;
143
178
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
+
144
186
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 ;
151
189
}
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 == ' ' ) {
155
231
if (CRT_colorScheme == COLORSCHEME_MONOCHROME ) {
156
232
assert (i < strlen (BarMeterMode_characters ));
157
- RichString_setChar (& bar , startPos + j , BarMeterMode_characters [i ]);
233
+ RichString_setChar (& bar , charPos , BarMeterMode_characters [i ]);
158
234
} else {
159
- RichString_setChar (& bar , startPos + j , '|' );
235
+ RichString_setChar (& bar , charPos , '|' );
160
236
}
161
237
}
162
- offset = nextOffset ;
163
- }
164
238
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
+
168
243
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 );
172
245
}
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 );
176
250
}
251
+ RichString_printVal (bar , y , x );
177
252
178
253
RichString_delete (& bar );
179
254
0 commit comments