| 
									
										
										
										
											2019-06-07 11:46:02 +02:00
										 |  |  | #include <LibGUI/GPainter.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | #include <LibGUI/GScrollBar.h>
 | 
					
						
							| 
									
										
										
										
											2019-07-18 10:15:00 +02:00
										 |  |  | #include <LibDraw/CharacterBitmap.h>
 | 
					
						
							|  |  |  | #include <LibDraw/GraphicsBitmap.h>
 | 
					
						
							|  |  |  | #include <LibDraw/StylePainter.h>
 | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  | static const char* s_up_arrow_bitmap_data = { | 
					
						
							| 
									
										
										
										
											2019-02-10 11:57:19 +01:00
										 |  |  |     "         " | 
					
						
							|  |  |  |     "    #    " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "  #####  " | 
					
						
							|  |  |  |     " ####### " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "         " | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char* s_down_arrow_bitmap_data = { | 
					
						
							| 
									
										
										
										
											2019-02-10 11:57:19 +01:00
										 |  |  |     "         " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     " ####### " | 
					
						
							|  |  |  |     "  #####  " | 
					
						
							|  |  |  |     "   ###   " | 
					
						
							|  |  |  |     "    #    " | 
					
						
							|  |  |  |     "         " | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  | static const char* s_left_arrow_bitmap_data = { | 
					
						
							|  |  |  |     "         " | 
					
						
							|  |  |  |     "    #    " | 
					
						
							|  |  |  |     "   ##    " | 
					
						
							|  |  |  |     "  ###### " | 
					
						
							|  |  |  |     " ####### " | 
					
						
							|  |  |  |     "  ###### " | 
					
						
							|  |  |  |     "   ##    " | 
					
						
							|  |  |  |     "    #    " | 
					
						
							|  |  |  |     "         " | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char* s_right_arrow_bitmap_data = { | 
					
						
							|  |  |  |     "         " | 
					
						
							|  |  |  |     "    #    " | 
					
						
							|  |  |  |     "    ##   " | 
					
						
							|  |  |  |     " ######  " | 
					
						
							|  |  |  |     " ####### " | 
					
						
							|  |  |  |     " ######  " | 
					
						
							|  |  |  |     "    ##   " | 
					
						
							|  |  |  |     "    #    " | 
					
						
							|  |  |  |     "         " | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  | static CharacterBitmap* s_up_arrow_bitmap; | 
					
						
							|  |  |  | static CharacterBitmap* s_down_arrow_bitmap; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  | static CharacterBitmap* s_left_arrow_bitmap; | 
					
						
							|  |  |  | static CharacterBitmap* s_right_arrow_bitmap; | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 11:57:19 +01:00
										 |  |  | GScrollBar::GScrollBar(Orientation orientation, GWidget* parent) | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  |     : GWidget(parent) | 
					
						
							| 
									
										
										
										
											2019-02-10 11:57:19 +01:00
										 |  |  |     , m_orientation(orientation) | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  |     if (!s_up_arrow_bitmap) | 
					
						
							| 
									
										
										
										
											2019-02-25 16:04:08 +01:00
										 |  |  |         s_up_arrow_bitmap = &CharacterBitmap::create_from_ascii(s_up_arrow_bitmap_data, 9, 9).leak_ref(); | 
					
						
							| 
									
										
										
										
											2019-02-10 08:23:03 +01:00
										 |  |  |     if (!s_down_arrow_bitmap) | 
					
						
							| 
									
										
										
										
											2019-02-25 16:04:08 +01:00
										 |  |  |         s_down_arrow_bitmap = &CharacterBitmap::create_from_ascii(s_down_arrow_bitmap_data, 9, 9).leak_ref(); | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     if (!s_left_arrow_bitmap) | 
					
						
							| 
									
										
										
										
											2019-02-25 16:04:08 +01:00
										 |  |  |         s_left_arrow_bitmap = &CharacterBitmap::create_from_ascii(s_left_arrow_bitmap_data, 9, 9).leak_ref(); | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     if (!s_right_arrow_bitmap) | 
					
						
							| 
									
										
										
										
											2019-02-25 16:04:08 +01:00
										 |  |  |         s_right_arrow_bitmap = &CharacterBitmap::create_from_ascii(s_right_arrow_bitmap_data, 9, 9).leak_ref(); | 
					
						
							| 
									
										
										
										
											2019-02-10 11:57:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_orientation == Orientation::Vertical) { | 
					
						
							|  |  |  |         set_preferred_size({ 15, 0 }); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         set_preferred_size({ 0, 15 }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     m_automatic_scrolling_timer.set_interval(100); | 
					
						
							|  |  |  |     m_automatic_scrolling_timer.on_timeout = [this] { | 
					
						
							|  |  |  |         on_automatic_scrolling_timer_fired(); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GScrollBar::~GScrollBar() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GScrollBar::set_range(int min, int max) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ASSERT(min <= max); | 
					
						
							|  |  |  |     if (m_min == min && m_max == max) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_min = min; | 
					
						
							|  |  |  |     m_max = max; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int old_value = m_value; | 
					
						
							|  |  |  |     if (m_value < m_min) | 
					
						
							|  |  |  |         m_value = m_min; | 
					
						
							|  |  |  |     if (m_value > m_max) | 
					
						
							|  |  |  |         m_value = m_max; | 
					
						
							|  |  |  |     if (on_change && m_value != old_value) | 
					
						
							|  |  |  |         on_change(m_value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GScrollBar::set_value(int value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (value < m_min) | 
					
						
							|  |  |  |         value = m_min; | 
					
						
							|  |  |  |     if (value > m_max) | 
					
						
							|  |  |  |         value = m_max; | 
					
						
							|  |  |  |     if (value == m_value) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     m_value = value; | 
					
						
							|  |  |  |     if (on_change) | 
					
						
							|  |  |  |         on_change(value); | 
					
						
							|  |  |  |     update(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  | Rect GScrollBar::decrement_button_rect() const | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |     return { 0, 0, button_width(), button_height() }; | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  | Rect GScrollBar::increment_button_rect() const | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     if (orientation() == Orientation::Vertical) | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { 0, height() - button_height(), button_width(), button_height() }; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { width() - button_width(), 0, button_width(), button_height() }; | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  | Rect GScrollBar::decrement_gutter_rect() const | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     if (orientation() == Orientation::Vertical) | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { 0, button_height(), button_width(), scrubber_rect().top() - button_height() }; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { button_width(), 0, scrubber_rect().x() - button_width(), button_height() }; | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  | Rect GScrollBar::increment_gutter_rect() const | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     auto scrubber_rect = this->scrubber_rect(); | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     if (orientation() == Orientation::Vertical) | 
					
						
							| 
									
										
										
										
											2019-06-07 11:46:02 +02:00
										 |  |  |         return { 0, scrubber_rect.bottom() + 1, button_width(), height() - button_height() - scrubber_rect.bottom() - 1 }; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { scrubber_rect.right() + 1, 0, width() - button_width() - scrubber_rect.right() - 1, button_width() }; | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  | int GScrollBar::scrubbable_range_in_pixels() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     if (orientation() == Orientation::Vertical) | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return height() - button_height() * 2 - scrubber_size(); | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return width() - button_width() * 2 - scrubber_size(); | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 07:11:01 +01:00
										 |  |  | bool GScrollBar::has_scrubber() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_max != m_min; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-29 02:51:19 +01:00
										 |  |  | int GScrollBar::scrubber_size() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-01 02:46:36 -05:00
										 |  |  |     int pixel_range = length(orientation()) - button_size() * 2; | 
					
						
							| 
									
										
										
										
											2019-03-29 02:51:19 +01:00
										 |  |  |     int value_range = m_max - m_min; | 
					
						
							|  |  |  |     return ::max(pixel_range - value_range, button_size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | Rect GScrollBar::scrubber_rect() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-01 02:46:36 -05:00
										 |  |  |     if (!has_scrubber() || length(orientation()) <= (button_size() * 2) + scrubber_size()) | 
					
						
							| 
									
										
										
										
											2019-06-07 11:46:02 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     float x_or_y; | 
					
						
							|  |  |  |     if (m_value == m_min) | 
					
						
							| 
									
										
										
										
											2019-03-27 20:48:23 +01:00
										 |  |  |         x_or_y = button_size(); | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else if (m_value == m_max) | 
					
						
							| 
									
										
										
										
											2019-07-01 02:46:36 -05:00
										 |  |  |         x_or_y = (length(orientation()) - button_size() - scrubber_size()) + 1; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else { | 
					
						
							|  |  |  |         float range_size = m_max - m_min; | 
					
						
							|  |  |  |         float available = scrubbable_range_in_pixels(); | 
					
						
							|  |  |  |         float step = available / range_size; | 
					
						
							|  |  |  |         x_or_y = (button_size() + (step * m_value)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (orientation() == Orientation::Vertical) | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { 0, (int)x_or_y, button_width(), scrubber_size() }; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         return { (int)x_or_y, 0, scrubber_size(), button_height() }; | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-28 18:57:36 +01:00
										 |  |  | void GScrollBar::paint_event(GPaintEvent& event) | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-28 17:19:56 +01:00
										 |  |  |     GPainter painter(*this); | 
					
						
							| 
									
										
										
										
											2019-03-29 15:01:54 +01:00
										 |  |  |     painter.add_clip_rect(event.rect()); | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-28 17:29:14 +01:00
										 |  |  |     painter.fill_rect(rect(), Color::from_rgb(0xd6d2ce)); | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  |     StylePainter::paint_button(painter, decrement_button_rect(), ButtonStyle::Normal, false, m_hovered_component == Component::DecrementButton); | 
					
						
							|  |  |  |     StylePainter::paint_button(painter, increment_button_rect(), ButtonStyle::Normal, false, m_hovered_component == Component::IncrementButton); | 
					
						
							| 
									
										
										
										
											2019-07-01 02:46:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (length(orientation()) > default_button_size()) { | 
					
						
							|  |  |  |         painter.draw_bitmap(decrement_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_up_arrow_bitmap : *s_left_arrow_bitmap, has_scrubber() ? Color::Black : Color::MidGray); | 
					
						
							|  |  |  |         painter.draw_bitmap(increment_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_down_arrow_bitmap : *s_right_arrow_bitmap, has_scrubber() ? Color::Black : Color::MidGray); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 07:11:01 +01:00
										 |  |  |     if (has_scrubber()) | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  |         StylePainter::paint_button(painter, scrubber_rect(), ButtonStyle::Normal, false, m_hovered_component == Component::Scrubber); | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  | void GScrollBar::on_automatic_scrolling_timer_fired() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_automatic_scrolling_direction == AutomaticScrollingDirection::Decrement) { | 
					
						
							|  |  |  |         set_value(value() - m_step); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m_automatic_scrolling_direction == AutomaticScrollingDirection::Increment) { | 
					
						
							|  |  |  |         set_value(value() + m_step); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | void GScrollBar::mousedown_event(GMouseEvent& event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (event.button() != GMouseButton::Left) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  |     if (decrement_button_rect().contains(event.position())) { | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  |         m_automatic_scrolling_direction = AutomaticScrollingDirection::Decrement; | 
					
						
							|  |  |  |         set_automatic_scrolling_active(true); | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  |     if (increment_button_rect().contains(event.position())) { | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  |         m_automatic_scrolling_direction = AutomaticScrollingDirection::Increment; | 
					
						
							|  |  |  |         set_automatic_scrolling_active(true); | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-10 07:11:01 +01:00
										 |  |  |     if (has_scrubber() && scrubber_rect().contains(event.position())) { | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  |         m_scrubbing = true; | 
					
						
							|  |  |  |         m_scrub_start_value = value(); | 
					
						
							|  |  |  |         m_scrub_origin = event.position(); | 
					
						
							| 
									
										
										
										
											2019-02-10 07:11:01 +01:00
										 |  |  |         update(); | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 05:03:40 +01:00
										 |  |  |     if (has_scrubber()) { | 
					
						
							|  |  |  |         float range_size = m_max - m_min; | 
					
						
							|  |  |  |         float available = scrubbable_range_in_pixels(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-11 13:16:43 +02:00
										 |  |  |         float x = ::max(0, event.position().x() - button_width() - button_width() / 2); | 
					
						
							|  |  |  |         float y = ::max(0, event.position().y() - button_height() - button_height() / 2); | 
					
						
							| 
									
										
										
										
											2019-03-25 05:03:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         float rel_x = x / available; | 
					
						
							|  |  |  |         float rel_y = y / available; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (orientation() == Orientation::Vertical) | 
					
						
							|  |  |  |             set_value(m_min + rel_y * range_size); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             set_value(m_min + rel_x * range_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_scrubbing = true; | 
					
						
							|  |  |  |         m_scrub_start_value = value(); | 
					
						
							|  |  |  |         m_scrub_origin = event.position(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GScrollBar::mouseup_event(GMouseEvent& event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (event.button() != GMouseButton::Left) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  |     m_automatic_scrolling_direction = AutomaticScrollingDirection::None; | 
					
						
							|  |  |  |     set_automatic_scrolling_active(false); | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  |     if (!m_scrubbing) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     m_scrubbing = false; | 
					
						
							| 
									
										
										
										
											2019-02-10 07:11:01 +01:00
										 |  |  |     update(); | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  | void GScrollBar::set_automatic_scrolling_active(bool active) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (active) { | 
					
						
							|  |  |  |         on_automatic_scrolling_timer_fired(); | 
					
						
							|  |  |  |         m_automatic_scrolling_timer.start(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         m_automatic_scrolling_timer.stop(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  | void GScrollBar::mousemove_event(GMouseEvent& event) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  |     auto old_hovered_component = m_hovered_component; | 
					
						
							|  |  |  |     if (scrubber_rect().contains(event.position())) | 
					
						
							|  |  |  |         m_hovered_component = Component::Scrubber; | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  |     else if (decrement_button_rect().contains(event.position())) | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  |         m_hovered_component = Component::DecrementButton; | 
					
						
							| 
									
										
										
										
											2019-06-07 10:56:30 +02:00
										 |  |  |     else if (increment_button_rect().contains(event.position())) | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  |         m_hovered_component = Component::IncrementButton; | 
					
						
							|  |  |  |     else if (rect().contains(event.position())) | 
					
						
							|  |  |  |         m_hovered_component = Component::Gutter; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         m_hovered_component = Component::Invalid; | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  |     if (old_hovered_component != m_hovered_component) { | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  |         update(); | 
					
						
							| 
									
										
										
										
											2019-06-07 10:43:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (m_automatic_scrolling_direction == AutomaticScrollingDirection::Decrement) | 
					
						
							|  |  |  |             set_automatic_scrolling_active(m_hovered_component == Component::DecrementButton); | 
					
						
							|  |  |  |         else if (m_automatic_scrolling_direction == AutomaticScrollingDirection::Increment) | 
					
						
							|  |  |  |             set_automatic_scrolling_active(m_hovered_component == Component::IncrementButton); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  |     if (!m_scrubbing) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-02-10 12:26:58 +01:00
										 |  |  |     float delta = orientation() == Orientation::Vertical ? (event.y() - m_scrub_origin.y()) : (event.x() - m_scrub_origin.x()); | 
					
						
							| 
									
										
										
										
											2019-02-10 06:51:01 +01:00
										 |  |  |     float scrubbable_range = scrubbable_range_in_pixels(); | 
					
						
							|  |  |  |     float value_steps_per_scrubbed_pixel = (m_max - m_min) / scrubbable_range; | 
					
						
							|  |  |  |     float new_value = m_scrub_start_value + (value_steps_per_scrubbed_pixel * delta); | 
					
						
							|  |  |  |     set_value(new_value); | 
					
						
							| 
									
										
										
										
											2019-02-09 11:19:38 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 16:56:55 +02:00
										 |  |  | void GScrollBar::leave_event(CEvent&) | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-10 01:50:10 +02:00
										 |  |  |     if (m_hovered_component != Component::Invalid) { | 
					
						
							|  |  |  |         m_hovered_component = Component::Invalid; | 
					
						
							|  |  |  |         update(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-06 13:55:56 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-25 13:40:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void GScrollBar::change_event(GEvent& event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (event.type() == GEvent::Type::EnabledChange) { | 
					
						
							|  |  |  |         if (!is_enabled()) | 
					
						
							|  |  |  |             m_scrubbing = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return GWidget::change_event(event); | 
					
						
							|  |  |  | } |