1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef GAME_CLIENT_UI_SCROLLREGION_H
4#define GAME_CLIENT_UI_SCROLLREGION_H
5
6#include "ui.h"
7
8struct CScrollRegionParams
9{
10 float m_ScrollbarThickness;
11 float m_ScrollbarMargin;
12 bool m_ScrollbarNoOuterMargin;
13 float m_SliderMinSize;
14 float m_ScrollUnit;
15 ColorRGBA m_ClipBgColor;
16 ColorRGBA m_ScrollbarBgColor;
17 ColorRGBA m_RailBgColor;
18 ColorRGBA m_SliderColor;
19 ColorRGBA m_SliderColorHover;
20 ColorRGBA m_SliderColorGrabbed;
21 bool m_ForceShowScrollbar;
22 bool m_ScrollHorizontal;
23
24 CScrollRegionParams()
25 {
26 m_ScrollbarThickness = 20.0f;
27 m_ScrollbarMargin = 5.0f;
28 m_ScrollbarNoOuterMargin = false;
29 m_SliderMinSize = 25.0f;
30 m_ScrollUnit = 10.0f;
31 m_ClipBgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
32 m_ScrollbarBgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
33 m_RailBgColor = ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f);
34 m_SliderColor = ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
35 m_SliderColorHover = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
36 m_SliderColorGrabbed = ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f);
37 m_ForceShowScrollbar = false;
38 m_ScrollHorizontal = false;
39 }
40
41 ColorRGBA SliderColor(bool Active, bool Hovered) const
42 {
43 if(Active)
44 return m_SliderColorGrabbed;
45 else if(Hovered)
46 return m_SliderColorHover;
47 return m_SliderColor;
48 }
49};
50
51/*
52Usage example:
53
54 // -- Layout --
55 CUIRect View = ...; // parent UI rect initialized elsewhere
56 CUIRect Content; // rect for scrollable content
57 View.HSplitTop(500.0f, &Content, &View); // split maximum size of scrollable content
58
59 // -- Initialization --
60 static CScrollRegion s_ScrollRegion;
61 s_ScrollRegion.Begin(&Content);
62 // Content rect is now offset by the scroll offset
63
64 // -- [Optional] Initialization with parameters --
65 static CScrollRegion s_ScrollRegion;
66 CScrollRegionParams ScrollParams;
67 ScrollParams.m_ScrollUnit = 3 * LineHeight;
68 s_ScrollRegion.Begin(&Content, &ScrollParams);
69 // Content rect is now offset by the scroll offset
70
71 // -- "Register" your content rects --
72 CUIRect Rect;
73 Content.HSplitTop(SomeValue, &Rect, &Content);
74 s_ScrollRegion.AddRect(Rect);
75
76 // -- [Optional] Knowing if a rect is clipped --
77 s_ScrollRegion.RectClipped(Rect);
78
79 // -- [Optional] Scroll to the last added rect --
80 s_ScrollRegion.AddRect(Rect);
81 s_ScrollRegion.ScrollHere(Option);
82
83 // -- [Convenience] Add rect and check for visibility at the same time --
84 if(s_ScrollRegion.AddRect(Rect))
85 {
86 // The rect is visible (not clipped)
87 }
88
89 // -- [Convenience] Add rect and scroll to it if it's selected --
90 if(s_ScrollRegion.AddRect(Rect, ScrollToSelection && IsSelected))
91 {
92 // The rect is visible (not clipped)
93 }
94
95 // -- End --
96 s_ScrollRegion.End();
97*/
98
99// Instances of CScrollRegion must be static, as member addresses are used as UI item IDs
100class CScrollRegion : private CUIElementBase
101{
102public:
103 enum EScrollRelative
104 {
105 SCROLLRELATIVE_UP = -1,
106 SCROLLRELATIVE_NONE = 0,
107 SCROLLRELATIVE_DOWN = 1,
108 };
109
110private:
111 float m_ScrollPos;
112 float m_ContentSize;
113 float m_RequestScrollPos; // [0, ContentSize]
114 EScrollRelative m_ScrollDirection;
115 float m_ScrollSpeedMultiplier;
116
117 float m_AnimTimeMax;
118 float m_AnimTime;
119 float m_AnimInitScrollPos;
120 float m_AnimTargetScrollPos;
121
122 CUIRect m_ContentAreaRect;
123 CUIRect m_RailRect;
124 CUIRect m_LastAddedRect; // saved for ScrollHere()
125 float m_SliderGrabPos; // where did user grab the slider
126 float m_ContentScrollOffset;
127 CScrollRegionParams m_Params;
128
129public:
130 enum EScrollOption
131 {
132 SCROLLHERE_KEEP_IN_VIEW = 0,
133 SCROLLHERE_TOP,
134 SCROLLHERE_BOTTOM,
135 };
136
137 CScrollRegion();
138 void Reset();
139
140 void Begin(CUIRect *pClipRect, const CScrollRegionParams *pParams = nullptr);
141 void End();
142 bool AddRect(const CUIRect &Rect, bool ShouldScrollHere = false); // returns true if the added rect is visible (not clipped)
143 void ScrollHere(EScrollOption Option = SCROLLHERE_KEEP_IN_VIEW);
144 void ScrollRelative(EScrollRelative Direction, float SpeedMultiplier = 1.0f);
145 void ScrollRelativeDirect(vec2 ScrollAmount);
146 void DoEdgeScrolling();
147 bool RectClipped(const CUIRect &Rect) const;
148 bool ContentOverflows() const;
149 bool ScrollbarShown() const;
150 bool Animating() const;
151 bool Active() const;
152
153private:
154 float ContentAreaPos() const;
155 float ContentAreaSize() const;
156 float MaxScroll() const;
157 CUIRect SplitContentArea();
158 void DrawBackground(const CUIRect &ScrollbarBg);
159 void DoScrollInput();
160 void UpdateHotScrollRegion();
161 void AdvanceAnimation();
162 void DoSlider();
163};
164
165#endif
166