Skip to content

Commit 58d44cd

Browse files
committed
Wide character support in bar meter text
1 parent 591c567 commit 58d44cd

File tree

1 file changed

+75
-53
lines changed

1 file changed

+75
-53
lines changed

Meter.c

Lines changed: 75 additions & 53 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,90 @@ 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+
if (offset >= w)
149+
break;
150+
160151
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) == ' ') {
152+
if (!isPositive(value))
153+
continue;
154+
value = MINIMUM(value, this->total);
155+
int blockSize = ceil((value / this->total) * w);
156+
blockSize = MINIMUM(blockSize, w - offset);
157+
if (blockSize < 1)
158+
continue;
159+
160+
int nextOffset = offset + blockSize;
161+
assert(offset < nextOffset);
162+
163+
size_t startPos = charPos;
164+
while (true) {
165+
#ifdef HAVE_LIBNCURSESW
166+
if (offset >= nextOffset && !CRT_utf8) {
167+
break;
168+
}
169+
#else
170+
if (offset >= nextOffset) {
171+
break;
172+
}
173+
#endif
174+
175+
#ifdef HAVE_LIBNCURSESW
176+
wchar_t ch = RichString_getCharVal(bar, charPos);
177+
if (ch == 0)
178+
break;
179+
180+
nCols = wcwidth(ch);
181+
assert(nCols >= 0);
182+
183+
if (offset >= nextOffset && nCols > 0) {
184+
// This break condition is for UTF-8.
185+
break;
186+
}
187+
#else
188+
char ch = RichString_getCharVal(bar, charPos);
189+
nCols = 1;
190+
191+
assert(offset < nextOffset);
192+
#endif
193+
if (ch == ' ') {
171194
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
172195
assert(i < strlen(BarMeterMode_characters));
173-
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
196+
RichString_setChar(&bar, charPos, BarMeterMode_characters[i]);
174197
} else {
175-
RichString_setChar(&bar, startPos + j, '|');
198+
RichString_setChar(&bar, charPos, '|');
176199
}
177200
}
178-
offset = nextOffset;
179-
}
180201

181-
// ...then print the buffer.
182-
offset = 0;
183-
for (uint8_t i = 0; i < this->curItems; i++) {
202+
offset += nCols;
203+
charPos++;
204+
}
205+
184206
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];
207+
RichString_setAttrn(&bar, CRT_colors[attr], startPos, charPos - startPos);
188208
}
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);
209+
210+
len = RichString_sizeVal(bar);
211+
if (charPos < len) {
212+
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], charPos, len - charPos);
192213
}
214+
RichString_printVal(bar, y, x);
193215

194216
RichString_delete(&bar);
195217

0 commit comments

Comments
 (0)