Skip to content

Commit bbb62fb

Browse files
committed
Wide character support in bar meter text
1 parent 9d71bea commit bbb62fb

File tree

1 file changed

+78
-52
lines changed

1 file changed

+78
-52
lines changed

Meter.c

Lines changed: 78 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,19 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
9090
assert(x >= 0);
9191
assert(w <= INT_MAX - x);
9292

93+
const char* ptr;
94+
int nCols;
95+
9396
// Draw the caption
9497
const int captionWidth = 3;
9598
const char* caption = Meter_getCaption(this);
9699
if (w >= captionWidth) {
97100
attrset(CRT_colors[METER_TEXT]);
98101

99-
const char* ptr = caption;
100-
int nCols = String_mbswidth(&ptr, 256, captionWidth);
101-
int len = (int)(ptr - caption);
102-
mvprintw(y, x, "%-*.*s", len + captionWidth - nCols, len, caption);
102+
ptr = caption;
103+
nCols = String_mbswidth(&ptr, 256, captionWidth);
104+
int captionLen = (int)(ptr - caption);
105+
mvprintw(y, x, "%-*.*s", captionLen + captionWidth - nCols, captionLen, caption);
103106
}
104107
w -= captionWidth;
105108

@@ -125,71 +128,94 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
125128
attrset(CRT_colors[RESET_COLOR]); // Clear the bold attribute
126129
x++;
127130

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-
}
131+
// Calculate the number of terminal columns needed for the meter text.
146132

147-
// If still too large, print the start not the end
148-
startPos = MINIMUM(startPos, w);
149-
}
133+
// The text in the bar is right aligned
150134

151-
assert(startPos >= 0);
152-
assert(startPos <= w);
153-
assert(startPos + w <= RichString_sizeVal(bar));
135+
ptr = this->txtBuffer;
136+
nCols = String_lineBreakWidth(&ptr, sizeof(this->txtBuffer) - 1, w, ' ');
137+
size_t len = (size_t)(ptr - this->txtBuffer);
154138

155-
int blockSizes[10];
139+
RichString_begin(bar);
140+
RichString_appendChr(&bar, 0, ' ', w - nCols);
141+
RichString_appendnWide(&bar, 0, this->txtBuffer, len);
156142

157-
// First draw in the bar[] buffer...
143+
size_t charPos = 0;
158144
int offset = 0;
159145
for (uint8_t i = 0; i < this->curItems; i++) {
146+
if (!(this->total > 0.0)) {
147+
break;
148+
}
149+
if (offset >= w) {
150+
break;
151+
}
152+
160153
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;
154+
if (!isPositive(value)) {
155+
continue;
156+
}
157+
value = MINIMUM(value, this->total);
158+
int blockSize = ceil((value / this->total) * w);
159+
blockSize = MINIMUM(blockSize, w - offset);
160+
if (blockSize < 1) {
161+
continue;
167162
}
168-
int nextOffset = offset + blockSizes[i];
169-
for (int j = offset; j < nextOffset; j++)
170-
if (RichString_getCharVal(bar, startPos + j) == ' ') {
163+
164+
int nextOffset = offset + blockSize;
165+
assert(offset < nextOffset);
166+
167+
size_t startPos = charPos;
168+
while (true) {
169+
if (offset >= nextOffset) {
170+
#ifdef HAVE_LIBNCURSESW
171+
if (!CRT_utf8) {
172+
break;
173+
}
174+
#else
175+
break;
176+
#endif
177+
}
178+
179+
#ifdef HAVE_LIBNCURSESW
180+
wchar_t ch = RichString_getCharVal(bar, charPos);
181+
if (ch == 0)
182+
break;
183+
184+
nCols = wcwidth(ch);
185+
assert(nCols >= 0);
186+
187+
if (offset >= nextOffset && nCols > 0) {
188+
// This break condition is for UTF-8.
189+
break;
190+
}
191+
#else
192+
char ch = RichString_getCharVal(bar, charPos);
193+
nCols = 1;
194+
195+
assert(offset < nextOffset);
196+
#endif
197+
if (ch == ' ') {
171198
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
172199
assert(i < strlen(BarMeterMode_characters));
173-
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
200+
RichString_setChar(&bar, charPos, BarMeterMode_characters[i]);
174201
} else {
175-
RichString_setChar(&bar, startPos + j, '|');
202+
RichString_setChar(&bar, charPos, '|');
176203
}
177204
}
178-
offset = nextOffset;
179-
}
180205

181-
// ...then print the buffer.
182-
offset = 0;
183-
for (uint8_t i = 0; i < this->curItems; i++) {
206+
offset += nCols;
207+
charPos++;
208+
}
209+
184210
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];
211+
RichString_setAttrn(&bar, CRT_colors[attr], startPos, charPos - startPos);
188212
}
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);
213+
214+
len = RichString_sizeVal(bar);
215+
if (charPos < len) {
216+
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], charPos, len - charPos);
192217
}
218+
RichString_printVal(bar, y, x);
193219

194220
RichString_delete(&bar);
195221

0 commit comments

Comments
 (0)