mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:52:45 +00:00 
			
		
		
		
	LibGUI: Add GUI::AbstractSlider and move generic parts of Slider there
This will allow us to share some code between Slider and ScrollBar.
This commit is contained in:
		
							parent
							
								
									761169f5c0
								
							
						
					
					
						commit
						fa836a4dda
					
				
					 5 changed files with 172 additions and 77 deletions
				
			
		
							
								
								
									
										82
									
								
								Libraries/LibGUI/AbstractSlider.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								Libraries/LibGUI/AbstractSlider.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||||
|  |  * 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 <AK/Assertions.h> | ||||||
|  | #include <AK/StdLibExtras.h> | ||||||
|  | #include <LibGUI/Painter.h> | ||||||
|  | #include <LibGUI/Slider.h> | ||||||
|  | #include <LibGfx/Palette.h> | ||||||
|  | #include <LibGfx/StylePainter.h> | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								Libraries/LibGUI/AbstractSlider.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Libraries/LibGUI/AbstractSlider.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||||
|  |  * 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 <LibGUI/Widget.h> | ||||||
|  | 
 | ||||||
|  | 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<void(int)> 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 }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| set(SOURCES | set(SOURCES | ||||||
|     AboutDialog.cpp |     AboutDialog.cpp | ||||||
|     AbstractButton.cpp |     AbstractButton.cpp | ||||||
|  |     AbstractSlider.cpp | ||||||
|     AbstractTableView.cpp |     AbstractTableView.cpp | ||||||
|     AbstractView.cpp |     AbstractView.cpp | ||||||
|     Action.cpp |     Action.cpp | ||||||
|  |  | ||||||
|  | @ -34,55 +34,17 @@ | ||||||
| namespace GUI { | namespace GUI { | ||||||
| 
 | 
 | ||||||
| Slider::Slider(Orientation orientation) | 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, |     REGISTER_ENUM_PROPERTY("knob_size_mode", knob_size_mode, set_knob_size_mode, KnobSizeMode, | ||||||
|         { KnobSizeMode::Fixed, "Fixed" }, |         { KnobSizeMode::Fixed, "Fixed" }, | ||||||
|         { KnobSizeMode::Proportional, "Proportional" }); |         { KnobSizeMode::Proportional, "Proportional" }); | ||||||
|     REGISTER_ENUM_PROPERTY("orientation", this->orientation, set_orientation, Orientation, |  | ||||||
|         { Orientation::Horizontal, "Horizontal" }, |  | ||||||
|         { Orientation::Vertical, "Vertical" }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Slider::~Slider() | 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) | void Slider::paint_event(PaintEvent& event) | ||||||
| { | { | ||||||
|     Painter painter(*this); |     Painter painter(*this); | ||||||
|  | @ -112,16 +74,16 @@ Gfx::IntRect Slider::knob_rect() const | ||||||
|     rect.set_secondary_size_for_orientation(orientation(), knob_secondary_size()); |     rect.set_secondary_size_for_orientation(orientation(), knob_secondary_size()); | ||||||
| 
 | 
 | ||||||
|     if (knob_size_mode() == KnobSizeMode::Fixed) { |     if (knob_size_mode() == KnobSizeMode::Fixed) { | ||||||
|         if (m_max - m_min) { |         if (max() - min()) { | ||||||
|             float scale = (float)inner_rect.primary_size_for_orientation(orientation()) / (float)(m_max - m_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)((m_value - m_min) * scale)) - (knob_fixed_primary_size() / 2)); |             rect.set_primary_offset_for_orientation(orientation(), inner_rect.primary_offset_for_orientation(orientation()) + ((int)((value() - min()) * scale)) - (knob_fixed_primary_size() / 2)); | ||||||
|         } else |         } else | ||||||
|             rect.set_primary_size_for_orientation(orientation(), 0); |             rect.set_primary_size_for_orientation(orientation(), 0); | ||||||
|         rect.set_primary_size_for_orientation(orientation(), knob_fixed_primary_size()); |         rect.set_primary_size_for_orientation(orientation(), knob_fixed_primary_size()); | ||||||
|     } else { |     } else { | ||||||
|         float scale = (float)inner_rect.primary_size_for_orientation(orientation()) / (float)(m_max - m_min + 1); |         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)((m_value - m_min) * scale))); |         rect.set_primary_offset_for_orientation(orientation(), inner_rect.primary_offset_for_orientation(orientation()) + ((int)((value() - min()) * scale))); | ||||||
|         if (m_max - m_min) |         if (max() - min()) | ||||||
|             rect.set_primary_size_for_orientation(orientation(), ::max((int)(scale), knob_fixed_primary_size())); |             rect.set_primary_size_for_orientation(orientation(), ::max((int)(scale), knob_fixed_primary_size())); | ||||||
|         else |         else | ||||||
|             rect.set_primary_size_for_orientation(orientation(), inner_rect.primary_size_for_orientation(orientation())); |             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())) { |         if (knob_rect().contains(event.position())) { | ||||||
|             m_dragging = true; |             m_dragging = true; | ||||||
|             m_drag_origin = event.position(); |             m_drag_origin = event.position(); | ||||||
|             m_drag_origin_value = m_value; |             m_drag_origin_value = value(); | ||||||
|             return; |             return; | ||||||
|         } else { |         } else { | ||||||
|             if (event.position().primary_offset_for_orientation(orientation()) > knob_rect().last_edge_for_orientation(orientation())) |             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())) |             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); |     return Widget::mousedown_event(event); | ||||||
|  | @ -157,7 +119,7 @@ void Slider::mousemove_event(MouseEvent& event) | ||||||
|     if (m_dragging) { |     if (m_dragging) { | ||||||
|         float delta = event.position().primary_offset_for_orientation(orientation()) - m_drag_origin.primary_offset_for_orientation(orientation()); |         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 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); |         float new_value = m_drag_origin_value + (value_steps_per_scrubbed_pixel * delta); | ||||||
|         set_value((int)new_value); |         set_value((int)new_value); | ||||||
|         return; |         return; | ||||||
|  | @ -177,7 +139,7 @@ void Slider::mouseup_event(MouseEvent& event) | ||||||
| 
 | 
 | ||||||
| void Slider::mousewheel_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) |     if (event.modifiers() == KeyModifier::Mod_Ctrl && knob_size_mode() == KnobSizeMode::Fixed) | ||||||
|         acceleration_modifier *= 6; |         acceleration_modifier *= 6; | ||||||
|  |  | ||||||
|  | @ -26,12 +26,13 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <LibGUI/Widget.h> | #include <LibGUI/AbstractSlider.h> | ||||||
| 
 | 
 | ||||||
| namespace GUI { | namespace GUI { | ||||||
| 
 | 
 | ||||||
| class Slider : public Widget { | class Slider : public AbstractSlider { | ||||||
|     C_OBJECT(Slider) |     C_OBJECT(Slider); | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
|     enum class KnobSizeMode { |     enum class KnobSizeMode { | ||||||
|         Fixed, |         Fixed, | ||||||
|  | @ -40,21 +41,6 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual ~Slider() override; |     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; } |     void set_knob_size_mode(KnobSizeMode mode) { m_knob_size_mode = mode; } | ||||||
|     KnobSizeMode knob_size_mode() const { return m_knob_size_mode; } |     KnobSizeMode knob_size_mode() const { return m_knob_size_mode; } | ||||||
| 
 | 
 | ||||||
|  | @ -72,8 +58,6 @@ public: | ||||||
|         return rect().shrunken(0, 20); |         return rect().shrunken(0, 20); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Function<void(int)> on_value_changed; |  | ||||||
| 
 |  | ||||||
| protected: | protected: | ||||||
|     explicit Slider(Orientation = Orientation::Vertical); |     explicit Slider(Orientation = Orientation::Vertical); | ||||||
| 
 | 
 | ||||||
|  | @ -88,20 +72,16 @@ protected: | ||||||
| private: | private: | ||||||
|     void set_knob_hovered(bool); |     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_knob_hovered { false }; | ||||||
|     bool m_dragging { false }; |     bool m_dragging { false }; | ||||||
|     int m_drag_origin_value { 0 }; |     int m_drag_origin_value { 0 }; | ||||||
|     Gfx::IntPoint m_drag_origin; |     Gfx::IntPoint m_drag_origin; | ||||||
|     KnobSizeMode m_knob_size_mode { KnobSizeMode::Fixed }; |     KnobSizeMode m_knob_size_mode { KnobSizeMode::Fixed }; | ||||||
|     Orientation m_orientation { Orientation::Horizontal }; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class VerticalSlider final : public Slider { | class VerticalSlider final : public Slider { | ||||||
|     C_OBJECT(VerticalSlider) |     C_OBJECT(VerticalSlider); | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
|     virtual ~VerticalSlider() override { } |     virtual ~VerticalSlider() override { } | ||||||
| 
 | 
 | ||||||
|  | @ -113,7 +93,8 @@ private: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class HorizontalSlider final : public Slider { | class HorizontalSlider final : public Slider { | ||||||
|     C_OBJECT(HorizontalSlider) |     C_OBJECT(HorizontalSlider); | ||||||
|  | 
 | ||||||
| public: | public: | ||||||
|     virtual ~HorizontalSlider() override { } |     virtual ~HorizontalSlider() override { } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling