diff --git a/firmware/common/ui_widget.cpp b/firmware/common/ui_widget.cpp index 2694344de..59c0e07b0 100644 --- a/firmware/common/ui_widget.cpp +++ b/firmware/common/ui_widget.cpp @@ -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; } }