Fix text color multiline handling (#3161)

This commit is contained in:
Totoo
2026-05-08 09:57:06 +02:00
committed by GitHub
parent cf4d245964
commit 5aff5ac277
+36 -7
View File
@@ -393,27 +393,56 @@ void Text::getAccessibilityText(std::string& result) {
void Text::getWidgetName(std::string& result) {
result = "Text";
}
void Text::paint(Painter& painter) {
const auto rect = screen_rect();
auto s = has_focus() ? style().invert() : style();
painter.fill_rectangle(rect, s.background);
const int char_width = s.font.char_width();
const int line_height = s.font.line_height();
auto default_style = has_focus() ? style().invert() : style();
painter.fill_rectangle(rect, default_style.background);
const int char_width = default_style.font.char_width();
const int line_height = default_style.font.line_height();
if (char_width == 0 || line_height == 0) return;
const size_t chars_per_line = rect.width() / char_width;
if (chars_per_line == 0) return;
size_t lines_capacity = rect.height() / line_height;
if (lines_capacity == 0) lines_capacity = 1; // at least one line, even if it overflows vertically
if (lines_capacity == 0) lines_capacity = 1;
auto text_view = std::string_view{text};
size_t current_offset = 0;
// Track the active text color across line breaks
Color active_color = default_style.foreground;
for (size_t line_idx = 0; line_idx < lines_capacity; ++line_idx) {
if (current_offset >= text_view.length()) break;
size_t chunk_len = std::min(chars_per_line, text_view.length() - current_offset);
size_t scan_offset = current_offset;
size_t printable_count = 0;
Color next_color = active_color; // This will hold the color state as we scan the current chunk
// Scan forward to find chunk length AND track color changes
while (scan_offset < text_view.length() && printable_count < chars_per_line) {
if (text_view[scan_offset] == '\x1B') {
scan_offset++;
if (scan_offset < text_view.length()) {
uint8_t color_idx = text_view[scan_offset];
// Mirror the logic from Painter::draw_string
if (color_idx < std::size(term_colors)) {
next_color = term_colors[color_idx];
} else {
next_color = active_color;
}
scan_offset++;
}
} else {
scan_offset++;
printable_count++;
}
}
size_t chunk_len = scan_offset - current_offset;
// Create a temporary style for this line, initialized with the carried-over color
Style line_style = {.font = default_style.font, .background = default_style.background, .foreground = active_color};
painter.draw_string(
rect.location() + Point(0, line_idx * line_height),
s,
line_style,
text_view.substr(current_offset, chunk_len));
current_offset += chunk_len;
// Carry the final color state of this line into the start of the next line
active_color = next_color;
}
}