Bläddra i källkod

Use smooth scrolling when interacting with scrollbar arrows and track

Michael Ragazzon 2 år sedan
förälder
incheckning
930e1bdb79
3 ändrade filer med 76 tillägg och 115 borttagningar
  1. 0 1
      Source/Core/ElementScroll.cpp
  2. 64 84
      Source/Core/WidgetScroll.cpp
  3. 12 30
      Source/Core/WidgetScroll.h

+ 0 - 1
Source/Core/ElementScroll.cpp

@@ -179,7 +179,6 @@ void ElementScroll::FormatScrollbars()
 		slider_length -= Math::Max(user_scrollbar_margin, min_scrollbar_margin);
 
 		scrollbars[i].widget->FormatElements(containing_block, slider_length);
-		scrollbars[i].widget->SetLineHeight(element->GetLineHeight());
 
 		int variable_axis = i == VERTICAL ? 0 : 1;
 		Vector2f offset = element_box.GetPosition(Box::PADDING);

+ 64 - 84
Source/Core/WidgetScroll.cpp

@@ -29,6 +29,7 @@
 #include "WidgetScroll.h"
 #include "../../Include/RmlUi/Core/ComputedValues.h"
 #include "../../Include/RmlUi/Core/Element.h"
+#include "../../Include/RmlUi/Core/ElementUtilities.h"
 #include "../../Include/RmlUi/Core/Event.h"
 #include "../../Include/RmlUi/Core/Factory.h"
 #include "../../Include/RmlUi/Core/Property.h"
@@ -37,8 +38,11 @@
 
 namespace Rml {
 
-static const float DEFAULT_REPEAT_DELAY = 0.5f;
-static const float DEFAULT_REPEAT_PERIOD = 0.1f;
+static constexpr float DEFAULT_REPEAT_DELAY = 0.5f;
+static constexpr float DEFAULT_REPEAT_PERIOD = 0.1f;
+
+static constexpr float SCROLL_LINE_LENGTH = 30.f; // [dp]
+static constexpr float SCROLL_PAGE_FACTOR = 0.8f;
 
 WidgetScroll::WidgetScroll(Element* _parent)
 {
@@ -60,7 +64,6 @@ WidgetScroll::WidgetScroll(Element* _parent)
 
 	track_length = 0;
 	bar_length = 0;
-	line_height = 12;
 }
 
 WidgetScroll::~WidgetScroll()
@@ -161,7 +164,10 @@ void WidgetScroll::Update()
 			while (arrow_timers[i] <= 0)
 			{
 				arrow_timers[i] += DEFAULT_REPEAT_PERIOD;
-				SetBarPosition(i == 0 ? OnLineDecrement() : OnLineIncrement());
+				if (i == 0)
+					ScrollLineUp();
+				else
+					ScrollLineDown();
 			}
 		}
 	}
@@ -172,19 +178,6 @@ void WidgetScroll::SetBarPosition(float _bar_position)
 {
 	bar_position = Math::Clamp(_bar_position, 0.0f, 1.0f);
 	PositionBar();
-	
-	// 'parent' is the scrollbar element, its parent again is the actual element we want to scroll
-	Element* element_scroll = parent->GetParentNode();
-	if (!element_scroll)
-	{
-		RMLUI_ERROR;
-		return;
-	}
-	
-	if (orientation == VERTICAL)
-		element_scroll->SetScrollTop(bar_position * (element_scroll->GetScrollHeight() - element_scroll->GetClientHeight()));
-	else if (orientation == HORIZONTAL)
-		element_scroll->SetScrollLeft(bar_position * (element_scroll->GetScrollWidth() - element_scroll->GetClientWidth()));
 }
 
 // Returns the current position of the bar.
@@ -372,57 +365,57 @@ void WidgetScroll::ProcessEvent(Event& event)
 	{
 		if (event == EventId::Drag)
 		{
+			float new_bar_position = 0.f;
 			if (orientation == HORIZONTAL)
 			{
-				float traversable_track_length = track->GetBox().GetSize(Box::CONTENT).x - bar->GetBox().GetSize(Box::CONTENT).x;
+				float traversable_track_length = track->GetBox().GetSize().x - bar->GetBox().GetSize().x;
 				if (traversable_track_length > 0)
 				{
 					float traversable_track_origin = track->GetAbsoluteOffset().x + bar_drag_anchor;
-					float new_bar_position = (event.GetParameter< float >("mouse_x", 0) - traversable_track_origin) / traversable_track_length;
-					new_bar_position = Math::Clamp(new_bar_position, 0.0f, 1.0f);
-
-					SetBarPosition(new_bar_position);
+					new_bar_position = (event.GetParameter("mouse_x", 0.f) - traversable_track_origin) / traversable_track_length;
 				}
 			}
 			else
 			{
-				float traversable_track_length = track->GetBox().GetSize(Box::CONTENT).y - bar->GetBox().GetSize(Box::CONTENT).y;
+				float traversable_track_length = track->GetBox().GetSize().y - bar->GetBox().GetSize().y;
 				if (traversable_track_length > 0)
 				{
 					float traversable_track_origin = track->GetAbsoluteOffset().y + bar_drag_anchor;
-					float new_bar_position = (event.GetParameter< float >("mouse_y", 0) - traversable_track_origin) / traversable_track_length;
-					new_bar_position = Math::Clamp(new_bar_position, 0.0f, 1.0f);
-
-					SetBarPosition(new_bar_position);
+					new_bar_position = (event.GetParameter("mouse_y", 0.f) - traversable_track_origin) / traversable_track_length;
 				}
 			}
+
+			SetBarPosition(new_bar_position);
+			Scroll(0.f, ScrollBehavior::Instant);
 		}
 		else if (event == EventId::Dragstart)
 		{
 			if (orientation == HORIZONTAL)
-				bar_drag_anchor = event.GetParameter< int >("mouse_x", 0) - Math::RealToInteger(bar->GetAbsoluteOffset().x);
+				bar_drag_anchor = event.GetParameter("mouse_x", 0.f) - bar->GetAbsoluteOffset().x;
 			else
-				bar_drag_anchor = event.GetParameter< int >("mouse_y", 0) - Math::RealToInteger(bar->GetAbsoluteOffset().y);
+				bar_drag_anchor = event.GetParameter("mouse_y", 0.f) - bar->GetAbsoluteOffset().y;
 		}
 	}
 	else if (event.GetTargetElement() == track)
 	{
 		if (event == EventId::Click)
 		{
+			float click_position = 0.f;
 			if (orientation == HORIZONTAL)
 			{
-				float mouse_position = event.GetParameter< float >("mouse_x", 0);
-				float click_position = (mouse_position - track->GetAbsoluteOffset().x) / track->GetBox().GetSize().x;
-
-				SetBarPosition(click_position <= bar_position ? OnPageDecrement() : OnPageIncrement());
+				float mouse_position = event.GetParameter("mouse_x", 0.f);
+				click_position = (mouse_position - track->GetAbsoluteOffset().x) / track->GetBox().GetSize().x;
 			}
 			else
 			{
-				float mouse_position = event.GetParameter< float >("mouse_y", 0);
-				float click_position = (mouse_position - track->GetAbsoluteOffset().y) / track->GetBox().GetSize().y;
-
-				SetBarPosition(click_position <= bar_position ? OnPageDecrement() : OnPageIncrement());
+				float mouse_position = event.GetParameter<float>("mouse_y", 0);
+				click_position = (mouse_position - track->GetAbsoluteOffset().y) / track->GetBox().GetSize().y;
 			}
+
+			if (click_position <= bar_position)
+				ScrollPageUp();
+			else
+				ScrollPageDown();
 		}
 	}
 
@@ -432,13 +425,13 @@ void WidgetScroll::ProcessEvent(Event& event)
 		{
 			arrow_timers[0] = DEFAULT_REPEAT_DELAY;
 			last_update_time = Clock::GetElapsedTime();
-			SetBarPosition(OnLineDecrement());
+			ScrollLineUp();
 		}
 		else if (event.GetTargetElement() == arrows[1])
 		{
 			arrow_timers[1] = DEFAULT_REPEAT_DELAY;
 			last_update_time = Clock::GetElapsedTime();
-			SetBarPosition(OnLineIncrement());
+			ScrollLineDown();
 		}
 	}
 	else if (event == EventId::Mouseup ||
@@ -468,36 +461,16 @@ void WidgetScroll::PositionBar()
 	}
 }
 
-
-
 // Sets the length of the entire track in some arbitrary unit.
-void WidgetScroll::SetTrackLength(float _track_length, bool RMLUI_UNUSED_PARAMETER(force_resize))
+void WidgetScroll::SetTrackLength(float _track_length)
 {
-	RMLUI_UNUSED(force_resize);
-
-	if (track_length != _track_length)
-	{
-		track_length = _track_length;
-		//		GenerateBar();
-	}
+	track_length = _track_length;
 }
 
 // Sets the length the bar represents in some arbitrary unit, relative to the track length.
-void WidgetScroll::SetBarLength(float _bar_length, bool RMLUI_UNUSED_PARAMETER(force_resize))
-{
-	RMLUI_UNUSED(force_resize);
-
-	if (bar_length != _bar_length)
-	{
-		bar_length = _bar_length;
-		//		GenerateBar();
-	}
-}
-
-// Sets the line height of the parent element; this is used for scrolling speeds.
-void WidgetScroll::SetLineHeight(float _line_height)
+void WidgetScroll::SetBarLength(float _bar_length)
 {
-	line_height = _line_height;
+	bar_length = _bar_length;
 }
 
 // Lays out and resizes the internal elements.
@@ -515,42 +488,49 @@ void WidgetScroll::FormatElements(const Vector2f containing_block, float slider_
 	WidgetScroll::FormatElements(containing_block, true, slider_length, relative_bar_length);
 }
 
-// Called when the slider is incremented by one 'line', either by the down / right key or a mouse-click on the
-// increment arrow.
-float WidgetScroll::OnLineIncrement()
+void WidgetScroll::ScrollLineDown()
 {
-	return Scroll(line_height);
+	Scroll(SCROLL_LINE_LENGTH * ElementUtilities::GetDensityIndependentPixelRatio(parent), ScrollBehavior::Smooth);
 }
 
-// Called when the slider is decremented by one 'line', either by the up / left key or a mouse-click on the decrement
-// arrow.
-float WidgetScroll::OnLineDecrement()
+void WidgetScroll::ScrollLineUp()
 {
-	return Scroll(-line_height);
+	Scroll(-SCROLL_LINE_LENGTH * ElementUtilities::GetDensityIndependentPixelRatio(parent), ScrollBehavior::Smooth);
 }
 
-// Called when the slider is incremented by one 'page', either by the page-up key or a mouse-click on the track
-// below / right of the bar.
-float WidgetScroll::OnPageIncrement()
+void WidgetScroll::ScrollPageDown()
 {
-	return Scroll(bar_length);
+	Scroll(SCROLL_PAGE_FACTOR * bar_length, ScrollBehavior::Smooth);
 }
 
-// Called when the slider is incremented by one 'page', either by the page-down key or a mouse-click on the track
-// above / left of the bar.
-float WidgetScroll::OnPageDecrement()
+void WidgetScroll::ScrollPageUp()
 {
-	return Scroll(-bar_length);
+	Scroll(-SCROLL_PAGE_FACTOR * bar_length, ScrollBehavior::Smooth);
 }
 
-// Returns the bar position after scrolling for a number of pixels.
-float WidgetScroll::Scroll(float distance)
+void WidgetScroll::Scroll(float distance, ScrollBehavior behavior)
 {
 	float traversable_track_length = (track_length - bar_length);
-	if (traversable_track_length <= 0)
-		return bar_position;
 
-	return (bar_position * traversable_track_length + distance) / traversable_track_length;
+	float new_bar_position = bar_position;
+	if (traversable_track_length > 0.f)
+		new_bar_position = Math::Clamp((bar_position * traversable_track_length + distance) / traversable_track_length, 0.f, 1.f);
+
+	// 'parent' is the scrollbar element, its parent again is the actual element we want to scroll
+	Element* element_scroll = parent->GetParentNode();
+	if (!element_scroll)
+	{
+		RMLUI_ERROR;
+		return;
+	}
+
+	Vector2f scroll_offset = {element_scroll->GetScrollLeft(), element_scroll->GetScrollTop()};
+	if (orientation == HORIZONTAL)
+		scroll_offset.x = new_bar_position * (element_scroll->GetScrollWidth() - element_scroll->GetClientWidth());
+	else
+		scroll_offset.y = new_bar_position * (element_scroll->GetScrollHeight() - element_scroll->GetClientHeight());
+
+	element_scroll->ScrollTo(scroll_offset, behavior);
 }
 
 } // namespace Rml

+ 12 - 30
Source/Core/WidgetScroll.h

@@ -34,6 +34,7 @@
 namespace Rml {
 
 class Element;
+enum class ScrollBehavior;
 
 /**
 	A widget for incorporating scrolling functionality into an element.
@@ -78,18 +79,12 @@ public:
 	/// Sets the length of the entire track in scrollable units (usually lines or characters). This affects the
 	/// length of the bar element and the speed of scrolling using the mouse-wheel or arrows.
 	/// @param[in] track_length The length of the track.
-	/// @param[in] force_resize True to resize the bar immediately, false to wait until the next format.
-	void SetTrackLength(float track_length, bool force_resize = true);
+	void SetTrackLength(float track_length);
 	/// Sets the length the bar represents in scrollable units (usually lines or characters), relative to the track
 	/// length. For example, for a scroll bar, this would represent how big each visible 'page' is compared to the
 	/// whole document (which would be set as the track length).
 	/// @param[in] bar_length The length of the slider's bar.
-	/// @param[in] force_resize True to resize the bar immediately, false to wait until the next format.
-	void SetBarLength(float bar_length, bool force_resize = true);
-
-	/// Sets the line height of the parent element; this is used for scrolling speeds.
-	/// @param[in] line_height The line height of the parent element.
-	void SetLineHeight(float line_height);
+	void SetBarLength(float bar_length);
 
 	/// Lays out and resizes the internal elements.
 	/// @param[in] containing_block The padded box containing the slider. This is used to resolve relative properties.
@@ -110,28 +105,16 @@ private:
 	/// @param[in] bar_length The total length of the bar, as a proportion of the track length. If this is -1, the intrinsic length will be used.
 	void FormatBar(float bar_length = -1);
 
-	// Set the offset on 'bar' from its position.
+	// Set the offset on 'bar' based on its position.
 	void PositionBar();
 
-	/// Called when the slider is incremented by one 'line', either by the down / right key or a mouse-click on the
-	/// increment arrow.
-	/// @return The new position of the bar.
-	float OnLineIncrement();
-	/// Called when the slider is decremented by one 'line', either by the up / left key or a mouse-click on the
-	/// decrement arrow.
-	/// @return The new position of the bar.
-	float OnLineDecrement();
-	/// Called when the slider is incremented by one 'page', either by the page-up key or a mouse-click on the
-	/// track below / right of the bar.
-	/// @return The new position of the bar.
-	float OnPageIncrement();
-	/// Called when the slider is incremented by one 'page', either by the page-down key or a mouse-click on the
-	/// track above / left of the bar.
-	/// @return The new position of the bar.
-	float OnPageDecrement();
-
-	// Returns the bar position after scrolling for a number of pixels.
-	float Scroll(float distance);
+	void ScrollLineDown();
+	void ScrollLineUp();
+	void ScrollPageDown();
+	void ScrollPageUp();
+
+	// Scrolls the parent element by the given distance.
+	void Scroll(float distance, ScrollBehavior behavior);
 
 	Element* parent;
 
@@ -147,7 +130,7 @@ private:
 	// A number from 0 to 1, indicating how far along the track the bar is.
 	float bar_position;
 	// If the bar is being dragged, this is the pixel offset from the start of the bar to where it was picked up.
-	int bar_drag_anchor;
+	float bar_drag_anchor;
 
 	// Set to the auto-repeat timer if either of the arrow buttons have been pressed, -1 if they haven't.
 	float arrow_timers[2];
@@ -155,7 +138,6 @@ private:
 
 	float track_length;
 	float bar_length;
-	float line_height;
 };
 
 } // namespace Rml