Extend CScrollRegion to support scrolling when mouse at edge

Add `ScrollRelative` function to initiate relative scrolling programmatically, to realise scroll regions that scroll when the mouse is being dragged at the edge.

Add `DoEdgeScrolling` to encapsulate all the necessary edge scrolling logic based on the position of the mouse. The edge scrolling starts at a fixed distance from the edges. The scrolling speed is dependent on the distance of the mouse from this border.
This commit is contained in:
Robert Müller 2023-03-16 12:22:59 +01:00
parent 762f1a1262
commit 66ad9536fe
2 changed files with 54 additions and 8 deletions

View file

@ -13,11 +13,15 @@ CScrollRegion::CScrollRegion()
{
m_ScrollY = 0.0f;
m_ContentH = 0.0f;
m_RequestScrollY = -1.0f;
m_ScrollDirection = SCROLLRELATIVE_NONE;
m_ScrollSpeedMultiplier = 1.0f;
m_AnimTimeMax = 0.0f;
m_AnimTime = 0.0f;
m_AnimInitScrollY = 0.0f;
m_AnimTargetScrollY = 0.0f;
m_RequestScrollY = -1.0f;
m_ContentScrollOff = vec2(0.0f, 0.0f);
m_Params = CScrollRegionParams();
}
@ -69,23 +73,30 @@ void CScrollRegion::End()
CUIRect RegionRect = m_ClipRect;
RegionRect.w += m_Params.m_ScrollbarWidth;
if(UI()->Enabled() && UI()->MouseHovered(&RegionRect))
if(m_ScrollDirection != SCROLLRELATIVE_NONE || (UI()->Enabled() && UI()->MouseHovered(&RegionRect)))
{
float ScrollDirection = 0.0f;
bool ProgrammaticScroll = false;
if(UI()->ConsumeHotkey(CUI::HOTKEY_SCROLL_UP))
ScrollDirection = -1.0f;
m_ScrollDirection = SCROLLRELATIVE_UP;
else if(UI()->ConsumeHotkey(CUI::HOTKEY_SCROLL_DOWN))
ScrollDirection = 1.0f;
m_ScrollDirection = SCROLLRELATIVE_DOWN;
else
ProgrammaticScroll = true;
if(ScrollDirection != 0.0f)
if(!ProgrammaticScroll)
m_ScrollSpeedMultiplier = 1.0f;
if(m_ScrollDirection != SCROLLRELATIVE_NONE)
{
const bool IsPageScroll = Input()->AltIsPressed();
const float ScrollUnit = IsPageScroll ? m_ClipRect.h : m_Params.m_ScrollUnit;
const float ScrollUnit = IsPageScroll && !ProgrammaticScroll ? m_ClipRect.h : m_Params.m_ScrollUnit;
m_AnimTimeMax = g_Config.m_UiSmoothScrollTime / 1000.0f;
m_AnimTime = m_AnimTimeMax;
m_AnimInitScrollY = m_ScrollY;
m_AnimTargetScrollY += ScrollDirection * ScrollUnit;
m_AnimTargetScrollY = (ProgrammaticScroll ? m_ScrollY : m_AnimTargetScrollY) + (int)m_ScrollDirection * ScrollUnit * m_ScrollSpeedMultiplier;
m_ScrollDirection = SCROLLRELATIVE_NONE;
m_ScrollSpeedMultiplier = 1.0f;
}
}
@ -206,6 +217,28 @@ void CScrollRegion::ScrollHere(EScrollOption Option)
}
}
void CScrollRegion::ScrollRelative(EScrollRelative Direction, float SpeedMultiplier)
{
m_ScrollDirection = Direction;
m_ScrollSpeedMultiplier = SpeedMultiplier;
}
void CScrollRegion::DoEdgeScrolling()
{
if(!IsScrollbarShown())
return;
const float ScrollBorderSize = 20.0f;
const float MaxScrollMultiplier = 2.0f;
const float ScrollSpeedFactor = MaxScrollMultiplier / ScrollBorderSize;
const float TopScrollPosition = m_ClipRect.y + ScrollBorderSize;
const float BottomScrollPosition = m_ClipRect.y + m_ClipRect.h - ScrollBorderSize;
if(UI()->MouseY() < TopScrollPosition)
ScrollRelative(SCROLLRELATIVE_UP, minimum(MaxScrollMultiplier, (TopScrollPosition - UI()->MouseY()) * ScrollSpeedFactor));
else if(UI()->MouseY() > BottomScrollPosition)
ScrollRelative(SCROLLRELATIVE_DOWN, minimum(MaxScrollMultiplier, (UI()->MouseY() - BottomScrollPosition) * ScrollSpeedFactor));
}
bool CScrollRegion::IsRectClipped(const CUIRect &Rect) const
{
return (m_ClipRect.x > (Rect.x + Rect.w) || (m_ClipRect.x + m_ClipRect.w) < Rect.x || m_ClipRect.y > (Rect.y + Rect.h) || (m_ClipRect.y + m_ClipRect.h) < Rect.y);

View file

@ -86,10 +86,20 @@ Usage:
// Instances of CScrollRegion must be static, as member addresses are used as UI item IDs
class CScrollRegion : private CUIElementBase
{
public:
enum EScrollRelative
{
SCROLLRELATIVE_UP = -1,
SCROLLRELATIVE_NONE = 0,
SCROLLRELATIVE_DOWN = 1,
};
private:
float m_ScrollY;
float m_ContentH;
float m_RequestScrollY; // [0, ContentHeight]
EScrollRelative m_ScrollDirection;
float m_ScrollSpeedMultiplier;
float m_AnimTimeMax;
float m_AnimTime;
@ -116,6 +126,9 @@ public:
void End();
bool AddRect(const CUIRect &Rect, bool ShouldScrollHere = false); // returns true if the added rect is visible (not clipped)
void ScrollHere(EScrollOption Option = SCROLLHERE_KEEP_IN_VIEW);
void ScrollRelative(EScrollRelative Direction, float SpeedMultiplier = 1.0f);
const CUIRect *ClipRect() const { return &m_ClipRect; }
void DoEdgeScrolling();
bool IsRectClipped(const CUIRect &Rect) const;
bool IsScrollbarShown() const;
bool IsAnimating() const;