From 014d8254726aa1fbaaef11649c773420bf9e4197 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 27 Jul 2022 16:46:21 +0100 Subject: [PATCH] LibGUI: Allow GlyphMapWidget to highlight modified glyphs This makes modifications in FontEditor more visible, both so you know what you've changed, and for taking a handy "here's what's changed" screenshot for a font PR. :^) The background color for new glyphs is green, modified glyphs is blue, and deleted glyphs is red. The changes persist until you load a new font file, so you can continue saving your work as you go and still be able to take a convenient screenshot at the end. I didn't feel like this one use was enough to add 3 new color roles to themes, so to make this look decent on dark themes, it detects if the theme is marked as dark, and uses darker colors for the highlights which look nice with a light text color. --- Userland/Libraries/LibGUI/GlyphMapWidget.cpp | 61 +++++++++++++++++++- Userland/Libraries/LibGUI/GlyphMapWidget.h | 9 +++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibGUI/GlyphMapWidget.cpp b/Userland/Libraries/LibGUI/GlyphMapWidget.cpp index 2c657e9979..d0ca319507 100644 --- a/Userland/Libraries/LibGUI/GlyphMapWidget.cpp +++ b/Userland/Libraries/LibGUI/GlyphMapWidget.cpp @@ -113,6 +113,7 @@ Gfx::IntRect GlyphMapWidget::get_outer_rect(int glyph) const void GlyphMapWidget::update_glyph(int glyph) { + set_glyph_modified(glyph, true); update(get_outer_rect(glyph)); } @@ -146,13 +147,38 @@ void GlyphMapWidget::paint_event(PaintEvent& event) else if (auto* emoji = Gfx::Emoji::emoji_for_code_point(glyph)) painter.draw_emoji(inner_rect.location(), *emoji, font()); } else if (font().contains_glyph(glyph)) { - painter.fill_rect(outer_rect, palette().base()); + if (m_highlight_modifications && m_modified_glyphs.contains(glyph)) { + if (m_original_font->contains_glyph(glyph)) { + // Modified + if (palette().is_dark()) + painter.fill_rect(outer_rect, Gfx::Color { 0, 65, 159 }); + else + painter.fill_rect(outer_rect, Gfx::Color { 138, 185, 252 }); + } else { + // Newly created + if (palette().is_dark()) + painter.fill_rect(outer_rect, Gfx::Color { 8, 127, 0 }); + else + painter.fill_rect(outer_rect, Gfx::Color { 133, 251, 116 }); + } + } else { + painter.fill_rect(outer_rect, palette().base()); + } painter.draw_glyph(inner_rect.location(), glyph, palette().base_text()); } else if (auto* emoji = Gfx::Emoji::emoji_for_code_point(glyph)) { painter.fill_rect(outer_rect, Gfx::Color { 255, 150, 150 }); painter.draw_emoji(inner_rect.location(), *emoji, font()); - } else - painter.fill_rect(outer_rect, palette().window()); + } else { + if (m_highlight_modifications && m_original_font->contains_glyph(glyph)) { + // Deleted + if (palette().is_dark()) + painter.fill_rect(outer_rect, Gfx::Color { 127, 0, 0 }); + else + painter.fill_rect(outer_rect, Gfx::Color { 255, 150, 150 }); + } else { + painter.fill_rect(outer_rect, palette().window()); + } + } } painter.draw_focus_rect(get_outer_rect(m_active_glyph), palette().focus_outline()); } @@ -401,4 +427,33 @@ void GlyphMapWidget::set_active_range(Unicode::CodePointRange range) update(); } +void GlyphMapWidget::set_highlight_modifications(bool highlight_modifications) +{ + if (m_highlight_modifications == highlight_modifications) + return; + + m_highlight_modifications = highlight_modifications; + update(); +} + +void GlyphMapWidget::set_glyph_modified(u32 glyph, bool modified) +{ + if (modified) + m_modified_glyphs.set(glyph); + else + m_modified_glyphs.remove(glyph); +} + +bool GlyphMapWidget::glyph_is_modified(u32 glyph) +{ + return m_modified_glyphs.contains(glyph); +} + +void GlyphMapWidget::set_font(Gfx::Font const& font) +{ + AbstractScrollableWidget::set_font(font); + m_original_font = font.clone(); + m_modified_glyphs.clear(); +} + } diff --git a/Userland/Libraries/LibGUI/GlyphMapWidget.h b/Userland/Libraries/LibGUI/GlyphMapWidget.h index 31f8b71da3..82634f5733 100644 --- a/Userland/Libraries/LibGUI/GlyphMapWidget.h +++ b/Userland/Libraries/LibGUI/GlyphMapWidget.h @@ -21,6 +21,8 @@ class GlyphMapWidget final : public AbstractScrollableWidget { public: virtual ~GlyphMapWidget() override = default; + void set_font(Gfx::Font const&); + class Selection { public: Selection() = default; @@ -60,6 +62,10 @@ public: void scroll_to_glyph(int); void update_glyph(int); + void set_highlight_modifications(bool); + void set_glyph_modified(u32 glyph, bool modified); + bool glyph_is_modified(u32 glyph); + void select_previous_existing_glyph(); void select_next_existing_glyph(); @@ -88,6 +94,7 @@ private: void recalculate_content_size(); + RefPtr m_original_font; int m_glyph_count { 0x110000 }; int m_columns { 0 }; int m_rows { 0 }; @@ -97,6 +104,8 @@ private: int m_active_glyph { 0 }; int m_visible_glyphs { 0 }; bool m_in_drag_select { false }; + bool m_highlight_modifications { false }; + HashTable m_modified_glyphs; Unicode::CodePointRange m_active_range { 0x0000, 0x10FFFF }; RefPtr m_automatic_selection_scroll_timer; Gfx::IntPoint m_last_mousemove_position;