Skip to content

Commit 948a555

Browse files
committed
Wide character support in bar meter text
1 parent ffaf387 commit 948a555

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
@@ -81,16 +81,19 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
8181
assert(x >= 0);
8282
assert(w <= INT_MAX - x);
8383

84+
const char* ptr;
85+
int nCols;
86+
8487
// Draw the caption
8588
const int captionWidth = 3;
8689
const char* caption = Meter_getCaption(this);
8790
if (w >= captionWidth) {
8891
attrset(CRT_colors[METER_TEXT]);
8992

90-
const char* ptr = caption;
91-
int nCols = String_mbswidth(&ptr, 256, captionWidth);
92-
int len = (int)(ptr - caption);
93-
mvprintw(y, x, "%-*.*s", len + captionWidth - nCols, len, caption);
93+
ptr = caption;
94+
nCols = String_mbswidth(&ptr, 256, captionWidth);
95+
int captionLen = (int)(ptr - caption);
96+
mvprintw(y, x, "%-*.*s", captionLen + captionWidth - nCols, captionLen, caption);
9497
}
9598
w -= captionWidth;
9699

@@ -110,71 +113,94 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) {
110113
attrset(CRT_colors[RESET_COLOR]); // Clear the bold attribute
111114
x++;
112115

113-
// The text in the bar is right aligned;
114-
// Pad with maximal spaces and then calculate needed starting position offset
115-
RichString_begin(bar);
116-
RichString_appendChr(&bar, 0, ' ', w);
117-
RichString_appendWide(&bar, 0, this->txtBuffer);
118-
119-
int startPos = RichString_sizeVal(bar) - w;
120-
if (startPos > w) {
121-
// Text is too large for bar
122-
// Truncate meter text at a space character
123-
for (int pos = 2 * w; pos > w; pos--) {
124-
if (RichString_getCharVal(bar, pos) == ' ') {
125-
while (pos > w && RichString_getCharVal(bar, pos - 1) == ' ')
126-
pos--;
127-
startPos = pos - w;
128-
break;
129-
}
130-
}
116+
// Calculate the number of terminal columns needed for the meter text.
131117

132-
// If still too large, print the start not the end
133-
startPos = MINIMUM(startPos, w);
134-
}
118+
// The text in the bar is right aligned
135119

136-
assert(startPos >= 0);
137-
assert(startPos <= w);
138-
assert(startPos + w <= RichString_sizeVal(bar));
120+
ptr = this->txtBuffer;
121+
nCols = String_lineBreakWidth(&ptr, sizeof(this->txtBuffer) - 1, w, ' ');
122+
size_t len = (size_t)(ptr - this->txtBuffer);
139123

140-
int blockSizes[10];
124+
RichString_begin(bar);
125+
RichString_appendChr(&bar, 0, ' ', w - nCols);
126+
RichString_appendnWide(&bar, 0, this->txtBuffer, len);
141127

142-
// First draw in the bar[] buffer...
128+
size_t charPos = 0;
143129
int offset = 0;
144130
for (uint8_t i = 0; i < this->curItems; i++) {
131+
if (!(this->total > 0.0)) {
132+
break;
133+
}
134+
if (offset >= w) {
135+
break;
136+
}
137+
145138
double value = this->values[i];
146-
if (isPositive(value) && this->total > 0.0) {
147-
value = MINIMUM(value, this->total);
148-
blockSizes[i] = ceil((value / this->total) * w);
149-
blockSizes[i] = MINIMUM(blockSizes[i], w - offset);
150-
} else {
151-
blockSizes[i] = 0;
139+
if (!isPositive(value)) {
140+
continue;
141+
}
142+
value = MINIMUM(value, this->total);
143+
int blockSize = ceil((value / this->total) * w);
144+
blockSize = MINIMUM(blockSize, w - offset);
145+
if (blockSize < 1) {
146+
continue;
152147
}
153-
int nextOffset = offset + blockSizes[i];
154-
for (int j = offset; j < nextOffset; j++)
155-
if (RichString_getCharVal(bar, startPos + j) == ' ') {
148+
149+
int nextOffset = offset + blockSize;
150+
assert(offset < nextOffset);
151+
152+
size_t startPos = charPos;
153+
while (true) {
154+
if (offset >= nextOffset) {
155+
#ifdef HAVE_LIBNCURSESW
156+
if (!CRT_utf8) {
157+
break;
158+
}
159+
#else
160+
break;
161+
#endif
162+
}
163+
164+
#ifdef HAVE_LIBNCURSESW
165+
wchar_t ch = RichString_getCharVal(bar, charPos);
166+
if (ch == 0)
167+
break;
168+
169+
nCols = wcwidth(ch);
170+
assert(nCols >= 0);
171+
172+
if (offset >= nextOffset && nCols > 0) {
173+
// This break condition is for UTF-8.
174+
break;
175+
}
176+
#else
177+
char ch = RichString_getCharVal(bar, charPos);
178+
nCols = 1;
179+
180+
assert(offset < nextOffset);
181+
#endif
182+
if (ch == ' ') {
156183
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
157184
assert(i < strlen(BarMeterMode_characters));
158-
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
185+
RichString_setChar(&bar, charPos, BarMeterMode_characters[i]);
159186
} else {
160-
RichString_setChar(&bar, startPos + j, '|');
187+
RichString_setChar(&bar, charPos, '|');
161188
}
162189
}
163-
offset = nextOffset;
164-
}
165190

166-
// ...then print the buffer.
167-
offset = 0;
168-
for (uint8_t i = 0; i < this->curItems; i++) {
191+
offset += nCols;
192+
charPos++;
193+
}
194+
169195
int attr = this->curAttributes ? this->curAttributes[i] : Meter_attributes(this)[i];
170-
RichString_setAttrn(&bar, CRT_colors[attr], startPos + offset, blockSizes[i]);
171-
RichString_printoffnVal(bar, y, x + offset, startPos + offset, blockSizes[i]);
172-
offset += blockSizes[i];
196+
RichString_setAttrn(&bar, CRT_colors[attr], startPos, charPos - startPos);
173197
}
174-
if (offset < w) {
175-
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], startPos + offset, w - offset);
176-
RichString_printoffnVal(bar, y, x + offset, startPos + offset, w - offset);
198+
199+
len = RichString_sizeVal(bar);
200+
if (charPos < len) {
201+
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], charPos, len - charPos);
177202
}
203+
RichString_printVal(bar, y, x);
178204

179205
RichString_delete(&bar);
180206

0 commit comments

Comments
 (0)