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
15enum class EInputPriority
16{
17 NONE = 0,
18 UI,
19 CHAT,
20 CONSOLE,
21};
22
23// line input helper
24class CLineInput
25{
26public:
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
39private:
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
97public:
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
200template<size_t MaxSize, size_t MaxChars = MaxSize>
201class CLineInputBuffered : public CLineInput
202{
203 char m_aBuffer[MaxSize];
204
205public:
206 CLineInputBuffered() :
207 CLineInput()
208 {
209 m_aBuffer[0] = '\0';
210 SetBuffer(m_aBuffer, MaxSize, MaxChars);
211 }
212};
213
214class CLineInputNumber : public CLineInputBuffered<32>
215{
216public:
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