diff --git a/Libraries/LibGUI/GTextEditor.cpp b/Libraries/LibGUI/GTextEditor.cpp index e6bfd12ec6a..151f1c175b6 100644 --- a/Libraries/LibGUI/GTextEditor.cpp +++ b/Libraries/LibGUI/GTextEditor.cpp @@ -364,7 +364,27 @@ void GTextEditor::paint_event(GPaintEvent& event) #ifdef DEBUG_GTEXTEDITOR painter.draw_rect(visual_line_rect, Color::Cyan); #endif - painter.draw_text(visual_line_rect, visual_line_text, m_text_alignment, Color::Black); + if (m_spans.is_empty()) { + // Fast-path for plain text + painter.draw_text(visual_line_rect, visual_line_text, m_text_alignment, Color::Black); + } else { + int advance = font().glyph_width(' ') + font().glyph_spacing(); + Rect character_rect = { visual_line_rect.location(), { font().glyph_width(' '), line_height() } }; + for (int i = 0; i < visual_line_text.length(); ++i) { + Color color; + int physical_line = line_index; + int physical_column = start_of_visual_line + i; + // FIXME: This is *horribly* inefficient. + for (auto& span : m_spans) { + if (!span.contains(GTextPosition(physical_line, physical_column))) + continue; + color = span.color; + break; + } + painter.draw_text(character_rect, visual_line_text.substring_view(i, 1), m_text_alignment, color); + character_rect.move_by(advance, 0); + } + } bool physical_line_has_selection = has_selection && line_index >= selection.start().line() && line_index <= selection.end().line(); if (physical_line_has_selection) { diff --git a/Libraries/LibGUI/GTextEditor.h b/Libraries/LibGUI/GTextEditor.h index 756f0fedb20..3952c038814 100644 --- a/Libraries/LibGUI/GTextEditor.h +++ b/Libraries/LibGUI/GTextEditor.h @@ -167,6 +167,26 @@ public: void set_cursor(int line, int column); void set_cursor(const GTextPosition&); + struct Span { + bool contains(const GTextPosition& position) const + { + if (!(position.line() > start.line() || (position.line() == start.line() && position.column() >= start.column()))) + return false; + if (!(position.line() < end.line() || (position.line() == end.line() && position.column() <= end.column()))) + return false; + return true; + } + + GTextPosition start; + GTextPosition end; + Color color; + }; + + void set_spans(const Vector& spans) + { + m_spans = spans; + } + protected: GTextEditor(Type, GWidget* parent); @@ -187,7 +207,6 @@ protected: virtual void resize_event(GResizeEvent&) override; private: - void create_actions(); void paint_ruler(Painter&); void update_content_size(); @@ -274,6 +293,8 @@ private: RefPtr m_delete_action; CElapsedTimer m_triple_click_timer; NonnullRefPtrVector m_custom_context_menu_actions; + + Vector m_spans; }; inline const LogStream& operator<<(const LogStream& stream, const GTextPosition& value)