Skip to content

Commit 801948a

Browse files
committed
Wide character support in bar meter text
1 parent 073e58a commit 801948a

1 file changed

Lines changed: 75 additions & 50 deletions

File tree

Meter.c

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,17 @@ 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);
93+
ptr = caption;
94+
nCols = String_mbswidth(&ptr, 256, captionWidth);
9295
int len = (int)(ptr - caption);
9396
mvprintw(y, x, "%-*.*s", len + captionWidth - nCols, len, caption);
9497
}
@@ -110,71 +113,93 @@ 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, ' ');
139122

140-
int blockSizes[10];
123+
RichString_begin(bar);
124+
RichString_appendChr(&bar, 0, ' ', w - nCols);
125+
RichString_appendnWide(&bar, 0, this->txtBuffer, (int)(ptr - this->txtbuffer));
141126

142-
// First draw in the bar[] buffer...
127+
size_t charPos = 0;
143128
int offset = 0;
144129
for (uint8_t i = 0; i < this->curItems; i++) {
130+
if (!(this->total > 0.0)) {
131+
break;
132+
}
133+
if (offset >= w) {
134+
break;
135+
}
136+
145137
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;
138+
if (!isPositive(value)) {
139+
continue;
152140
}
153-
int nextOffset = offset + blockSizes[i];
154-
for (int j = offset; j < nextOffset; j++)
155-
if (RichString_getCharVal(bar, startPos + j) == ' ') {
141+
value = MINIMUM(value, this->total);
142+
int blockSize = ceil((value / this->total) * w);
143+
blockSize = MINIMUM(blockSize, w - offset);
144+
if (blockSize < 1) {
145+
continue;
146+
}
147+
148+
int nextOffset = offset + blockSize;
149+
assert(offset < nextOffset);
150+
151+
size_t startPos = charPos;
152+
while (true) {
153+
if (offset >= nextOffset) {
154+
#ifdef HAVE_LIBNCURSESW
155+
if (!CRT_utf8) {
156+
break;
157+
}
158+
#else
159+
break;
160+
#endif
161+
}
162+
163+
#ifdef HAVE_LIBNCURSESW
164+
wchar_t ch = RichString_getCharVal(bar, charPos);
165+
if (ch == 0)
166+
break;
167+
168+
nCols = wcwidth(ch);
169+
assert(nCols >= 0);
170+
171+
if (offset >= nextOffset && nCols > 0) {
172+
// This break condition is for UTF-8.
173+
break;
174+
}
175+
#else
176+
char ch = RichString_getCharVal(bar, charPos);
177+
nCols = 1;
178+
179+
assert(offset < nextOffset);
180+
#endif
181+
if (ch == ' ') {
156182
if (CRT_colorScheme == COLORSCHEME_MONOCHROME) {
157183
assert(i < strlen(BarMeterMode_characters));
158-
RichString_setChar(&bar, startPos + j, BarMeterMode_characters[i]);
184+
RichString_setChar(&bar, charPos, BarMeterMode_characters[i]);
159185
} else {
160-
RichString_setChar(&bar, startPos + j, '|');
186+
RichString_setChar(&bar, charPos, '|');
161187
}
162188
}
163-
offset = nextOffset;
164-
}
165189

166-
// ...then print the buffer.
167-
offset = 0;
168-
for (uint8_t i = 0; i < this->curItems; i++) {
190+
offset += nCols;
191+
charPos++;
192+
}
193+
169194
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];
195+
RichString_setAttrn(&bar, CRT_colors[attr], startPos, charPos - startPos);
173196
}
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);
197+
198+
len = RichString_sizeVal(bar);
199+
if (charPos < len) {
200+
RichString_setAttrn(&bar, CRT_colors[BAR_SHADOW], charPos, len - charPos);
177201
}
202+
RichString_printVal(bar, y, x);
178203

179204
RichString_delete(&bar);
180205

0 commit comments

Comments
 (0)