@@ -98,8 +98,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
9898
9999 const char * ptr = caption ;
100100 int nCols = String_mbswidth (& ptr , 256 , captionWidth );
101- int len = (int )(ptr - caption );
102- mvprintw (y , x , "%-*.*s" , len + captionWidth - nCols , len , caption );
101+ int captionLen = (int )(ptr - caption );
102+ mvprintw (y , x , "%-*.*s" , captionLen + captionWidth - nCols , captionLen , caption );
103103 }
104104 w -= captionWidth ;
105105
@@ -125,71 +125,92 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
125125 attrset (CRT_colors [RESET_COLOR ]); // Clear the bold attribute
126126 x ++ ;
127127
128- // The text in the bar is right aligned;
129- // Pad with maximal spaces and then calculate needed starting position offset
130- RichString_begin (bar );
131- RichString_appendChr (& bar , 0 , ' ' , w );
132- RichString_appendWide (& bar , 0 , this -> txtBuffer );
133-
134- int startPos = RichString_sizeVal (bar ) - w ;
135- if (startPos > w ) {
136- // Text is too large for bar
137- // Truncate meter text at a space character
138- for (int pos = 2 * w ; pos > w ; pos -- ) {
139- if (RichString_getCharVal (bar , pos ) == ' ' ) {
140- while (pos > w && RichString_getCharVal (bar , pos - 1 ) == ' ' )
141- pos -- ;
142- startPos = pos - w ;
143- break ;
144- }
145- }
128+ // Calculate the number of terminal columns needed for the meter text.
129+ // The text in the bar is right aligned
146130
147- // If still too large, print the start not the end
148- startPos = MINIMUM (startPos , w );
131+ RichString_begin (bar );
132+ {
133+ const char * ptr = this -> txtBuffer ;
134+ int padWidth = w - String_lineBreakWidth (& ptr , sizeof (this -> txtBuffer ) - 1 , w , ' ' );
135+ RichString_appendChr (& bar , 0 , ' ' , padWidth );
136+ RichString_appendnWide (& bar , 0 , this -> txtBuffer , (size_t )(ptr - this -> txtBuffer ));
149137 }
150138
151- assert (startPos >= 0 );
152- assert (startPos <= w );
153- assert (startPos + w <= RichString_sizeVal (bar ));
154-
155- int blockSizes [10 ];
139+ #ifdef HAVE_LIBNCURSESW
140+ // If the character takes zero columns, include the character in the
141+ // substring if the working encoding is UTF-8, and ignore it otherwise.
142+ // In Unicode, combining characters are always placed after the base
143+ // character, but some legacy 8-bit encodings instead place combining
144+ // characters before the base character.
145+ const bool isUnicode = CRT_utf8 ;
146+ #else
147+ const bool isUnicode = false;
148+ #endif
156149
157- // First draw in the bar[] buffer...
158150 int offset = 0 ;
151+ size_t len = RichString_sizeVal (bar );
152+ size_t charPos = 0 ;
159153 for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
154+ if (!(this -> total > 0.0 ))
155+ break ;
156+ if (offset >= w )
157+ break ;
158+
160159 double value = this -> values [i ];
161- if (isPositive (value ) && this -> total > 0.0 ) {
162- value = MINIMUM (value , this -> total );
163- blockSizes [i ] = ceil ((value / this -> total ) * w );
164- blockSizes [i ] = MINIMUM (blockSizes [i ], w - offset );
165- } else {
166- blockSizes [i ] = 0 ;
167- }
168- int nextOffset = offset + blockSizes [i ];
169- for (int j = offset ; j < nextOffset ; j ++ )
170- if (RichString_getCharVal (bar , startPos + j ) == ' ' ) {
160+ if (!isPositive (value ))
161+ continue ;
162+ value = MINIMUM (value , this -> total );
163+ int blockSize = ceil ((value / this -> total ) * w );
164+ blockSize = MINIMUM (blockSize , w - offset );
165+ if (blockSize < 1 )
166+ continue ;
167+
168+ int nextOffset = offset + blockSize ;
169+
170+ size_t startPos = charPos ;
171+ while (charPos < len && (offset < nextOffset || isUnicode )) {
172+ assert (offset <= nextOffset );
173+
174+ #ifdef HAVE_LIBNCURSESW
175+ wchar_t ch = RichString_getCharVal (bar , charPos );
176+ #else
177+ char ch = RichString_getCharVal (bar , charPos );
178+ #endif
179+ assert (ch != 0 );
180+
181+ #ifdef HAVE_LIBNCURSESW
182+ int nCols = wcwidth (ch );
183+ assert (nCols >= 0 );
184+
185+ if (offset >= nextOffset && nCols > 0 ) {
186+ // This break condition is for UTF-8.
187+ break ;
188+ }
189+ #else
190+ const int nCols = 1 ;
191+ #endif
192+ if (ch == ' ' ) {
171193 if (CRT_colorScheme == COLORSCHEME_MONOCHROME ) {
172194 assert (i < strlen (BarMeterMode_characters ));
173- RichString_setChar (& bar , startPos + j , BarMeterMode_characters [i ]);
195+ RichString_setChar (& bar , charPos , BarMeterMode_characters [i ]);
174196 } else {
175- RichString_setChar (& bar , startPos + j , '|' );
197+ RichString_setChar (& bar , charPos , '|' );
176198 }
177199 }
178- offset = nextOffset ;
179- }
180200
181- // ...then print the buffer.
182- offset = 0 ;
183- for (uint8_t i = 0 ; i < this -> curItems ; i ++ ) {
201+ offset += nCols ;
202+ charPos ++ ;
203+ }
204+ if (charPos <= startPos )
205+ continue ;
206+
184207 int attr = this -> curAttributes ? this -> curAttributes [i ] : Meter_attributes (this )[i ];
185- RichString_setAttrn (& bar , CRT_colors [attr ], startPos + offset , blockSizes [i ]);
186- RichString_printoffnVal (bar , y , x + offset , startPos + offset , blockSizes [i ]);
187- offset += blockSizes [i ];
208+ RichString_setAttrn (& bar , CRT_colors [attr ], startPos , charPos - startPos );
188209 }
189- if (offset < w ) {
190- RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], startPos + offset , w - offset );
191- RichString_printoffnVal (bar , y , x + offset , startPos + offset , w - offset );
210+ if (charPos < len ) {
211+ RichString_setAttrn (& bar , CRT_colors [BAR_SHADOW ], charPos , len - charPos );
192212 }
213+ RichString_printVal (bar , y , x );
193214
194215 RichString_delete (& bar );
195216
0 commit comments