From 7b2dd7e116c81b586d793a2b7b98100fe28388d7 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 29 Dec 2019 00:47:49 +0100 Subject: [PATCH] LibDraw+LibGUI: Allow changing individual colors in a Palette Palette is now a value wrapper around a NonnullRefPtr. A new function, set_color(ColorRole, Color) implements a simple copy-on-write mechanism so that we're sharing the PaletteImpl in the common case, but allowing you to create custom palettes if you like, by getting a GWidget's palette, modifying it, and then assigning the modified palette to the widget via GWidget::set_palette(). Use this to make PaintBrush show its palette colors once again. Fixes #943. --- Applications/PaintBrush/ColorDialog.cpp | 8 +++-- Applications/PaintBrush/PaintableWidget.cpp | 4 +++ Applications/PaintBrush/PaletteWidget.cpp | 16 ++++++--- Libraries/LibDraw/Palette.cpp | 30 ++++++++++++++--- Libraries/LibDraw/Palette.h | 36 ++++++++++++++++----- Libraries/LibDraw/SystemTheme.h | 1 + Libraries/LibGUI/GApplication.cpp | 4 +-- Libraries/LibGUI/GApplication.h | 7 ++-- Libraries/LibGUI/GWidget.cpp | 4 +-- Libraries/LibGUI/GWidget.h | 6 ++-- Servers/WindowServer/WSButton.cpp | 2 +- Servers/WindowServer/WSMenu.cpp | 2 +- Servers/WindowServer/WSMenuManager.cpp | 2 +- Servers/WindowServer/WSWindowFrame.cpp | 2 +- Servers/WindowServer/WSWindowManager.cpp | 4 +-- Servers/WindowServer/WSWindowManager.h | 6 ++-- Servers/WindowServer/WSWindowSwitcher.cpp | 2 +- Servers/WindowServer/main.cpp | 2 +- 18 files changed, 98 insertions(+), 40 deletions(-) diff --git a/Applications/PaintBrush/ColorDialog.cpp b/Applications/PaintBrush/ColorDialog.cpp index 24322ee955..404b65d8a1 100644 --- a/Applications/PaintBrush/ColorDialog.cpp +++ b/Applications/PaintBrush/ColorDialog.cpp @@ -36,8 +36,10 @@ void ColorDialog::build() }; m_preview_widget = GFrame::construct(right_vertical_container); - m_preview_widget->set_background_color(m_color); + auto pal = m_preview_widget->palette(); + pal.set_color(ColorRole::Background, m_color); m_preview_widget->set_fill_with_background_color(true); + m_preview_widget->set_palette(pal); right_vertical_container->layout()->add_spacer(); auto cancel_button = GButton::construct("Cancel", right_vertical_container); cancel_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); @@ -68,7 +70,9 @@ void ColorDialog::build() if (component == Blue) m_color.set_blue(value); - m_preview_widget->set_background_color(m_color); + auto pal = m_preview_widget->palette(); + pal.set_color(ColorRole::Background, m_color); + m_preview_widget->set_palette(pal); m_preview_widget->update(); }; return spinbox; diff --git a/Applications/PaintBrush/PaintableWidget.cpp b/Applications/PaintBrush/PaintableWidget.cpp index 41a523dd26..7d553346c3 100644 --- a/Applications/PaintBrush/PaintableWidget.cpp +++ b/Applications/PaintBrush/PaintableWidget.cpp @@ -1,6 +1,7 @@ #include "PaintableWidget.h" #include "Tool.h" #include +#include #include static PaintableWidget* s_the; @@ -16,6 +17,9 @@ PaintableWidget::PaintableWidget(GWidget* parent) ASSERT(!s_the); s_the = this; set_fill_with_background_color(true); + auto pal = palette(); + pal.set_color(ColorRole::Window, Color::MidGray); + set_palette(pal); set_background_color(Color::MidGray); m_bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, { 600, 400 }); m_bitmap->fill(Color::White); diff --git a/Applications/PaintBrush/PaletteWidget.cpp b/Applications/PaintBrush/PaletteWidget.cpp index a081f26a7f..739f18eccf 100644 --- a/Applications/PaintBrush/PaletteWidget.cpp +++ b/Applications/PaintBrush/PaletteWidget.cpp @@ -26,7 +26,9 @@ public: auto dialog = ColorDialog::construct(m_color, window()); if (dialog->exec() == GDialog::ExecOK) { m_color = dialog->color(); - set_background_color(m_color); + auto pal = palette(); + pal.set_color(ColorRole::Background, m_color); + set_palette(pal); update(); } return; @@ -97,7 +99,9 @@ PaletteWidget::PaletteWidget(PaintableWidget& paintable_widget, GWidget* parent) auto add_color_widget = [&](GWidget* container, Color color) { auto color_widget = ColorWidget::construct(color, *this, container); color_widget->set_fill_with_background_color(true); - color_widget->set_background_color(color); + auto pal = color_widget->palette(); + pal.set_color(ColorRole::Background, color); + color_widget->set_palette(pal); }; add_color_widget(top_color_container, Color::from_rgb(0x000000)); @@ -138,13 +142,17 @@ PaletteWidget::~PaletteWidget() void PaletteWidget::set_primary_color(Color color) { m_paintable_widget.set_primary_color(color); - m_primary_color_widget->set_background_color(color); + auto pal = m_primary_color_widget->palette(); + pal.set_color(ColorRole::Background, color); + m_primary_color_widget->set_palette(pal); m_primary_color_widget->update(); } void PaletteWidget::set_secondary_color(Color color) { m_paintable_widget.set_secondary_color(color); - m_secondary_color_widget->set_background_color(color); + auto pal = m_secondary_color_widget->palette(); + pal.set_color(ColorRole::Background, color); + m_secondary_color_widget->set_palette(pal); m_secondary_color_widget->update(); } diff --git a/Libraries/LibDraw/Palette.cpp b/Libraries/LibDraw/Palette.cpp index 2570dfacfb..f5b0237928 100644 --- a/Libraries/LibDraw/Palette.cpp +++ b/Libraries/LibDraw/Palette.cpp @@ -1,26 +1,46 @@ #include -NonnullRefPtr Palette::create_with_shared_buffer(SharedBuffer& buffer) +NonnullRefPtr PaletteImpl::create_with_shared_buffer(SharedBuffer& buffer) { - return adopt(*new Palette(buffer)); + return adopt(*new PaletteImpl(buffer)); } -Palette::Palette(SharedBuffer& buffer) +PaletteImpl::PaletteImpl(SharedBuffer& buffer) : m_theme_buffer(buffer) { } +Palette::Palette(const PaletteImpl& impl) + : m_impl(impl) +{ +} + Palette::~Palette() { } -const SystemTheme& Palette::theme() const +const SystemTheme& PaletteImpl::theme() const { return *(const SystemTheme*)m_theme_buffer->data(); } -Color Palette::color(ColorRole role) const +Color PaletteImpl::color(ColorRole role) const { ASSERT((int)role < (int)ColorRole::__Count); return theme().color[(int)role]; } + +NonnullRefPtr PaletteImpl::clone() const +{ + auto new_theme_buffer = SharedBuffer::create_with_size(m_theme_buffer->size()); + memcpy(new_theme_buffer->data(), m_theme_buffer->data(), m_theme_buffer->size()); + return adopt(*new PaletteImpl(*new_theme_buffer)); +} + +void Palette::set_color(ColorRole role, Color color) +{ + if (m_impl->ref_count() != 1) + m_impl = m_impl->clone(); + auto& theme = const_cast(impl().theme()); + theme.color[(int)role] = color; +} diff --git a/Libraries/LibDraw/Palette.h b/Libraries/LibDraw/Palette.h index 4ee5816543..af04aef659 100644 --- a/Libraries/LibDraw/Palette.h +++ b/Libraries/LibDraw/Palette.h @@ -1,13 +1,33 @@ #pragma once #include +#include #include class GApplication; -class Palette : public RefCounted { +class PaletteImpl : public RefCounted { + AK_MAKE_NONCOPYABLE(PaletteImpl) + AK_MAKE_NONMOVABLE(PaletteImpl) public: - static NonnullRefPtr create_with_shared_buffer(SharedBuffer&); + static NonnullRefPtr create_with_shared_buffer(SharedBuffer&); + NonnullRefPtr clone() const; + + Color color(ColorRole) const; + const SystemTheme& theme() const; + + void replace_internal_buffer(Badge, SharedBuffer& buffer) { m_theme_buffer = buffer; } + +private: + explicit PaletteImpl(SharedBuffer&); + + RefPtr m_theme_buffer; +}; + +class Palette { + +public: + explicit Palette(const PaletteImpl&); ~Palette(); Color window() const { return color(ColorRole::Window); } @@ -41,14 +61,14 @@ public: Color threed_shadow2() const { return color(ColorRole::ThreedShadow2); } Color hover_highlight() const { return color(ColorRole::ThreedHighlight); } - Color color(ColorRole) const; + Color color(ColorRole role) const { return m_impl->color(role); } + void set_color(ColorRole, Color); - const SystemTheme& theme() const; + const SystemTheme& theme() const { return m_impl->theme(); } - void replace_internal_buffer(Badge, SharedBuffer& buffer) { m_theme_buffer = buffer; } + PaletteImpl& impl() { return *m_impl; } + const PaletteImpl& impl() const { return *m_impl; } private: - explicit Palette(SharedBuffer&); - - RefPtr m_theme_buffer; + NonnullRefPtr m_impl; }; diff --git a/Libraries/LibDraw/SystemTheme.h b/Libraries/LibDraw/SystemTheme.h index b1428e7594..b02b9ecc44 100644 --- a/Libraries/LibDraw/SystemTheme.h +++ b/Libraries/LibDraw/SystemTheme.h @@ -39,6 +39,7 @@ enum class ColorRole { __Count, + Background = Window, DisabledText = ThreedShadow1, }; diff --git a/Libraries/LibGUI/GApplication.cpp b/Libraries/LibGUI/GApplication.cpp index 5635dafc8f..17aed99289 100644 --- a/Libraries/LibGUI/GApplication.cpp +++ b/Libraries/LibGUI/GApplication.cpp @@ -147,7 +147,7 @@ void GApplication::did_delete_last_window(Badge) void GApplication::set_system_palette(SharedBuffer& buffer) { if (!m_system_palette) - m_system_palette = Palette::create_with_shared_buffer(buffer); + m_system_palette = PaletteImpl::create_with_shared_buffer(buffer); else m_system_palette->replace_internal_buffer({}, buffer); @@ -157,5 +157,5 @@ void GApplication::set_system_palette(SharedBuffer& buffer) void GApplication::set_palette(const Palette& palette) { - m_palette = palette; + m_palette = palette.impl(); } diff --git a/Libraries/LibGUI/GApplication.h b/Libraries/LibGUI/GApplication.h index 539ebef04f..9194a32976 100644 --- a/Libraries/LibGUI/GApplication.h +++ b/Libraries/LibGUI/GApplication.h @@ -3,6 +3,7 @@ #include #include #include +#include #include class CEventLoop; @@ -42,7 +43,7 @@ public: const String& invoked_as() const { return m_invoked_as; } const Vector& args() const { return m_args; } - const Palette& palette() const { return *m_palette; } + Palette palette() const { return Palette(*m_palette); } void set_palette(const Palette&); void set_system_palette(SharedBuffer&); @@ -50,8 +51,8 @@ public: private: OwnPtr m_event_loop; OwnPtr m_menubar; - RefPtr m_palette; - RefPtr m_system_palette; + RefPtr m_palette; + RefPtr m_system_palette; HashMap m_global_shortcut_actions; class TooltipWindow; TooltipWindow* m_tooltip_window { nullptr }; diff --git a/Libraries/LibGUI/GWidget.cpp b/Libraries/LibGUI/GWidget.cpp index 71c472c0f2..d2a88bc966 100644 --- a/Libraries/LibGUI/GWidget.cpp +++ b/Libraries/LibGUI/GWidget.cpp @@ -67,7 +67,7 @@ const GWidgetClassRegistration* GWidgetClassRegistration::find(const String& cla GWidget::GWidget(GWidget* parent) : CObject(parent, true) , m_font(Font::default_font()) - , m_palette(GApplication::the().palette()) + , m_palette(GApplication::the().palette().impl()) { } @@ -695,5 +695,5 @@ Vector GWidget::child_widgets() const void GWidget::set_palette(const Palette& palette) { - m_palette = palette; + m_palette = palette.impl(); } diff --git a/Libraries/LibGUI/GWidget.h b/Libraries/LibGUI/GWidget.h index 9ff587ae79..9ccf9398f3 100644 --- a/Libraries/LibGUI/GWidget.h +++ b/Libraries/LibGUI/GWidget.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,6 @@ class GLayout; class GMenu; class GWindow; class GraphicsBitmap; -class Palette; enum class SizePolicy { Fixed, @@ -237,7 +237,7 @@ public: void do_layout(); - const Palette& palette() const { return *m_palette; } + Palette palette() const { return Palette(*m_palette); } void set_palette(const Palette&); protected: @@ -301,7 +301,7 @@ private: HashMap m_local_shortcut_actions; - NonnullRefPtr m_palette; + NonnullRefPtr m_palette; }; template<> diff --git a/Servers/WindowServer/WSButton.cpp b/Servers/WindowServer/WSButton.cpp index 0c6d749d41..507add13b4 100644 --- a/Servers/WindowServer/WSButton.cpp +++ b/Servers/WindowServer/WSButton.cpp @@ -18,7 +18,7 @@ WSButton::~WSButton() void WSButton::paint(Painter& painter) { - auto& palette = WSWindowManager::the().palette(); + auto palette = WSWindowManager::the().palette(); PainterStateSaver saver(painter); painter.translate(relative_rect().location()); StylePainter::paint_button(painter, rect(), palette, ButtonStyle::Normal, m_pressed, m_hovered); diff --git a/Servers/WindowServer/WSMenu.cpp b/Servers/WindowServer/WSMenu.cpp index 3711e5949d..d6de3f6852 100644 --- a/Servers/WindowServer/WSMenu.cpp +++ b/Servers/WindowServer/WSMenu.cpp @@ -126,7 +126,7 @@ WSWindow& WSMenu::ensure_menu_window() void WSMenu::draw() { - auto& palette = WSWindowManager::the().palette(); + auto palette = WSWindowManager::the().palette(); m_theme_index_at_last_paint = WSWindowManager::the().theme_index(); ASSERT(menu_window()); diff --git a/Servers/WindowServer/WSMenuManager.cpp b/Servers/WindowServer/WSMenuManager.cpp index 3eb0fa67c7..f80a143ecb 100644 --- a/Servers/WindowServer/WSMenuManager.cpp +++ b/Servers/WindowServer/WSMenuManager.cpp @@ -33,7 +33,7 @@ bool WSMenuManager::is_open(const WSMenu& menu) const void WSMenuManager::draw() { auto& wm = WSWindowManager::the(); - auto& palette = wm.palette(); + auto palette = wm.palette(); auto menubar_rect = this->menubar_rect(); if (m_needs_window_resize) { diff --git a/Servers/WindowServer/WSWindowFrame.cpp b/Servers/WindowServer/WSWindowFrame.cpp index da968a28a1..3fd3ae86d6 100644 --- a/Servers/WindowServer/WSWindowFrame.cpp +++ b/Servers/WindowServer/WSWindowFrame.cpp @@ -153,7 +153,7 @@ void WSWindowFrame::paint(Painter& painter) if (m_window.type() != WSWindowType::Normal) return; - auto& palette = WSWindowManager::the().palette(); + auto palette = WSWindowManager::the().palette(); auto& window = m_window; auto titlebar_rect = title_bar_rect(); diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 37e0e7fe7b..33b468fb26 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -42,7 +42,7 @@ WSWindowManager& WSWindowManager::the() return *s_the; } -WSWindowManager::WSWindowManager(const Palette& palette) +WSWindowManager::WSWindowManager(const PaletteImpl& palette) : m_palette(palette) { s_the = this; @@ -133,7 +133,7 @@ WSWindowManager::WSWindowManager(const Palette& palette) auto new_theme = load_system_theme(theme.path); ASSERT(new_theme); set_system_theme(*new_theme); - m_palette = Palette::create_with_shared_buffer(*new_theme); + m_palette = PaletteImpl::create_with_shared_buffer(*new_theme); HashTable notified_clients; for_each_window([&](WSWindow& window) { if (window.client()) { diff --git a/Servers/WindowServer/WSWindowManager.h b/Servers/WindowServer/WSWindowManager.h index 0600b88fd8..8a6f1324cf 100644 --- a/Servers/WindowServer/WSWindowManager.h +++ b/Servers/WindowServer/WSWindowManager.h @@ -51,10 +51,10 @@ class WSWindowManager : public CObject { public: static WSWindowManager& the(); - explicit WSWindowManager(const Palette&); + explicit WSWindowManager(const PaletteImpl&); virtual ~WSWindowManager() override; - const Palette& palette() const { return *m_palette; } + Palette palette() const { return Palette(*m_palette); } RefPtr wm_config() const { @@ -286,7 +286,7 @@ private: WeakPtr m_cursor_tracking_button; WeakPtr m_hovered_button; - NonnullRefPtr m_palette; + NonnullRefPtr m_palette; RefPtr m_wm_config; diff --git a/Servers/WindowServer/WSWindowSwitcher.cpp b/Servers/WindowServer/WSWindowSwitcher.cpp index 2c6622a90d..6436bea5a5 100644 --- a/Servers/WindowServer/WSWindowSwitcher.cpp +++ b/Servers/WindowServer/WSWindowSwitcher.cpp @@ -71,7 +71,7 @@ void WSWindowSwitcher::on_key_event(const WSKeyEvent& event) void WSWindowSwitcher::draw() { - auto& palette = WSWindowManager::the().palette(); + auto palette = WSWindowManager::the().palette(); Painter painter(*m_switcher_window->backing_store()); painter.fill_rect({ {}, m_rect.size() }, palette.window()); painter.draw_rect({ {}, m_rect.size() }, palette.threed_shadow2()); diff --git a/Servers/WindowServer/main.cpp b/Servers/WindowServer/main.cpp index c12a53d496..1f6849f8b1 100644 --- a/Servers/WindowServer/main.cpp +++ b/Servers/WindowServer/main.cpp @@ -26,7 +26,7 @@ int main(int, char**) auto theme = load_system_theme(String::format("/res/themes/%s.ini", theme_name.characters())); ASSERT(theme); set_system_theme(*theme); - auto palette = Palette::create_with_shared_buffer(*theme); + auto palette = PaletteImpl::create_with_shared_buffer(*theme); WSEventLoop loop;