From 253eb5c6d74336b653a1ca267fd00efde3092aa3 Mon Sep 17 00:00:00 2001 From: Mustafa Quraish Date: Sat, 4 Sep 2021 00:37:39 -0400 Subject: [PATCH] ColorPicker: Add ability to select a color on the screen This commit adds a `ColorSelectOverlay` class, and uses it to allow the user to pick a color from the screen. The API for `ColorSelectOverlay` is inspired from the `SelectableOverlay` in `Utilities/shot.cpp`. In particular, it opens up it's own window, so that we can have control over the cursor over the whole screen. There's one thing notably different: In addition to returning the final selected color from the `exec()` function, it also provides an `on_color_changed()` hook, which can be used to (optionally) get live updated as the mouse is moving around. This is a bit odd, but allows us to use the preview widget of the color picker to see the current color under the mouse (which will be selected upon clicking). When trying to select the color from text / other small elements, this is very useful. --- Userland/Libraries/LibGUI/ColorPicker.cpp | 75 ++++++++++++++++++++++- Userland/Libraries/LibGUI/ColorPicker.h | 2 + 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibGUI/ColorPicker.cpp b/Userland/Libraries/LibGUI/ColorPicker.cpp index 50be4baaa79..d4e3a0d1ce6 100644 --- a/Userland/Libraries/LibGUI/ColorPicker.cpp +++ b/Userland/Libraries/LibGUI/ColorPicker.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace GUI { @@ -125,6 +126,60 @@ private: RefPtr m_color_slider; }; +class ColorSelectOverlay final : public Widget { + C_OBJECT(ColorSelectOverlay) +public: + ColorSelectOverlay() + { + set_override_cursor(Gfx::StandardCursor::Eyedropper); + } + + Optional exec() + { + m_event_loop = make(); + + // FIXME: Allow creation of fully transparent windows without a backing store. + auto window = Window::construct(); + window->set_main_widget(this); + window->set_has_alpha_channel(true); + window->set_background_color(Color::Transparent); + window->set_fullscreen(true); + window->set_frameless(true); + window->show(); + + if (!m_event_loop->exec()) + return {}; + return m_col; + } + + virtual ~ColorSelectOverlay() override { } + Function on_color_changed; + +private: + virtual void mousedown_event(GUI::MouseEvent&) { m_event_loop->quit(1); } + virtual void mousemove_event(GUI::MouseEvent&) + { + auto new_col = WindowServerConnection::the().get_color_under_cursor(); + if (new_col == m_col) + return; + m_col = new_col; + if (on_color_changed) + on_color_changed(m_col); + } + + virtual void keydown_event(GUI::KeyEvent& event) + { + if (event.key() == KeyCode::Key_Escape) { + event.accept(); + m_event_loop->quit(0); + return; + } + } + + OwnPtr m_event_loop; + Color m_col; +}; + ColorPicker::ColorPicker(Color color, Window* parent_window, String title) : Dialog(parent_window) , m_color(color) @@ -247,7 +302,7 @@ void ColorPicker::build_ui_custom(Widget& root_container) preview_container.set_layout(); preview_container.layout()->set_margins(2); preview_container.layout()->set_spacing(0); - preview_container.set_fixed_height(128); + preview_container.set_fixed_height(100); // Current color preview_container.add(m_color); @@ -340,6 +395,24 @@ void ColorPicker::build_ui_custom(Widget& root_container) make_spinbox(Green, m_color.green()); make_spinbox(Blue, m_color.blue()); make_spinbox(Alpha, m_color.alpha()); + + m_selector_button = vertical_container.add("Select on screen"); + m_selector_button->on_click = [this](auto) { + auto selector = ColorSelectOverlay::construct(); + auto original_color = m_color; + // This allows us to use the color preview widget as a live-preview for + // the color currently under the cursor, which is helpful. + selector->on_color_changed = [this](auto color) { + m_color = color; + update_color_widgets(); + }; + + // Set the final color + auto maybe_color = selector->exec(); + m_color = maybe_color.value_or(original_color); + m_custom_color->set_color(m_color); + update_color_widgets(); + }; } void ColorPicker::update_color_widgets() diff --git a/Userland/Libraries/LibGUI/ColorPicker.h b/Userland/Libraries/LibGUI/ColorPicker.h index e2627a094b0..fb9ed0eee3b 100644 --- a/Userland/Libraries/LibGUI/ColorPicker.h +++ b/Userland/Libraries/LibGUI/ColorPicker.h @@ -14,6 +14,7 @@ namespace GUI { class ColorButton; class ColorPreview; class CustomColorWidget; +class ColorSelectOverlay; class ColorPicker final : public Dialog { C_OBJECT(ColorPicker) @@ -40,6 +41,7 @@ private: Vector m_color_widgets; RefPtr m_custom_color; RefPtr m_preview_widget; + RefPtr