mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +00:00 
			
		
		
		
	LibGUI: Animated smooth scroll interpolation
This commit is contained in:
		
							parent
							
								
									86c0961240
								
							
						
					
					
						commit
						c204885a94
					
				
					 3 changed files with 75 additions and 7 deletions
				
			
		|  | @ -38,12 +38,12 @@ public: | ||||||
|     void set_page_step(int page_step); |     void set_page_step(int page_step); | ||||||
|     void set_jump_to_cursor(bool b) { m_jump_to_cursor = b; } |     void set_jump_to_cursor(bool b) { m_jump_to_cursor = b; } | ||||||
| 
 | 
 | ||||||
|     void increase_slider_by(int delta) { set_value(value() + delta); } |     virtual void increase_slider_by(int delta) { set_value(value() + delta); } | ||||||
|     void decrease_slider_by(int delta) { set_value(value() - delta); } |     virtual void decrease_slider_by(int delta) { set_value(value() - delta); } | ||||||
|     void increase_slider_by_page_steps(int page_steps) { set_value(value() + page_step() * page_steps); } |     virtual void increase_slider_by_page_steps(int page_steps) { set_value(value() + page_step() * page_steps); } | ||||||
|     void decrease_slider_by_page_steps(int page_steps) { set_value(value() - page_step() * page_steps); } |     virtual void decrease_slider_by_page_steps(int page_steps) { set_value(value() - page_step() * page_steps); } | ||||||
|     void increase_slider_by_steps(int steps) { set_value(value() + step() * steps); } |     virtual void increase_slider_by_steps(int steps) { set_value(value() + step() * steps); } | ||||||
|     void decrease_slider_by_steps(int steps) { set_value(value() - step() * steps); } |     virtual void decrease_slider_by_steps(int steps) { set_value(value() - step() * steps); } | ||||||
| 
 | 
 | ||||||
|     Function<void(int)> on_change; |     Function<void(int)> on_change; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,6 +12,9 @@ | ||||||
| #include <LibGfx/Palette.h> | #include <LibGfx/Palette.h> | ||||||
| #include <LibGfx/StylePainter.h> | #include <LibGfx/StylePainter.h> | ||||||
| 
 | 
 | ||||||
|  | static constexpr int ANIMATION_INTERVAL = 16;  // Milliseconds
 | ||||||
|  | static constexpr double ANIMATION_TIME = 0.18; // Seconds
 | ||||||
|  | 
 | ||||||
| REGISTER_WIDGET(GUI, Scrollbar) | REGISTER_WIDGET(GUI, Scrollbar) | ||||||
| 
 | 
 | ||||||
| namespace GUI { | namespace GUI { | ||||||
|  | @ -115,6 +118,39 @@ bool Scrollbar::has_scrubber() const | ||||||
|     return max() != min(); |     return max() != min(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Scrollbar::set_value(int value, AllowCallback allow_callback) | ||||||
|  | { | ||||||
|  |     m_target_value = value; | ||||||
|  |     if (!(m_animated_scrolling_timer.is_null())) | ||||||
|  |         m_animated_scrolling_timer->stop(); | ||||||
|  | 
 | ||||||
|  |     AbstractSlider::set_value(value, allow_callback); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Scrollbar::set_target_value(int new_target_value) | ||||||
|  | { | ||||||
|  |     new_target_value = clamp(new_target_value, min(), max()); | ||||||
|  | 
 | ||||||
|  |     // If we are already at or scrolling to the new target then don't touch anything
 | ||||||
|  |     if (m_target_value == new_target_value) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     m_animation_time_elapsed = 0; | ||||||
|  |     m_start_value = value(); | ||||||
|  |     m_target_value = new_target_value; | ||||||
|  | 
 | ||||||
|  |     if (m_animated_scrolling_timer.is_null()) { | ||||||
|  |         m_animated_scrolling_timer = add<Core::Timer>(); | ||||||
|  |         m_animated_scrolling_timer->set_interval(ANIMATION_INTERVAL); | ||||||
|  |         m_animated_scrolling_timer->on_timeout = [this]() { | ||||||
|  |             m_animation_time_elapsed += (double)ANIMATION_INTERVAL / 1'000; // ms -> sec
 | ||||||
|  |             update_animated_scroll(); | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     m_animated_scrolling_timer->start(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| float Scrollbar::unclamped_scrubber_size() const | float Scrollbar::unclamped_scrubber_size() const | ||||||
| { | { | ||||||
|     float pixel_range = length(orientation()) - button_size() * 2; |     float pixel_range = length(orientation()) - button_size() * 2; | ||||||
|  | @ -335,7 +371,7 @@ void Scrollbar::scroll_to_position(const Gfx::IntPoint& click_position) | ||||||
| 
 | 
 | ||||||
|     float x_or_y = ::max(0, click_position.primary_offset_for_orientation(orientation()) - button_width() - button_width() / 2); |     float x_or_y = ::max(0, click_position.primary_offset_for_orientation(orientation()) - button_width() - button_width() / 2); | ||||||
|     float rel_x_or_y = x_or_y / available; |     float rel_x_or_y = x_or_y / available; | ||||||
|     set_value(min() + rel_x_or_y * range_size); |     set_target_value(min() + rel_x_or_y * range_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Scrollbar::Component Scrollbar::component_at_position(const Gfx::IntPoint& position) | Scrollbar::Component Scrollbar::component_at_position(const Gfx::IntPoint& position) | ||||||
|  | @ -391,4 +427,19 @@ void Scrollbar::change_event(Event& event) | ||||||
|     return Widget::change_event(event); |     return Widget::change_event(event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Scrollbar::update_animated_scroll() | ||||||
|  | { | ||||||
|  |     if (value() == m_target_value) { | ||||||
|  |         m_animated_scrolling_timer->stop(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     double time_percent = m_animation_time_elapsed / ANIMATION_TIME; | ||||||
|  |     double ease_percent = 1.0 - pow(1.0 - time_percent, 5.0); // Ease out quint
 | ||||||
|  |     double initial_distance = m_target_value - m_start_value; | ||||||
|  |     double new_distance = initial_distance * ease_percent; | ||||||
|  |     int new_value = m_start_value + (int)round(new_distance); | ||||||
|  |     AbstractSlider::set_value(new_value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,16 @@ public: | ||||||
| 
 | 
 | ||||||
|     bool has_scrubber() const; |     bool has_scrubber() const; | ||||||
| 
 | 
 | ||||||
|  |     virtual void set_value(int, AllowCallback = AllowCallback::Yes) override; | ||||||
|  |     void set_target_value(int); | ||||||
|  | 
 | ||||||
|  |     virtual void increase_slider_by(int delta) override { set_target_value(m_target_value + delta); } | ||||||
|  |     virtual void decrease_slider_by(int delta) override { set_target_value(m_target_value - delta); } | ||||||
|  |     virtual void increase_slider_by_page_steps(int page_steps) override { set_target_value(m_target_value + page_step() * page_steps); } | ||||||
|  |     virtual void decrease_slider_by_page_steps(int page_steps) override { set_target_value(m_target_value - page_step() * page_steps); } | ||||||
|  |     virtual void increase_slider_by_steps(int steps) override { set_target_value(m_target_value + step() * steps); } | ||||||
|  |     virtual void decrease_slider_by_steps(int steps) override { set_target_value(m_target_value - step() * steps); } | ||||||
|  | 
 | ||||||
|     enum Component { |     enum Component { | ||||||
|         None, |         None, | ||||||
|         DecrementButton, |         DecrementButton, | ||||||
|  | @ -66,6 +76,12 @@ private: | ||||||
| 
 | 
 | ||||||
|     Component component_at_position(const Gfx::IntPoint&); |     Component component_at_position(const Gfx::IntPoint&); | ||||||
| 
 | 
 | ||||||
|  |     void update_animated_scroll(); | ||||||
|  | 
 | ||||||
|  |     int m_target_value { 0 }; | ||||||
|  |     int m_start_value { 0 }; | ||||||
|  |     double m_animation_time_elapsed { 0 }; | ||||||
|  | 
 | ||||||
|     int m_scrub_start_value { 0 }; |     int m_scrub_start_value { 0 }; | ||||||
|     Gfx::IntPoint m_scrub_origin; |     Gfx::IntPoint m_scrub_origin; | ||||||
| 
 | 
 | ||||||
|  | @ -74,6 +90,7 @@ private: | ||||||
|     Gfx::IntPoint m_last_mouse_position; |     Gfx::IntPoint m_last_mouse_position; | ||||||
| 
 | 
 | ||||||
|     RefPtr<Core::Timer> m_automatic_scrolling_timer; |     RefPtr<Core::Timer> m_automatic_scrolling_timer; | ||||||
|  |     RefPtr<Core::Timer> m_animated_scrolling_timer; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 ForLoveOfCats
						ForLoveOfCats