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_LINEINPUT_H |
4 | #define GAME_CLIENT_LINEINPUT_H |
5 | |
6 | #include <base/vmath.h> |
7 | |
8 | #include <engine/client.h> |
9 | #include <engine/graphics.h> |
10 | #include <engine/input.h> |
11 | #include <engine/textrender.h> |
12 | |
13 | #include <game/client/ui_rect.h> |
14 | |
15 | enum class EInputPriority |
16 | { |
17 | NONE = 0, |
18 | UI, |
19 | CHAT, |
20 | CONSOLE, |
21 | }; |
22 | |
23 | // line input helper |
24 | class CLineInput |
25 | { |
26 | public: |
27 | struct SMouseSelection |
28 | { |
29 | bool m_Selecting = false; |
30 | vec2 m_PressMouse = vec2(0.0f, 0.0f); |
31 | vec2 m_ReleaseMouse = vec2(0.0f, 0.0f); |
32 | vec2 m_Offset = vec2(0.0f, 0.0f); |
33 | }; |
34 | |
35 | typedef std::function<void(const char *pLine)> FClipboardLineCallback; |
36 | typedef std::function<const char *(char *pCurrentText, size_t NumChars)> FDisplayTextCallback; |
37 | typedef std::function<bool()> FCalculateOffsetCallback; |
38 | |
39 | private: |
40 | static IClient *ms_pClient; |
41 | static IGraphics *ms_pGraphics; |
42 | static IInput *ms_pInput; |
43 | static ITextRender *ms_pTextRender; |
44 | |
45 | static IClient *Client() { return ms_pClient; } |
46 | static IGraphics *Graphics() { return ms_pGraphics; } |
47 | static IInput *Input() { return ms_pInput; } |
48 | static ITextRender *TextRender() { return ms_pTextRender; } |
49 | |
50 | static CLineInput *ms_pActiveInput; |
51 | static EInputPriority ms_ActiveInputPriority; |
52 | |
53 | static vec2 ms_CompositionWindowPosition; |
54 | static float ms_CompositionLineHeight; |
55 | |
56 | static char ms_aStars[128]; |
57 | |
58 | char *m_pStr = nullptr; // explicitly set to nullptr outside of constructor, so SetBuffer works in this case |
59 | size_t m_MaxSize; |
60 | size_t m_MaxChars; |
61 | size_t m_Len; |
62 | size_t m_NumChars; |
63 | |
64 | size_t m_CursorPos; |
65 | size_t m_SelectionStart; |
66 | size_t m_SelectionEnd; |
67 | |
68 | float m_ScrollOffset; |
69 | float m_ScrollOffsetChange; |
70 | vec2 m_CaretPosition; |
71 | SMouseSelection m_MouseSelection; |
72 | size_t m_LastCompositionCursorPos; |
73 | |
74 | bool m_Hidden; |
75 | const char *m_pEmptyText; |
76 | FClipboardLineCallback m_pfnClipboardLineCallback; |
77 | FDisplayTextCallback m_pfnDisplayTextCallback; |
78 | FCalculateOffsetCallback m_pfnCalculateOffsetCallback; |
79 | bool m_WasChanged; |
80 | bool m_WasCursorChanged; |
81 | bool m_WasRendered; |
82 | |
83 | char m_ClearButtonId; |
84 | |
85 | void UpdateStrData(); |
86 | enum EMoveDirection |
87 | { |
88 | FORWARD, |
89 | REWIND |
90 | }; |
91 | static void MoveCursor(EMoveDirection Direction, bool MoveWord, const char *pStr, size_t MaxSize, size_t *pCursorPos); |
92 | static void SetCompositionWindowPosition(vec2 Anchor, float LineHeight); |
93 | |
94 | void OnActivate(); |
95 | void OnDeactivate(); |
96 | |
97 | public: |
98 | static void Init(IClient *pClient, IGraphics *pGraphics, IInput *pInput, ITextRender *pTextRender) |
99 | { |
100 | ms_pClient = pClient; |
101 | ms_pGraphics = pGraphics; |
102 | ms_pInput = pInput; |
103 | ms_pTextRender = pTextRender; |
104 | } |
105 | static void RenderCandidates(); |
106 | |
107 | static CLineInput *GetActiveInput() { return ms_pActiveInput; } |
108 | |
109 | CLineInput() |
110 | { |
111 | SetBuffer(pStr: nullptr, MaxSize: 0, MaxChars: 0); |
112 | } |
113 | |
114 | CLineInput(char *pStr, size_t MaxSize) |
115 | { |
116 | SetBuffer(pStr, MaxSize); |
117 | } |
118 | |
119 | CLineInput(char *pStr, size_t MaxSize, size_t MaxChars) |
120 | { |
121 | SetBuffer(pStr, MaxSize, MaxChars); |
122 | } |
123 | |
124 | void SetBuffer(char *pStr, size_t MaxSize) { SetBuffer(pStr, MaxSize, MaxChars: MaxSize); } |
125 | void SetBuffer(char *pStr, size_t MaxSize, size_t MaxChars); |
126 | |
127 | void Clear(); |
128 | void Set(const char *pString); |
129 | void SetRange(const char *pString, size_t Begin, size_t End); |
130 | void Insert(const char *pString, size_t Begin); |
131 | void Append(const char *pString); |
132 | |
133 | const char *GetString() const { return m_pStr; } |
134 | const char *GetDisplayedString(); |
135 | size_t GetMaxSize() const { return m_MaxSize; } |
136 | size_t GetMaxChars() const { return m_MaxChars; } |
137 | size_t GetLength() const { return m_Len; } |
138 | size_t GetNumChars() const { return m_NumChars; } |
139 | bool IsEmpty() const { return GetLength() == 0; } |
140 | |
141 | size_t GetCursorOffset() const { return m_CursorPos; } |
142 | void SetCursorOffset(size_t Offset); |
143 | size_t GetSelectionStart() const { return m_SelectionStart; } |
144 | size_t GetSelectionEnd() const { return m_SelectionEnd; } |
145 | size_t GetSelectionLength() const { return m_SelectionEnd - m_SelectionStart; } |
146 | bool HasSelection() const { return GetSelectionLength() > 0; } |
147 | void SetSelection(size_t Start, size_t End); |
148 | void SelectNothing() { SetSelection(Start: GetCursorOffset(), End: GetCursorOffset()); } |
149 | void SelectAll() |
150 | { |
151 | SetCursorOffset(GetLength()); |
152 | SetSelection(Start: 0, End: GetLength()); |
153 | } |
154 | |
155 | size_t OffsetFromActualToDisplay(size_t ActualOffset); |
156 | size_t OffsetFromDisplayToActual(size_t DisplayOffset); |
157 | |
158 | // used either for vertical or horizontal scrolling |
159 | float GetScrollOffset() const { return m_ScrollOffset; } |
160 | void SetScrollOffset(float ScrollOffset) { m_ScrollOffset = ScrollOffset; } |
161 | float GetScrollOffsetChange() const { return m_ScrollOffsetChange; } |
162 | void SetScrollOffsetChange(float ScrollOffsetChange) { m_ScrollOffsetChange = ScrollOffsetChange; } |
163 | |
164 | vec2 GetCaretPosition() const { return m_CaretPosition; } // only updated while the input is active |
165 | |
166 | bool IsHidden() const { return m_Hidden; } |
167 | void SetHidden(bool Hidden) { m_Hidden = Hidden; } |
168 | |
169 | const char *GetEmptyText() const { return m_pEmptyText; } |
170 | void SetEmptyText(const char *pText) { m_pEmptyText = pText; } |
171 | |
172 | void SetClipboardLineCallback(FClipboardLineCallback pfnClipboardLineCallback) { m_pfnClipboardLineCallback = pfnClipboardLineCallback; } |
173 | void SetDisplayTextCallback(FDisplayTextCallback pfnDisplayTextCallback) { m_pfnDisplayTextCallback = pfnDisplayTextCallback; } |
174 | void SetCalculateOffsetCallback(FCalculateOffsetCallback pfnCalculateOffsetCallback) { m_pfnCalculateOffsetCallback = pfnCalculateOffsetCallback; } |
175 | |
176 | bool ProcessInput(const IInput::CEvent &Event); |
177 | bool WasChanged() |
178 | { |
179 | const bool Changed = m_WasChanged; |
180 | m_WasChanged = false; |
181 | return Changed; |
182 | } |
183 | bool WasCursorChanged() |
184 | { |
185 | const bool Changed = m_WasCursorChanged; |
186 | m_WasCursorChanged = false; |
187 | return Changed; |
188 | } |
189 | |
190 | STextBoundingBox Render(const CUIRect *pRect, float FontSize, int Align, bool Changed, float LineWidth, float LineSpacing, const std::vector<STextColorSplit> &vColorSplits = {}); |
191 | SMouseSelection *GetMouseSelection() { return &m_MouseSelection; } |
192 | |
193 | const void *GetClearButtonId() const { return &m_ClearButtonId; } |
194 | |
195 | bool IsActive() const { return GetActiveInput() == this; } |
196 | void Activate(EInputPriority Priority); |
197 | void Deactivate() const; |
198 | }; |
199 | |
200 | template<size_t MaxSize, size_t MaxChars = MaxSize> |
201 | class CLineInputBuffered : public CLineInput |
202 | { |
203 | char m_aBuffer[MaxSize]; |
204 | |
205 | public: |
206 | CLineInputBuffered() : |
207 | CLineInput() |
208 | { |
209 | m_aBuffer[0] = '\0'; |
210 | SetBuffer(m_aBuffer, MaxSize, MaxChars); |
211 | } |
212 | }; |
213 | |
214 | class CLineInputNumber : public CLineInputBuffered<32> |
215 | { |
216 | public: |
217 | CLineInputNumber() : |
218 | CLineInputBuffered() |
219 | { |
220 | } |
221 | |
222 | CLineInputNumber(int Number) : |
223 | CLineInputBuffered() |
224 | { |
225 | SetInteger(Number); |
226 | } |
227 | |
228 | CLineInputNumber(float Number) : |
229 | CLineInputBuffered() |
230 | { |
231 | SetFloat(Number); |
232 | } |
233 | |
234 | void SetInteger(int Number, int Base = 10, int HexPrefix = 6); |
235 | int GetInteger(int Base = 10) const; |
236 | |
237 | void SetInteger64(int64_t Number, int Base = 10, int HexPrefix = 6); |
238 | int64_t GetInteger64(int Base = 10) const; |
239 | |
240 | void SetFloat(float Number); |
241 | float GetFloat() const; |
242 | }; |
243 | |
244 | #endif |
245 | |