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_H
4#define GAME_CLIENT_UI_H
5
6#include "lineinput.h"
7#include "ui_rect.h"
8
9#include <engine/input.h>
10#include <engine/textrender.h>
11
12#include <chrono>
13#include <set>
14#include <string>
15#include <vector>
16
17class CScrollRegion;
18class IClient;
19class IGraphics;
20class IKernel;
21
22enum class EEditState
23{
24 NONE,
25 START,
26 EDITING,
27 END,
28 ONE_GO
29};
30
31template<typename T>
32struct SEditResult
33{
34 EEditState m_State;
35 T m_Value;
36};
37
38struct SUIAnimator
39{
40 bool m_Active;
41 bool m_ScaleLabel;
42 bool m_RepositionLabel;
43
44 std::chrono::nanoseconds m_Time;
45 float m_Value;
46
47 float m_XOffset;
48 float m_YOffset;
49 float m_WOffset;
50 float m_HOffset;
51};
52
53class IScrollbarScale
54{
55public:
56 virtual float ToRelative(int AbsoluteValue, int Min, int Max) const = 0;
57 virtual int ToAbsolute(float RelativeValue, int Min, int Max) const = 0;
58};
59class CLinearScrollbarScale : public IScrollbarScale
60{
61public:
62 float ToRelative(int AbsoluteValue, int Min, int Max) const override
63 {
64 return (AbsoluteValue - Min) / (float)(Max - Min);
65 }
66 int ToAbsolute(float RelativeValue, int Min, int Max) const override
67 {
68 return round_to_int(f: RelativeValue * (Max - Min) + Min + 0.1f);
69 }
70};
71class CLogarithmicScrollbarScale : public IScrollbarScale
72{
73private:
74 int m_MinAdjustment;
75
76public:
77 CLogarithmicScrollbarScale(int MinAdjustment)
78 {
79 m_MinAdjustment = maximum(a: MinAdjustment, b: 1); // must be at least 1 to support Min == 0 with logarithm
80 }
81 float ToRelative(int AbsoluteValue, int Min, int Max) const override
82 {
83 if(Min < m_MinAdjustment)
84 {
85 AbsoluteValue += m_MinAdjustment;
86 Min += m_MinAdjustment;
87 Max += m_MinAdjustment;
88 }
89 return (std::log(x: AbsoluteValue) - std::log(x: Min)) / (float)(std::log(x: Max) - std::log(x: Min));
90 }
91 int ToAbsolute(float RelativeValue, int Min, int Max) const override
92 {
93 int ResultAdjustment = 0;
94 if(Min < m_MinAdjustment)
95 {
96 Min += m_MinAdjustment;
97 Max += m_MinAdjustment;
98 ResultAdjustment = -m_MinAdjustment;
99 }
100 return round_to_int(f: std::exp(x: RelativeValue * (std::log(x: Max) - std::log(x: Min)) + std::log(x: Min))) + ResultAdjustment;
101 }
102};
103
104class IButtonColorFunction
105{
106public:
107 virtual ColorRGBA GetColor(bool Active, bool Hovered) const = 0;
108};
109class CDarkButtonColorFunction : public IButtonColorFunction
110{
111public:
112 ColorRGBA GetColor(bool Active, bool Hovered) const override
113 {
114 if(Active)
115 return ColorRGBA(0.15f, 0.15f, 0.15f, 0.25f);
116 else if(Hovered)
117 return ColorRGBA(0.5f, 0.5f, 0.5f, 0.25f);
118 return ColorRGBA(0.0f, 0.0f, 0.0f, 0.25f);
119 }
120};
121class CLightButtonColorFunction : public IButtonColorFunction
122{
123public:
124 ColorRGBA GetColor(bool Active, bool Hovered) const override
125 {
126 if(Active)
127 return ColorRGBA(1.0f, 1.0f, 1.0f, 0.4f);
128 else if(Hovered)
129 return ColorRGBA(1.0f, 1.0f, 1.0f, 0.6f);
130 return ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
131 }
132};
133class CScrollBarColorFunction : public IButtonColorFunction
134{
135public:
136 ColorRGBA GetColor(bool Active, bool Hovered) const override
137 {
138 if(Active)
139 return ColorRGBA(0.9f, 0.9f, 0.9f, 1.0f);
140 else if(Hovered)
141 return ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
142 return ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f);
143 }
144};
145
146class CUi;
147
148class CUIElement
149{
150 friend class CUi;
151
152 CUi *m_pUI;
153
154 CUIElement(CUi *pUI, int RequestedRectCount) { Init(pUI, RequestedRectCount); }
155
156public:
157 struct SUIElementRect
158 {
159 CUIElement *m_pParent;
160
161 public:
162 int m_UIRectQuadContainer;
163 STextContainerIndex m_UITextContainer;
164
165 float m_X;
166 float m_Y;
167 float m_Width;
168 float m_Height;
169 float m_Rounding;
170 int m_Corners;
171
172 std::string m_Text;
173 int m_ReadCursorGlyphCount;
174
175 CTextCursor m_Cursor;
176
177 ColorRGBA m_TextColor;
178 ColorRGBA m_TextOutlineColor;
179
180 SUIElementRect();
181
182 ColorRGBA m_QuadColor;
183
184 void Reset();
185 void Draw(const CUIRect *pRect, ColorRGBA Color, int Corners, float Rounding);
186 };
187
188protected:
189 CUi *Ui() const { return m_pUI; }
190 std::vector<SUIElementRect> m_vUIRects;
191
192public:
193 CUIElement() = default;
194
195 void Init(CUi *pUI, int RequestedRectCount);
196
197 SUIElementRect *Rect(size_t Index)
198 {
199 return &m_vUIRects[Index];
200 }
201
202 bool AreRectsInit()
203 {
204 return !m_vUIRects.empty();
205 }
206
207 void InitRects(int RequestedRectCount);
208};
209
210struct SLabelProperties
211{
212 float m_MaxWidth = -1;
213 bool m_StopAtEnd = false;
214 bool m_EllipsisAtEnd = false;
215 bool m_EnableWidthCheck = true;
216 std::vector<STextColorSplit> m_vColorSplits = {};
217};
218
219struct SMenuButtonProperties
220{
221 int m_Checked = 0;
222 bool m_HintRequiresStringCheck = false;
223 bool m_HintCanChangePositionOrSize = false;
224 bool m_UseIconFont = false;
225 bool m_ShowDropDownIcon = false;
226 int m_Corners = IGraphics::CORNER_ALL;
227 float m_Rounding = 5.0f;
228 float m_FontFactor = 0.0f;
229 ColorRGBA m_Color = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
230};
231
232class CUIElementBase
233{
234private:
235 static CUi *s_pUI;
236
237public:
238 static void Init(CUi *pUI) { s_pUI = pUI; }
239
240 IClient *Client() const;
241 IGraphics *Graphics() const;
242 IInput *Input() const;
243 ITextRender *TextRender() const;
244 CUi *Ui() const { return s_pUI; }
245};
246
247class CButtonContainer
248{
249};
250
251struct SValueSelectorProperties
252{
253 bool m_UseScroll = true;
254 int64_t m_Step = 1;
255 float m_Scale = 1.0f;
256 bool m_IsHex = false;
257 int m_HexPrefix = 6;
258 ColorRGBA m_Color = ColorRGBA(0.0f, 0.0f, 0.0f, 0.4f);
259};
260
261struct SProgressSpinnerProperties
262{
263 float m_Progress = -1.0f; // between 0.0f and 1.0f, or negative for indeterminate progress
264 ColorRGBA m_Color = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);
265 int m_Segments = 64;
266};
267
268/**
269 * Type safe UI ID for popup menus.
270 */
271struct SPopupMenuId
272{
273};
274
275struct SPopupMenuProperties
276{
277 int m_Corners = IGraphics::CORNER_ALL;
278 ColorRGBA m_BorderColor = ColorRGBA(0.5f, 0.5f, 0.5f, 0.75f);
279 ColorRGBA m_BackgroundColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.75f);
280};
281
282class CUi
283{
284public:
285 /**
286 * These enum values are returned by popup menu functions to specify the behavior.
287 */
288 enum EPopupMenuFunctionResult
289 {
290 /**
291 * The current popup menu will be kept open.
292 */
293 POPUP_KEEP_OPEN = 0,
294
295 /**
296 * The current popup menu will be closed.
297 */
298 POPUP_CLOSE_CURRENT = 1,
299
300 /**
301 * The current popup menu and all popup menus above it will be closed.
302 */
303 POPUP_CLOSE_CURRENT_AND_DESCENDANTS = 2,
304 };
305
306 /**
307 * Callback that draws a popup menu.
308 *
309 * @param pContext The context object of the popup menu.
310 * @param View The UI rect where the popup menu's contents should be drawn.
311 * @param Active Whether this popup is active (the top-most popup).
312 * Only the active popup should handle key and mouse events.
313 *
314 * @return Value from the @link EPopupMenuFunctionResult @endlink enum.
315 */
316 typedef EPopupMenuFunctionResult (*FPopupMenuFunction)(void *pContext, CUIRect View, bool Active);
317
318 /**
319 * Callback that is called when one or more popups are closed.
320 */
321 typedef std::function<void()> FPopupMenuClosedCallback;
322
323private:
324 bool m_Enabled;
325
326 const void *m_pHotItem = nullptr;
327 const void *m_pActiveItem = nullptr;
328 const void *m_pLastActiveItem = nullptr; // only used internally to track active CLineInput
329 const void *m_pBecomingHotItem = nullptr;
330 const CScrollRegion *m_pHotScrollRegion = nullptr;
331 const CScrollRegion *m_pBecomingHotScrollRegion = nullptr;
332 bool m_ActiveItemValid = false;
333
334 int m_ActiveButtonLogicButton = -1;
335 int m_ActiveDraggableButtonLogicButton = -1;
336 class CDoubleClickState
337 {
338 public:
339 const void *m_pLastClickedId = nullptr;
340 float m_LastClickTime = -1.0f;
341 vec2 m_LastClickPos = vec2(-1.0f, -1.0f);
342 };
343 CDoubleClickState m_DoubleClickState;
344 const void *m_pLastEditingItem = nullptr;
345 float m_ActiveScrollbarOffset = 0.0f;
346 float m_ProgressSpinnerOffset = 0.0f;
347 class CValueSelectorState
348 {
349 public:
350 int m_Button = -1;
351 bool m_DidScroll = false;
352 float m_ScrollValue = 0.0f;
353 CLineInputNumber m_NumberInput;
354 const void *m_pLastTextId = nullptr;
355 };
356 CValueSelectorState m_ActiveValueSelectorState;
357
358 vec2 m_UpdatedMousePos = vec2(0.0f, 0.0f); // in window screen space
359 vec2 m_UpdatedMouseDelta = vec2(0.0f, 0.0f); // in window screen space
360 vec2 m_MousePos = vec2(0.0f, 0.0f); // in gui space
361 vec2 m_MouseDelta = vec2(0.0f, 0.0f); // in gui space
362 vec2 m_MouseWorldPos = vec2(-1.0f, -1.0f); // in world space
363 unsigned m_MouseButtons = 0;
364 unsigned m_LastMouseButtons = 0;
365 bool m_MouseSlow = false;
366 bool m_MouseLock = false;
367 const void *m_pMouseLockId = nullptr;
368
369 unsigned m_HotkeysPressed = 0;
370
371 CUIRect m_Screen;
372
373 std::vector<CUIRect> m_vClips;
374 void UpdateClipping();
375
376 struct SPopupMenu
377 {
378 static constexpr float POPUP_BORDER = 1.0f;
379 static constexpr float POPUP_MARGIN = 4.0f;
380
381 const SPopupMenuId *m_pId;
382 SPopupMenuProperties m_Props;
383 CUIRect m_Rect;
384 void *m_pContext;
385 FPopupMenuFunction m_pfnFunc;
386 };
387 std::vector<SPopupMenu> m_vPopupMenus;
388 FPopupMenuClosedCallback m_pfnPopupMenuClosedCallback = nullptr;
389
390 static CUi::EPopupMenuFunctionResult PopupMessage(void *pContext, CUIRect View, bool Active);
391 static CUi::EPopupMenuFunctionResult PopupConfirm(void *pContext, CUIRect View, bool Active);
392 static CUi::EPopupMenuFunctionResult PopupSelection(void *pContext, CUIRect View, bool Active);
393 static CUi::EPopupMenuFunctionResult PopupColorPicker(void *pContext, CUIRect View, bool Active);
394
395 IClient *m_pClient;
396 IGraphics *m_pGraphics;
397 IInput *m_pInput;
398 ITextRender *m_pTextRender;
399
400 std::vector<CUIElement *> m_vpOwnUIElements; // ui elements maintained by CUi class
401 std::vector<CUIElement *> m_vpUIElements;
402
403public:
404 static const CLinearScrollbarScale ms_LinearScrollbarScale;
405 static const CLogarithmicScrollbarScale ms_LogarithmicScrollbarScale;
406 static const CDarkButtonColorFunction ms_DarkButtonColorFunction;
407 static const CLightButtonColorFunction ms_LightButtonColorFunction;
408 static const CScrollBarColorFunction ms_ScrollBarColorFunction;
409
410 static const float ms_FontmodHeight;
411
412 void Init(IKernel *pKernel);
413 IClient *Client() const { return m_pClient; }
414 IGraphics *Graphics() const { return m_pGraphics; }
415 IInput *Input() const { return m_pInput; }
416 ITextRender *TextRender() const { return m_pTextRender; }
417
418 CUi();
419 ~CUi();
420
421 enum EHotkey : unsigned
422 {
423 HOTKEY_ENTER = 1 << 0,
424 HOTKEY_ESCAPE = 1 << 1,
425 HOTKEY_UP = 1 << 2,
426 HOTKEY_DOWN = 1 << 3,
427 HOTKEY_DELETE = 1 << 4,
428 HOTKEY_TAB = 1 << 5,
429 HOTKEY_SCROLL_UP = 1 << 6,
430 HOTKEY_SCROLL_DOWN = 1 << 7,
431 HOTKEY_PAGE_UP = 1 << 8,
432 HOTKEY_PAGE_DOWN = 1 << 9,
433 HOTKEY_HOME = 1 << 10,
434 HOTKEY_END = 1 << 11,
435 };
436
437 void ResetUIElement(CUIElement &UIElement) const;
438
439 CUIElement *GetNewUIElement(int RequestedRectCount);
440
441 void AddUIElement(CUIElement *pElement);
442 void OnElementsReset();
443 void OnWindowResize();
444 void OnCursorMove(float X, float Y);
445
446 void SetEnabled(bool Enabled) { m_Enabled = Enabled; }
447 bool Enabled() const { return m_Enabled; }
448 void Update(vec2 MouseWorldPos = vec2(-1.0f, -1.0f));
449 void DebugRender();
450
451 vec2 MousePos() const { return m_MousePos; }
452 float MouseX() const { return m_MousePos.x; }
453 float MouseY() const { return m_MousePos.y; }
454 vec2 MouseDelta() const { return m_MouseDelta; }
455 float MouseDeltaX() const { return m_MouseDelta.x; }
456 float MouseDeltaY() const { return m_MouseDelta.y; }
457 vec2 MouseWorldPos() const { return m_MouseWorldPos; }
458 float MouseWorldX() const { return m_MouseWorldPos.x; }
459 float MouseWorldY() const { return m_MouseWorldPos.y; }
460 vec2 UpdatedMousePos() const { return m_UpdatedMousePos; }
461 vec2 UpdatedMouseDelta() const { return m_UpdatedMouseDelta; }
462 int MouseButton(int Index) const { return (m_MouseButtons >> Index) & 1; }
463 int MouseButtonClicked(int Index) const { return MouseButton(Index) && !((m_LastMouseButtons >> Index) & 1); }
464 bool CheckMouseLock()
465 {
466 if(m_MouseLock && ActiveItem() != m_pMouseLockId)
467 DisableMouseLock();
468 return m_MouseLock;
469 }
470 void EnableMouseLock(const void *pId)
471 {
472 m_MouseLock = true;
473 m_pMouseLockId = pId;
474 }
475 void DisableMouseLock() { m_MouseLock = false; }
476
477 void SetHotItem(const void *pId) { m_pBecomingHotItem = pId; }
478 void SetActiveItem(const void *pId)
479 {
480 m_ActiveItemValid = true;
481 m_pActiveItem = pId;
482 if(pId)
483 m_pLastActiveItem = pId;
484 }
485 bool CheckActiveItem(const void *pId)
486 {
487 if(m_pActiveItem == pId)
488 {
489 m_ActiveItemValid = true;
490 return true;
491 }
492 return false;
493 }
494 void SetHotScrollRegion(const CScrollRegion *pId) { m_pBecomingHotScrollRegion = pId; }
495 const void *HotItem() const { return m_pHotItem; }
496 const void *NextHotItem() const { return m_pBecomingHotItem; }
497 const void *ActiveItem() const { return m_pActiveItem; }
498 const CScrollRegion *HotScrollRegion() const { return m_pHotScrollRegion; }
499
500 void StartCheck() { m_ActiveItemValid = false; }
501 void FinishCheck()
502 {
503 if(!m_ActiveItemValid && m_pActiveItem != nullptr)
504 {
505 SetActiveItem(nullptr);
506 m_pHotItem = nullptr;
507 m_pBecomingHotItem = nullptr;
508 }
509 }
510
511 bool MouseInside(const CUIRect *pRect) const;
512 bool MouseInsideClip() const { return !IsClipped() || MouseInside(pRect: ClipArea()); }
513 bool MouseHovered(const CUIRect *pRect) const { return MouseInside(pRect) && MouseInsideClip(); }
514 void ConvertMouseMove(float *pX, float *pY, IInput::ECursorType CursorType) const;
515 void ResetMouseSlow() { m_MouseSlow = false; }
516
517 bool ConsumeHotkey(EHotkey Hotkey);
518 void ClearHotkeys() { m_HotkeysPressed = 0; }
519 bool OnInput(const IInput::CEvent &Event);
520
521 constexpr float ButtonColorMulActive() const { return 0.5f; }
522 constexpr float ButtonColorMulHot() const { return 1.5f; }
523 constexpr float ButtonColorMulDefault() const { return 1.0f; }
524 float ButtonColorMul(const void *pId);
525
526 const CUIRect *Screen();
527 void MapScreen();
528 float PixelSize();
529
530 void ClipEnable(const CUIRect *pRect);
531 void ClipDisable();
532 const CUIRect *ClipArea() const;
533 inline bool IsClipped() const { return !m_vClips.empty(); }
534
535 int DoButtonLogic(const void *pId, int Checked, const CUIRect *pRect);
536 int DoDraggableButtonLogic(const void *pId, int Checked, const CUIRect *pRect, bool *pClicked, bool *pAbrupted);
537 bool DoDoubleClickLogic(const void *pId);
538 EEditState DoPickerLogic(const void *pId, const CUIRect *pRect, float *pX, float *pY);
539 void DoSmoothScrollLogic(float *pScrollOffset, float *pScrollOffsetChange, float ViewPortSize, float TotalSize, bool SmoothClamp = false, float ScrollSpeed = 10.0f) const;
540 static vec2 CalcAlignedCursorPos(const CUIRect *pRect, vec2 TextSize, int Align, const float *pBiggestCharHeight = nullptr);
541
542 void DoLabel(const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps = {}) const;
543
544 void DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps = {}, int StrLen = -1, const CTextCursor *pReadCursor = nullptr) const;
545 void DoLabelStreamed(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps = {}, int StrLen = -1, const CTextCursor *pReadCursor = nullptr) const;
546
547 /**
548 * Creates an input field.
549 *
550 * @see DoClearableEditBox
551 *
552 * @param pLineInput This pointer will be stored and written to on next user input.
553 * So you can not pass in a pointer that goes out of scope such as a local variable.
554 * Pass in either a member variable of the current class or a static variable.
555 * For example ```static CLineInputBuffered<IO_MAX_PATH_LENGTH> s_MyInput;```
556 * @param pRect the UI rect it will attach to with a 2.0f margin
557 * @param FontSize Size of the font (`10.0f`, `12.0f` and `14.0f` are commonly used here)
558 * @param Corners Number of corners (default: `IGraphics::CORNER_ALL`)
559 * @param vColorSplits Sets color splits of the `CTextCursor` to allow multicolored text
560 *
561 * @return true if the value of the input field changed since the last call.
562 */
563 bool DoEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const std::vector<STextColorSplit> &vColorSplits = {});
564
565 /**
566 * Creates an input field with a clear [x] button attached to it.
567 *
568 * @see DoEditBox
569 *
570 * @param pLineInput This pointer will be stored and written to on next user input.
571 * So you can not pass in a pointer that goes out of scope such as a local variable.
572 * Pass in either a member variable of the current class or a static variable.
573 * For example ```static CLineInputBuffered<IO_MAX_PATH_LENGTH> s_MyInput;```
574 * @param pRect the UI rect it will attach to
575 * @param FontSize Size of the font (`10.0f`, `12.0f` and `14.0f` are commonly used here)
576 * @param Corners Number of corners (default: `IGraphics::CORNER_ALL`)
577 * @param vColorSplits Sets color splits of the `CTextCursor` to allow multicolored text
578 *
579 * @return true if the value of the input field changed since the last call.
580 */
581 bool DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const std::vector<STextColorSplit> &vColorSplits = {});
582
583 int DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pId, const std::function<const char *()> &GetTextLambda, const CUIRect *pRect, const SMenuButtonProperties &Props = {});
584 // only used for popup menus
585 int DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding = 0.0f, bool TransparentInactive = false, bool Enabled = true);
586
587 // value selector
588 SEditResult<int64_t> DoValueSelectorWithState(const void *pId, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props = {});
589 int64_t DoValueSelector(const void *pId, const CUIRect *pRect, const char *pLabel, int64_t Current, int64_t Min, int64_t Max, const SValueSelectorProperties &Props = {});
590
591 // scrollbars
592 enum
593 {
594 SCROLLBAR_OPTION_INFINITE = 1 << 0,
595 SCROLLBAR_OPTION_NOCLAMPVALUE = 1 << 1,
596 SCROLLBAR_OPTION_MULTILINE = 1 << 2,
597 };
598 float DoScrollbarV(const void *pId, const CUIRect *pRect, float Current);
599 float DoScrollbarH(const void *pId, const CUIRect *pRect, float Current, const ColorRGBA *pColorInner = nullptr);
600 bool DoScrollbarOption(const void *pId, int *pOption, const CUIRect *pRect, const char *pStr, int Min, int Max, const IScrollbarScale *pScale = &ms_LinearScrollbarScale, unsigned Flags = 0u, const char *pSuffix = "");
601
602 // progress bar
603 void RenderProgressBar(CUIRect ProgressBar, float Progress);
604
605 // progress spinner
606 void RenderProgressSpinner(vec2 Center, float OuterRadius, const SProgressSpinnerProperties &Props = {}) const;
607
608 // popup menu
609 void DoPopupMenu(const SPopupMenuId *pId, int X, int Y, int Width, int Height, void *pContext, FPopupMenuFunction pfnFunc, const SPopupMenuProperties &Props = {});
610 void RenderPopupMenus();
611 void ClosePopupMenu(const SPopupMenuId *pId, bool IncludeDescendants = false);
612 void ClosePopupMenus();
613 bool IsPopupOpen() const;
614 bool IsPopupOpen(const SPopupMenuId *pId) const;
615 bool IsPopupHovered() const;
616 void SetPopupMenuClosedCallback(FPopupMenuClosedCallback pfnCallback);
617
618 struct SMessagePopupContext : public SPopupMenuId
619 {
620 static constexpr float POPUP_MAX_WIDTH = 200.0f;
621 static constexpr float POPUP_FONT_SIZE = 10.0f;
622
623 CUi *m_pUI; // set by CUi when popup is shown
624 char m_aMessage[1024];
625 ColorRGBA m_TextColor;
626
627 void DefaultColor(class ITextRender *pTextRender);
628 void ErrorColor();
629 };
630 void ShowPopupMessage(float X, float Y, SMessagePopupContext *pContext);
631
632 struct SConfirmPopupContext : public SPopupMenuId
633 {
634 enum EConfirmationResult
635 {
636 UNSET = 0,
637 CONFIRMED,
638 CANCELED,
639 };
640 static constexpr float POPUP_MAX_WIDTH = 200.0f;
641 static constexpr float POPUP_FONT_SIZE = 10.0f;
642 static constexpr float POPUP_BUTTON_HEIGHT = 12.0f;
643 static constexpr float POPUP_BUTTON_SPACING = 5.0f;
644
645 CUi *m_pUI; // set by CUi when popup is shown
646 char m_aPositiveButtonLabel[128];
647 char m_aNegativeButtonLabel[128];
648 char m_aMessage[1024];
649 EConfirmationResult m_Result;
650
651 CButtonContainer m_CancelButton;
652 CButtonContainer m_ConfirmButton;
653
654 SConfirmPopupContext();
655 void Reset();
656 void YesNoButtons();
657 };
658 void ShowPopupConfirm(float X, float Y, SConfirmPopupContext *pContext);
659
660 struct SSelectionPopupContext : public SPopupMenuId
661 {
662 CUi *m_pUI; // set by CUi when popup is shown
663 CScrollRegion *m_pScrollRegion;
664 SPopupMenuProperties m_Props;
665 char m_aMessage[256];
666 std::vector<std::string> m_vEntries;
667 std::vector<CButtonContainer> m_vButtonContainers;
668 const std::string *m_pSelection;
669 int m_SelectionIndex;
670 float m_EntryHeight;
671 float m_EntryPadding;
672 float m_EntrySpacing;
673 float m_FontSize;
674 float m_Width;
675 float m_AlignmentHeight;
676 bool m_TransparentButtons;
677
678 SSelectionPopupContext();
679 void Reset();
680 };
681 void ShowPopupSelection(float X, float Y, SSelectionPopupContext *pContext);
682
683 struct SColorPickerPopupContext : public SPopupMenuId
684 {
685 enum EColorPickerMode
686 {
687 MODE_UNSET = -1,
688 MODE_HSVA,
689 MODE_RGBA,
690 MODE_HSLA,
691 };
692
693 CUi *m_pUI; // set by CUi when popup is shown
694 EColorPickerMode m_ColorMode = MODE_UNSET;
695 bool m_Alpha = false;
696 unsigned int *m_pHslaColor = nullptr; // may be nullptr
697 ColorHSVA m_HsvaColor;
698 ColorRGBA m_RgbaColor;
699 ColorHSLA m_HslaColor;
700 // UI element IDs
701 const char m_HuePickerId = 0;
702 const char m_ColorPickerId = 0;
703 const char m_aValueSelectorIds[5] = {0};
704 CButtonContainer m_aModeButtons[(int)MODE_HSLA + 1];
705 EEditState m_State;
706 };
707 void ShowPopupColorPicker(float X, float Y, SColorPickerPopupContext *pContext);
708
709 // dropdown menu
710 struct SDropDownState
711 {
712 SSelectionPopupContext m_SelectionPopupContext;
713 CUIElement m_UiElement;
714 CButtonContainer m_ButtonContainer;
715 bool m_Init = false;
716 };
717 int DoDropDown(CUIRect *pRect, int CurSelection, const char **pStrs, int Num, SDropDownState &State);
718};
719
720#endif
721