From fa836a4ddaba3533a10b9eac541c767a7a506dd3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 30 Dec 2020 14:28:22 +0100 Subject: [PATCH] LibGUI: Add GUI::AbstractSlider and move generic parts of Slider there This will allow us to share some code between Slider and ScrollBar. --- Libraries/LibGUI/AbstractSlider.cpp | 82 +++++++++++++++++++++++++++++ Libraries/LibGUI/AbstractSlider.h | 69 ++++++++++++++++++++++++ Libraries/LibGUI/CMakeLists.txt | 1 + Libraries/LibGUI/Slider.cpp | 62 +++++----------------- Libraries/LibGUI/Slider.h | 35 +++--------- 5 files changed, 172 insertions(+), 77 deletions(-) create mode 100644 Libraries/LibGUI/AbstractSlider.cpp create mode 100644 Libraries/LibGUI/AbstractSlider.h diff --git a/Libraries/LibGUI/AbstractSlider.cpp b/Libraries/LibGUI/AbstractSlider.cpp new file mode 100644 index 0000000000..75d6f63c07 --- /dev/null +++ b/Libraries/LibGUI/AbstractSlider.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +namespace GUI { + +AbstractSlider::AbstractSlider(Orientation orientation) + : m_orientation(orientation) +{ + REGISTER_INT_PROPERTY("min", min, set_min); + REGISTER_INT_PROPERTY("max", max, set_max); + REGISTER_INT_PROPERTY("step", step, set_step); + REGISTER_ENUM_PROPERTY("orientation", this->orientation, set_orientation, Orientation, + { Orientation::Horizontal, "Horizontal" }, + { Orientation::Vertical, "Vertical" }); +} + +AbstractSlider::~AbstractSlider() +{ +} + +void AbstractSlider::set_orientation(Orientation value) +{ + if (m_orientation == value) + return; + m_orientation = value; + update(); +} + +void AbstractSlider::set_range(int min, int max) +{ + ASSERT(min <= max); + if (m_min == min && m_max == max) + return; + m_min = min; + m_max = max; + m_value = clamp(m_value, m_min, m_max); + update(); +} + +void AbstractSlider::set_value(int value) +{ + value = clamp(value, m_min, m_max); + if (m_value == value) + return; + m_value = value; + update(); + + if (on_value_changed) + on_value_changed(m_value); +} + +} diff --git a/Libraries/LibGUI/AbstractSlider.h b/Libraries/LibGUI/AbstractSlider.h new file mode 100644 index 0000000000..98ec292b70 --- /dev/null +++ b/Libraries/LibGUI/AbstractSlider.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace GUI { + +class AbstractSlider : public Widget { + C_OBJECT_ABSTRACT(AbstractSlider); + +public: + virtual ~AbstractSlider() override; + + void set_orientation(Orientation value); + Orientation orientation() const { return m_orientation; } + + int value() const { return m_value; } + int min() const { return m_min; } + int max() const { return m_max; } + int step() const { return m_step; } + + void set_range(int min, int max); + void set_value(int); + + void set_min(int min) { set_range(min, max()); } + void set_max(int max) { set_range(min(), max); } + void set_step(int step) { m_step = step; } + + Function on_value_changed; + +protected: + explicit AbstractSlider(Orientation = Orientation::Vertical); + +private: + void set_knob_hovered(bool); + + int m_value { 0 }; + int m_min { 0 }; + int m_max { 100 }; + int m_step { 1 }; + Orientation m_orientation { Orientation::Horizontal }; +}; + +} diff --git a/Libraries/LibGUI/CMakeLists.txt b/Libraries/LibGUI/CMakeLists.txt index 3aefaaab94..1a8c7c2112 100644 --- a/Libraries/LibGUI/CMakeLists.txt +++ b/Libraries/LibGUI/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES AboutDialog.cpp AbstractButton.cpp + AbstractSlider.cpp AbstractTableView.cpp AbstractView.cpp Action.cpp diff --git a/Libraries/LibGUI/Slider.cpp b/Libraries/LibGUI/Slider.cpp index 3585f33c3e..68ca874736 100644 --- a/Libraries/LibGUI/Slider.cpp +++ b/Libraries/LibGUI/Slider.cpp @@ -34,55 +34,17 @@ namespace GUI { Slider::Slider(Orientation orientation) - : m_orientation(orientation) + : AbstractSlider(orientation) { - - REGISTER_INT_PROPERTY("min", min, set_min); - REGISTER_INT_PROPERTY("max", max, set_max); - REGISTER_INT_PROPERTY("step", step, set_step); REGISTER_ENUM_PROPERTY("knob_size_mode", knob_size_mode, set_knob_size_mode, KnobSizeMode, { KnobSizeMode::Fixed, "Fixed" }, { KnobSizeMode::Proportional, "Proportional" }); - REGISTER_ENUM_PROPERTY("orientation", this->orientation, set_orientation, Orientation, - { Orientation::Horizontal, "Horizontal" }, - { Orientation::Vertical, "Vertical" }); } Slider::~Slider() { } -void Slider::set_orientation(Orientation value) -{ - if (m_orientation == value) - return; - m_orientation = value; - update(); -} - -void Slider::set_range(int min, int max) -{ - ASSERT(min <= max); - if (m_min == min && m_max == max) - return; - m_min = min; - m_max = max; - m_value = clamp(m_value, m_min, m_max); - update(); -} - -void Slider::set_value(int value) -{ - value = clamp(value, m_min, m_max); - if (m_value == value) - return; - m_value = value; - update(); - - if (on_value_changed) - on_value_changed(m_value); -} - void Slider::paint_event(PaintEvent& event) { Painter painter(*this); @@ -112,16 +74,16 @@ Gfx::IntRect Slider::knob_rect() const rect.set_secondary_size_for_orientation(orientation(), knob_secondary_size()); if (knob_size_mode() == KnobSizeMode::Fixed) { - if (m_max - m_min) { - float scale = (float)inner_rect.primary_size_for_orientation(orientation()) / (float)(m_max - m_min); - rect.set_primary_offset_for_orientation(orientation(), inner_rect.primary_offset_for_orientation(orientation()) + ((int)((m_value - m_min) * scale)) - (knob_fixed_primary_size() / 2)); + if (max() - min()) { + float scale = (float)inner_rect.primary_size_for_orientation(orientation()) / (float)(max() - min()); + rect.set_primary_offset_for_orientation(orientation(), inner_rect.primary_offset_for_orientation(orientation()) + ((int)((value() - min()) * scale)) - (knob_fixed_primary_size() / 2)); } else rect.set_primary_size_for_orientation(orientation(), 0); rect.set_primary_size_for_orientation(orientation(), knob_fixed_primary_size()); } else { - float scale = (float)inner_rect.primary_size_for_orientation(orientation()) / (float)(m_max - m_min + 1); - rect.set_primary_offset_for_orientation(orientation(), inner_rect.primary_offset_for_orientation(orientation()) + ((int)((m_value - m_min) * scale))); - if (m_max - m_min) + float scale = (float)inner_rect.primary_size_for_orientation(orientation()) / (float)(max() - min() + 1); + rect.set_primary_offset_for_orientation(orientation(), inner_rect.primary_offset_for_orientation(orientation()) + ((int)((value() - min()) * scale))); + if (max() - min()) rect.set_primary_size_for_orientation(orientation(), ::max((int)(scale), knob_fixed_primary_size())); else rect.set_primary_size_for_orientation(orientation(), inner_rect.primary_size_for_orientation(orientation())); @@ -139,13 +101,13 @@ void Slider::mousedown_event(MouseEvent& event) if (knob_rect().contains(event.position())) { m_dragging = true; m_drag_origin = event.position(); - m_drag_origin_value = m_value; + m_drag_origin_value = value(); return; } else { if (event.position().primary_offset_for_orientation(orientation()) > knob_rect().last_edge_for_orientation(orientation())) - set_value(m_value + 1); + set_value(value() + 1); else if (event.position().primary_offset_for_orientation(orientation()) < knob_rect().first_edge_for_orientation(orientation())) - set_value(m_value - 1); + set_value(value() - 1); } } return Widget::mousedown_event(event); @@ -157,7 +119,7 @@ void Slider::mousemove_event(MouseEvent& event) if (m_dragging) { float delta = event.position().primary_offset_for_orientation(orientation()) - m_drag_origin.primary_offset_for_orientation(orientation()); float scrubbable_range = inner_rect().primary_size_for_orientation(orientation()); - float value_steps_per_scrubbed_pixel = (m_max - m_min) / scrubbable_range; + float value_steps_per_scrubbed_pixel = (max() - min()) / scrubbable_range; float new_value = m_drag_origin_value + (value_steps_per_scrubbed_pixel * delta); set_value((int)new_value); return; @@ -177,7 +139,7 @@ void Slider::mouseup_event(MouseEvent& event) void Slider::mousewheel_event(MouseEvent& event) { - auto acceleration_modifier = m_step; + auto acceleration_modifier = step(); if (event.modifiers() == KeyModifier::Mod_Ctrl && knob_size_mode() == KnobSizeMode::Fixed) acceleration_modifier *= 6; diff --git a/Libraries/LibGUI/Slider.h b/Libraries/LibGUI/Slider.h index 18bc008ed9..65362b6b0a 100644 --- a/Libraries/LibGUI/Slider.h +++ b/Libraries/LibGUI/Slider.h @@ -26,12 +26,13 @@ #pragma once -#include +#include namespace GUI { -class Slider : public Widget { - C_OBJECT(Slider) +class Slider : public AbstractSlider { + C_OBJECT(Slider); + public: enum class KnobSizeMode { Fixed, @@ -40,21 +41,6 @@ public: virtual ~Slider() override; - void set_orientation(Orientation value); - Orientation orientation() const { return m_orientation; } - - int value() const { return m_value; } - int min() const { return m_min; } - int max() const { return m_max; } - int step() const { return m_step; } - - void set_range(int min, int max); - void set_value(int); - - void set_min(int min) { set_range(min, max()); } - void set_max(int max) { set_range(min(), max); } - void set_step(int step) { m_step = step; } - void set_knob_size_mode(KnobSizeMode mode) { m_knob_size_mode = mode; } KnobSizeMode knob_size_mode() const { return m_knob_size_mode; } @@ -72,8 +58,6 @@ public: return rect().shrunken(0, 20); } - Function on_value_changed; - protected: explicit Slider(Orientation = Orientation::Vertical); @@ -88,20 +72,16 @@ protected: private: void set_knob_hovered(bool); - int m_value { 0 }; - int m_min { 0 }; - int m_max { 100 }; - int m_step { 1 }; bool m_knob_hovered { false }; bool m_dragging { false }; int m_drag_origin_value { 0 }; Gfx::IntPoint m_drag_origin; KnobSizeMode m_knob_size_mode { KnobSizeMode::Fixed }; - Orientation m_orientation { Orientation::Horizontal }; }; class VerticalSlider final : public Slider { - C_OBJECT(VerticalSlider) + C_OBJECT(VerticalSlider); + public: virtual ~VerticalSlider() override { } @@ -113,7 +93,8 @@ private: }; class HorizontalSlider final : public Slider { - C_OBJECT(HorizontalSlider) + C_OBJECT(HorizontalSlider); + public: virtual ~HorizontalSlider() override { }