diff options
author | LepkoQQ <lepko.san@gmail.com> | 2020-08-25 17:49:38 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-26 00:38:23 +0200 |
commit | 189c4931625be6e9b7961d8bcd10e91a035767c6 (patch) | |
tree | b07ce018d722e97f4539827eb52708d437642f26 /Libraries | |
parent | bb5014fad7449565482cd2c0a07eb0da4fc19bca (diff) | |
download | serenity-189c4931625be6e9b7961d8bcd10e91a035767c6.zip |
LibGUI: Split ColorPicker in to a field and slider
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibGUI/ColorPicker.cpp | 273 |
1 files changed, 223 insertions, 50 deletions
diff --git a/Libraries/LibGUI/ColorPicker.cpp b/Libraries/LibGUI/ColorPicker.cpp index a96037c5bc..3df54ded8e 100644 --- a/Libraries/LibGUI/ColorPicker.cpp +++ b/Libraries/LibGUI/ColorPicker.cpp @@ -61,23 +61,52 @@ private: bool m_selected { false }; }; -class CustomColorWidget final : public GUI::Frame { - C_OBJECT(CustomColorWidget); +class ColorField final : public GUI::Frame { + C_OBJECT(ColorField); public: Function<void(Color)> on_pick; - void set_color_and_recalculate_position(Color); + void set_color(Color); + void set_hue(double); private: - CustomColorWidget(Color color); + ColorField(Color color); Color m_color; - RefPtr<Gfx::Bitmap> m_custom_colors; + RefPtr<Gfx::Bitmap> m_color_bitmap; bool m_being_pressed { false }; Gfx::IntPoint m_last_position; + void create_color_bitmap(); void pick_color_at_position(GUI::MouseEvent& event); + void recalculate_position(); + + virtual void mousedown_event(GUI::MouseEvent&) override; + virtual void mouseup_event(GUI::MouseEvent&) override; + virtual void mousemove_event(GUI::MouseEvent&) override; + virtual void paint_event(GUI::PaintEvent&) override; + virtual void resize_event(ResizeEvent&) override; +}; + +class ColorSlider final : public GUI::Frame { + C_OBJECT(ColorSlider); + +public: + Function<void(double)> on_pick; + void set_value(double); + +private: + ColorSlider(double value); + + double m_value; + + RefPtr<Gfx::Bitmap> m_color_bitmap; + bool m_being_pressed { false }; + int m_last_position; + + void pick_value_at_position(GUI::MouseEvent& event); + void recalculate_position(); virtual void mousedown_event(GUI::MouseEvent&) override; virtual void mouseup_event(GUI::MouseEvent&) override; @@ -86,6 +115,21 @@ private: virtual void resize_event(ResizeEvent&) override; }; +class CustomColorWidget final : public GUI::Widget { + C_OBJECT(CustomColorWidget); + +public: + Function<void(Color)> on_pick; + void set_color(Color); + +private: + CustomColorWidget(Color); + + + RefPtr<ColorField> m_color_field; + RefPtr<ColorSlider> m_color_slider; +}; + ColorPicker::ColorPicker(Color color, Window* parent_window, String title) : Dialog(parent_window) , m_color(color) @@ -93,7 +137,7 @@ ColorPicker::ColorPicker(Color color, Window* parent_window, String title) set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/color-chooser.png")); set_title(title); set_resizable(false); - resize(530, 325); + resize(500, 322); build_ui(); } @@ -184,8 +228,9 @@ void ColorPicker::build_ui_custom(Widget& root_container) horizontal_container.set_layout<HorizontalBoxLayout>(); // Left Side - m_custom_color = horizontal_container.add<GUI::CustomColorWidget>(m_color); - m_custom_color->set_size_policy(SizePolicy::Fill, SizePolicy::Fill); + m_custom_color = horizontal_container.add<CustomColorWidget>(m_color); + m_custom_color->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); + m_custom_color->set_preferred_size(291, 256); m_custom_color->on_pick = [this](Color color) { if (m_color == color) return; @@ -237,7 +282,7 @@ void ColorPicker::build_ui_custom(Widget& root_container) return; m_color = optional_color.value(); - m_custom_color->set_color_and_recalculate_position(color); + m_custom_color->set_color(color); update_color_widgets(); } }; @@ -274,7 +319,7 @@ void ColorPicker::build_ui_custom(Widget& root_container) return; m_color = color; - m_custom_color->set_color_and_recalculate_position(color); + m_custom_color->set_color(color); update_color_widgets(); }; @@ -322,7 +367,7 @@ void ColorPicker::create_color_button(Widget& container, unsigned rgb) } m_color = color; - m_custom_color->set_color_and_recalculate_position(color); + m_custom_color->set_color(color); update_color_widgets(); }; @@ -380,54 +425,87 @@ void ColorButton::click(unsigned) } CustomColorWidget::CustomColorWidget(Color color) - : m_color(color) { - m_custom_colors = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { 360, 512 }); - auto painter = Gfx::Painter(*m_custom_colors); + set_layout<HorizontalBoxLayout>(); + + m_color_field = add<ColorField>(color); + m_color_field->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + m_color_field->set_preferred_size(256, 0); + m_color_field->on_pick = [this](Color color) { + if (on_pick) + on_pick(color); + }; - for (int h = 0; h < 360; h++) { - Gfx::HSV hsv; - hsv.hue = h / 2; + m_color_slider = add<ColorSlider>(color.to_hsv().hue); + m_color_slider->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + m_color_slider->set_preferred_size(32, 0); + m_color_slider->on_pick = [this](double value) { + m_color_field->set_hue(value); + }; +} - hsv.saturation = 255; - for (int v = 0; v < 256; v++) { - hsv.value = v; +void CustomColorWidget::set_color(Color color) +{ + m_color_field->set_color(color); +} - Color color = Color::from_hsv(hsv); - painter.set_pixel({ h, v }, color); - } +ColorField::ColorField(Color color) + : m_color(color) +{ + create_color_bitmap(); +} + +void ColorField::create_color_bitmap() +{ + m_color_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { 256, 256 }); + auto painter = Gfx::Painter(*m_color_bitmap); - hsv.value = 255; - for (int s = 0; s < 256; s++) { - hsv.saturation = 255 - s; + auto hsv = m_color.to_hsv(); + for (int x = 0; x < 256; x++) { + hsv.saturation = x / 255.0; + for (int y = 0; y < 256; y++) { + hsv.value = (255 - y) / 255.0; Color color = Color::from_hsv(hsv); - painter.set_pixel({ h, 256 + s }, color); + painter.set_pixel({ x, y }, color); } } } -void CustomColorWidget::set_color_and_recalculate_position(Color color) +void ColorField::set_color(Color color) { + if (m_color == color) + return; + m_color = color; + create_color_bitmap(); + recalculate_position(); +} +void ColorField::recalculate_position() +{ Gfx::HSV hsv = m_color.to_hsv(); - auto x = hsv.hue * width(); - // FIXME: the current color representation tries to represent a 3D color vector as a 2D gradient, - // as a result not all colors can be represented on it (if saturation and value are both < 1), - // let's try our best for now - auto y = height() / 2; - if (hsv.saturation < 1) { - y += (1 - hsv.saturation) * (height() / 2); - } else if (hsv.value < 1) { - y -= (1 - hsv.value) * (height() / 2); - } - + auto x = hsv.saturation * width(); + auto y = (1 - hsv.value) * height(); m_last_position = Gfx::IntPoint(x, y); update(); } -void CustomColorWidget::pick_color_at_position(GUI::MouseEvent& event) +void ColorField::set_hue(double value) +{ + auto hsv = m_color.to_hsv(); + if (hsv.hue == value) + return; + + hsv.hue = value; + auto color = Color::from_hsv(hsv); + set_color(color); + + if (on_pick) + on_pick(color); +} + +void ColorField::pick_color_at_position(GUI::MouseEvent& event) { if (!m_being_pressed) return; @@ -437,9 +515,9 @@ void CustomColorWidget::pick_color_at_position(GUI::MouseEvent& event) return; // Map actual event position onto scaled bitmap to get the right pixel - auto pixel_x = min(position.x() * m_custom_colors->width() / frame_inner_rect().width(), m_custom_colors->width() - 1); - auto pixel_y = min(position.y() * m_custom_colors->height() / frame_inner_rect().height(), m_custom_colors->height() - 1); - auto color = m_custom_colors->get_pixel({ pixel_x, pixel_y }); + auto pixel_x = min(position.x() * m_color_bitmap->width() / frame_inner_rect().width(), m_color_bitmap->width() - 1); + auto pixel_y = min(position.y() * m_color_bitmap->height() / frame_inner_rect().height(), m_color_bitmap->height() - 1); + auto color = m_color_bitmap->get_pixel({ pixel_x, pixel_y }); m_last_position = position; m_color = color; @@ -449,7 +527,7 @@ void CustomColorWidget::pick_color_at_position(GUI::MouseEvent& event) update(); } -void CustomColorWidget::mousedown_event(GUI::MouseEvent& event) +void ColorField::mousedown_event(GUI::MouseEvent& event) { if (event.button() == GUI::MouseButton::Left) { m_being_pressed = true; @@ -457,7 +535,7 @@ void CustomColorWidget::mousedown_event(GUI::MouseEvent& event) } } -void CustomColorWidget::mouseup_event(GUI::MouseEvent& event) +void ColorField::mouseup_event(GUI::MouseEvent& event) { if (event.button() == GUI::MouseButton::Left) { m_being_pressed = false; @@ -465,13 +543,13 @@ void CustomColorWidget::mouseup_event(GUI::MouseEvent& event) } } -void CustomColorWidget::mousemove_event(GUI::MouseEvent& event) +void ColorField::mousemove_event(GUI::MouseEvent& event) { if (event.buttons() & GUI::MouseButton::Left) pick_color_at_position(event); } -void CustomColorWidget::paint_event(GUI::PaintEvent& event) +void ColorField::paint_event(GUI::PaintEvent& event) { Frame::paint_event(event); @@ -479,7 +557,7 @@ void CustomColorWidget::paint_event(GUI::PaintEvent& event) painter.add_clip_rect(event.rect()); painter.add_clip_rect(frame_inner_rect()); - painter.draw_scaled_bitmap(frame_inner_rect(), *m_custom_colors, m_custom_colors->rect()); + painter.draw_scaled_bitmap(frame_inner_rect(), *m_color_bitmap, m_color_bitmap->rect()); painter.translate(frame_thickness(), frame_thickness()); painter.draw_line({ m_last_position.x() - 1, 0 }, { m_last_position.x() - 1, height() }, Color::White); @@ -490,9 +568,104 @@ void CustomColorWidget::paint_event(GUI::PaintEvent& event) painter.draw_line({ 0, m_last_position.y() }, { width(), m_last_position.y() }, Color::Black); } -void CustomColorWidget::resize_event(ResizeEvent&) +void ColorField::resize_event(ResizeEvent&) +{ + recalculate_position(); +} + +ColorSlider::ColorSlider(double value) + : m_value(value) +{ + m_color_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, { 32, 360 }); + auto painter = Gfx::Painter(*m_color_bitmap); + + for (int h = 0; h < 360; h++) { + Gfx::HSV hsv; + hsv.hue = h; + hsv.saturation = 1.0; + hsv.value = 1.0; + Color color = Color::from_hsv(hsv); + painter.draw_line({ 0, h }, { 32, h }, color); + } +} + +void ColorSlider::set_value(double value) +{ + if (m_value == value) + return; + + m_value = value; + recalculate_position(); +} + +void ColorSlider::recalculate_position() +{ + m_last_position = (m_value / 360.0) * height(); + update(); +} + +void ColorSlider::pick_value_at_position(GUI::MouseEvent& event) +{ + if (!m_being_pressed) + return; + + auto position = event.position().translated(-frame_thickness(), -frame_thickness()); + if (!frame_inner_rect().contains(position)) + return; + + // Map actual event position onto scaled bitmap to get the right pixel + auto pixel_y = min(position.y() * m_color_bitmap->height() / frame_inner_rect().height(), m_color_bitmap->height() - 1); + auto color = m_color_bitmap->get_pixel({ 0, pixel_y }); + m_last_position = position.y(); + m_value = color.to_hsv().hue; + + if (on_pick) + on_pick(m_value); + + update(); +} + +void ColorSlider::mousedown_event(GUI::MouseEvent& event) +{ + if (event.button() == GUI::MouseButton::Left) { + m_being_pressed = true; + pick_value_at_position(event); + } +} + +void ColorSlider::mouseup_event(GUI::MouseEvent& event) +{ + if (event.button() == GUI::MouseButton::Left) { + m_being_pressed = false; + pick_value_at_position(event); + } +} + +void ColorSlider::mousemove_event(GUI::MouseEvent& event) +{ + if (event.buttons() & GUI::MouseButton::Left) + pick_value_at_position(event); +} + +void ColorSlider::paint_event(GUI::PaintEvent& event) +{ + Frame::paint_event(event); + + Painter painter(*this); + painter.add_clip_rect(event.rect()); + painter.add_clip_rect(frame_inner_rect()); + + painter.draw_scaled_bitmap(frame_inner_rect(), *m_color_bitmap, m_color_bitmap->rect()); + + painter.translate(frame_thickness(), frame_thickness()); + painter.draw_line({ 0, m_last_position - 1 }, { width(), m_last_position - 1 }, Color::White); + painter.draw_line({ 0, m_last_position + 1 }, { width(), m_last_position + 1 }, Color::White); + painter.draw_line({ 0, m_last_position }, { width(), m_last_position }, Color::Black); +} + +void ColorSlider::resize_event(ResizeEvent&) { - set_color_and_recalculate_position(m_color); + recalculate_position(); } } |