@@ -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