mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 10:22: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 | ||||
|     AboutDialog.cpp | ||||
|     AbstractButton.cpp | ||||
|     AbstractSlider.cpp | ||||
|     AbstractTableView.cpp | ||||
|     AbstractView.cpp | ||||
|     Action.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; | ||||
|  |  | |||
|  | @ -26,12 +26,13 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <LibGUI/Widget.h> | ||||
| #include <LibGUI/AbstractSlider.h> | ||||
| 
 | ||||
| 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<void(int)> 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 { } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling