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_ScrollbarWidth;
11 float m_ScrollbarMargin;
12 bool m_ScrollbarNoMarginRight;
13 float m_SliderMinHeight;
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 unsigned m_Flags;
22
23 enum
24 {
25 FLAG_CONTENT_STATIC_WIDTH = 1 << 0,
26 };
27
28 CScrollRegionParams()
29 {
30 m_ScrollbarWidth = 20.0f;
31 m_ScrollbarMargin = 5.0f;
32 m_ScrollbarNoMarginRight = false;
33 m_SliderMinHeight = 25.0f;
34 m_ScrollUnit = 10.0f;
35 m_ClipBgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
36 m_ScrollbarBgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.0f);
37 m_RailBgColor = ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f);
38 m_SliderColor = ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
39 m_SliderColorHover = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
40 m_SliderColorGrabbed = ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f);
41 m_Flags = 0;
42 }
43
44 ColorRGBA SliderColor(bool Active, bool Hovered) const
45 {
46 if(Active)
47 return m_SliderColorGrabbed;
48 else if(Hovered)
49 return m_SliderColorHover;
50 return m_SliderColor;
51 }
52};
53
54/*
55Usage example:
56
57 // -- Layout --
58 CUIRect View = ...; // parent UI rect initialized elsewhere
59 CUIRect Content; // rect for scrollable content
60 View.HSplitTop(500.0f, &Content, &View); // split maximum size of scrollable content
61
62 // -- Initialization --
63 static CScrollRegion s_ScrollRegion;
64 s_ScrollRegion.Begin(&Content);
65 // Content rect is now offset by the scroll offset
66
67 // -- [Optional] Initialization with parameters --
68 static CScrollRegion s_ScrollRegion;
69 CScrollRegionParams ScrollParams;
70 ScrollParams.m_ScrollUnit = 3 * LineHeight;
71 s_ScrollRegion.Begin(&Content, &ScrollParams);
72 // Content rect is now offset by the scroll offset
73
74 // -- "Register" your content rects --
75 CUIRect Rect;
76 Content.HSplitTop(SomeValue, &Rect, &Content);
77 s_ScrollRegion.AddRect(Rect);
78
79 // -- [Optional] Knowing if a rect is clipped --
80 s_ScrollRegion.RectClipped(Rect);
81
82 // -- [Optional] Scroll to the last added rect --
83 s_ScrollRegion.AddRect(Rect);
84 s_ScrollRegion.ScrollHere(Option);
85
86 // -- [Convenience] Add rect and check for visibility at the same time --
87 if(s_ScrollRegion.AddRect(Rect))
88 {
89 // The rect is visible (not clipped)
90 }
91
92 // -- [Convenience] Add rect and scroll to it if it's selected --
93 if(s_ScrollRegion.AddRect(Rect, ScrollToSelection && IsSelected))
94 {
95 // The rect is visible (not clipped)
96 }
97
98 // -- End --
99 s_ScrollRegion.End();
100*/
101
102// Instances of CScrollRegion must be static, as member addresses are used as UI item IDs
103class CScrollRegion : private CUIElementBase
104{
105public:
106 enum EScrollRelative
107 {
108 SCROLLRELATIVE_UP = -1,
109 SCROLLRELATIVE_NONE = 0,
110 SCROLLRELATIVE_DOWN = 1,
111 };
112
113private:
114 float m_ScrollY;
115 float m_ContentH;
116 float m_RequestScrollY; // [0, ContentHeight]
117 EScrollRelative m_ScrollDirection;
118 float m_ScrollSpeedMultiplier;
119
120 float m_AnimTimeMax;
121 float m_AnimTime;
122 float m_AnimInitScrollY;
123 float m_AnimTargetScrollY;
124
125 CUIRect m_ClipRect;
126 CUIRect m_RailRect;
127 CUIRect m_LastAddedRect; // saved for ScrollHere()
128 float m_SliderGrabPos; // where did user grab the slider
129 vec2 m_ContentScrollOff;
130 CScrollRegionParams m_Params;
131
132public:
133 enum EScrollOption
134 {
135 SCROLLHERE_KEEP_IN_VIEW = 0,
136 SCROLLHERE_TOP,
137 SCROLLHERE_BOTTOM,
138 };
139
140 CScrollRegion();
141 void Reset();
142
143 void Begin(CUIRect *pClipRect, const CScrollRegionParams *pParams = nullptr);
144 void End();
145 bool AddRect(const CUIRect &Rect, bool ShouldScrollHere = false); // returns true if the added rect is visible (not clipped)
146 void ScrollHere(EScrollOption Option = SCROLLHERE_KEEP_IN_VIEW);
147 void ScrollRelative(EScrollRelative Direction, float SpeedMultiplier = 1.0f);
148 void ScrollRelativeDirect(float ScrollAmount);
149 const CUIRect *ClipRect() const { return &m_ClipRect; }
150 void DoEdgeScrolling();
151 bool RectClipped(const CUIRect &Rect) const;
152 bool ScrollbarShown() const;
153 bool Animating() const;
154 bool Active() const;
155 const CScrollRegionParams &Params() const { return m_Params; }
156};
157
158#endif
159