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:
56 -- Initialization --
57 static CScrollRegion s_ScrollRegion;
58 vec2 ScrollOffset(0, 0);
59 s_ScrollRegion.Begin(&ScrollRegionRect, &ScrollOffset);
60 Content = ScrollRegionRect;
61 Content.y += ScrollOffset.y;
62
63 -- "Register" your content rects --
64 CUIRect Rect;
65 Content.HSplitTop(SomeValue, &Rect, &Content);
66 s_ScrollRegion.AddRect(Rect);
67
68 -- [Optional] Knowing if a rect is clipped --
69 s_ScrollRegion.RectClipped(Rect);
70
71 -- [Optional] Scroll to a rect (to the last added rect)--
72 ...
73 s_ScrollRegion.AddRect(Rect);
74 s_ScrollRegion.ScrollHere(Option);
75
76 -- [Convenience] Add rect and check for visibility at the same time
77 if(s_ScrollRegion.AddRect(Rect))
78 // The rect is visible (not clipped)
79
80 -- [Convenience] Add rect and scroll to it if it's selected
81 if(s_ScrollRegion.AddRect(Rect, ScrollToSelection && IsSelected))
82 // The rect is visible (not clipped)
83
84 -- End --
85 s_ScrollRegion.End();
86*/
87
88// Instances of CScrollRegion must be static, as member addresses are used as UI item IDs
89class CScrollRegion : private CUIElementBase
90{
91public:
92 // TODO: Properly fix whatever is causing the 1-pixel discrepancy in scrolling rect height and remove this magic value.
93 // Currently this must be added when calculating the required height of a UI rect for a scroll region to get a perfect fit.
94 static constexpr float HEIGHT_MAGIC_FIX = 1.0f;
95
96 enum EScrollRelative
97 {
98 SCROLLRELATIVE_UP = -1,
99 SCROLLRELATIVE_NONE = 0,
100 SCROLLRELATIVE_DOWN = 1,
101 };
102
103private:
104 float m_ScrollY;
105 float m_ContentH;
106 float m_RequestScrollY; // [0, ContentHeight]
107 EScrollRelative m_ScrollDirection;
108 float m_ScrollSpeedMultiplier;
109
110 float m_AnimTimeMax;
111 float m_AnimTime;
112 float m_AnimInitScrollY;
113 float m_AnimTargetScrollY;
114
115 CUIRect m_ClipRect;
116 CUIRect m_RailRect;
117 CUIRect m_LastAddedRect; // saved for ScrollHere()
118 float m_SliderGrabPos; // where did user grab the slider
119 vec2 m_ContentScrollOff;
120 CScrollRegionParams m_Params;
121
122public:
123 enum EScrollOption
124 {
125 SCROLLHERE_KEEP_IN_VIEW = 0,
126 SCROLLHERE_TOP,
127 SCROLLHERE_BOTTOM,
128 };
129
130 CScrollRegion();
131 void Begin(CUIRect *pClipRect, vec2 *pOutOffset, const CScrollRegionParams *pParams = nullptr);
132 void End();
133 bool AddRect(const CUIRect &Rect, bool ShouldScrollHere = false); // returns true if the added rect is visible (not clipped)
134 void ScrollHere(EScrollOption Option = SCROLLHERE_KEEP_IN_VIEW);
135 void ScrollRelative(EScrollRelative Direction, float SpeedMultiplier = 1.0f);
136 const CUIRect *ClipRect() const { return &m_ClipRect; }
137 void DoEdgeScrolling();
138 bool RectClipped(const CUIRect &Rect) const;
139 bool ScrollbarShown() const;
140 bool Animating() const;
141 bool Active() const;
142 const CScrollRegionParams &Params() const { return m_Params; }
143};
144
145#endif
146