1#ifndef GAME_CLIENT_COMPONENTS_TOUCH_CONTROLS_H
2#define GAME_CLIENT_COMPONENTS_TOUCH_CONTROLS_H
3
4#include <base/color.h>
5#include <base/vmath.h>
6
7#include <engine/input.h>
8
9#include <game/client/component.h>
10#include <game/client/ui_rect.h>
11
12#include <array>
13#include <chrono>
14#include <functional>
15#include <memory>
16#include <optional>
17#include <string>
18#include <vector>
19
20class CJsonWriter;
21typedef struct _json_value json_value;
22
23class CTouchControls : public CComponent
24{
25public:
26 static constexpr const int BUTTON_SIZE_SCALE = 1000000;
27 static constexpr const int BUTTON_SIZE_MINIMUM = 50000;
28 static constexpr const int BUTTON_SIZE_MAXIMUM = 500000;
29 enum class EDirectTouchIngameMode
30 {
31 DISABLED,
32 ACTION,
33 AIM,
34 FIRE,
35 HOOK,
36 NUM_STATES
37 };
38 enum class EDirectTouchSpectateMode
39 {
40 DISABLED,
41 AIM,
42 NUM_STATES
43 };
44
45 int Sizeof() const override { return sizeof(*this); }
46 void OnInit() override;
47 void OnReset() override;
48 void OnWindowResize() override;
49 bool OnTouchState(const std::vector<IInput::CTouchFingerState> &vTouchFingerStates) override;
50 void OnRender() override;
51
52 bool LoadConfigurationFromFile(int StorageType);
53 bool LoadConfigurationFromClipboard();
54 bool SaveConfigurationToFile();
55 void SaveConfigurationToClipboard();
56
57 EDirectTouchIngameMode DirectTouchIngame() const { return m_DirectTouchIngame; }
58 void SetDirectTouchIngame(EDirectTouchIngameMode DirectTouchIngame)
59 {
60 m_DirectTouchIngame = DirectTouchIngame;
61 m_EditingChanges = true;
62 }
63 EDirectTouchSpectateMode DirectTouchSpectate() const { return m_DirectTouchSpectate; }
64 void SetDirectTouchSpectate(EDirectTouchSpectateMode DirectTouchSpectate)
65 {
66 m_DirectTouchSpectate = DirectTouchSpectate;
67 m_EditingChanges = true;
68 }
69 bool IsEditingActive() const { return m_EditingActive; }
70 void SetEditingActive(bool EditingActive) { m_EditingActive = EditingActive; }
71 bool HasEditingChanges() const { return m_EditingChanges; }
72 void SetEditingChanges(bool EditingChanges) { m_EditingChanges = EditingChanges; }
73
74 class CUnitRect
75 {
76 public:
77 int m_X;
78 int m_Y;
79 int m_W;
80 int m_H;
81 float Distance(const CUnitRect &Other) const;
82 bool IsOverlap(const CUnitRect &Other) const
83 {
84 return (m_X < Other.m_X + Other.m_W) && (m_X + m_W > Other.m_X) && (m_Y < Other.m_Y + Other.m_H) && (m_Y + m_H > Other.m_Y);
85 }
86 bool operator==(const CUnitRect &Other) const
87 {
88 return m_X == Other.m_X && m_Y == Other.m_Y && m_W == Other.m_W && m_H == Other.m_H;
89 }
90 };
91
92 enum class EButtonVisibility
93 {
94 INGAME,
95 ZOOM_ALLOWED,
96 VOTE_ACTIVE,
97 DUMMY_ALLOWED,
98 DUMMY_CONNECTED,
99 RCON_AUTHED,
100 DEMO_PLAYER,
101 EXTRA_MENU_1,
102 EXTRA_MENU_2,
103 EXTRA_MENU_3,
104 EXTRA_MENU_4,
105 EXTRA_MENU_5,
106 NUM_VISIBILITIES
107 };
108 static const constexpr int MAX_EXTRA_MENU_NUMBER = (int)EButtonVisibility::EXTRA_MENU_5 - (int)EButtonVisibility::EXTRA_MENU_1 + 1;
109
110 enum class EButtonShape
111 {
112 RECT,
113 CIRCLE,
114 NUM_SHAPES
115 };
116
117 class CButtonLabel
118 {
119 public:
120 enum class EType
121 {
122 /**
123 * Label is used as is.
124 */
125 PLAIN,
126 /**
127 * Label is localized. Only usable for default button labels for which there must be
128 * corresponding `Localizable`-calls in code and string in the translation files.
129 */
130 LOCALIZED,
131 /**
132 * Icon font is used for the label.
133 */
134 ICON,
135 /**
136 * Number of label types.
137 */
138 NUM_TYPES
139 };
140
141 EType m_Type;
142 const char *m_pLabel;
143 };
144
145private:
146 static constexpr const char *const DIRECT_TOUCH_INGAME_MODE_NAMES[(int)EDirectTouchIngameMode::NUM_STATES] = {"disabled", "action", "aim", "fire", "hook"};
147 static constexpr const char *const DIRECT_TOUCH_SPECTATE_MODE_NAMES[(int)EDirectTouchSpectateMode::NUM_STATES] = {"disabled", "aim"};
148 static constexpr const char *const SHAPE_NAMES[(int)EButtonShape::NUM_SHAPES] = {"rect", "circle"};
149
150 class CButtonVisibility
151 {
152 public:
153 EButtonVisibility m_Type;
154 bool m_Parity;
155
156 CButtonVisibility(EButtonVisibility Type, bool Parity) :
157 m_Type(Type), m_Parity(Parity) {}
158 };
159
160 class CButtonVisibilityData
161 {
162 public:
163 const char *m_pId;
164 std::function<bool()> m_Function;
165 };
166
167 CButtonVisibilityData m_aVisibilityFunctions[(int)EButtonVisibility::NUM_VISIBILITIES];
168
169 enum
170 {
171 ACTION_AIM,
172 ACTION_FIRE,
173 ACTION_HOOK,
174 NUM_ACTIONS
175 };
176
177 static constexpr const char *const LABEL_TYPE_NAMES[(int)CButtonLabel::EType::NUM_TYPES] = {"plain", "localized", "icon"};
178
179public:
180 class CTouchButtonBehavior;
181
182 class CTouchButton
183 {
184 public:
185 CTouchButton(CTouchControls *pTouchControls);
186 CTouchButton(CTouchButton &&Other) noexcept;
187 CTouchButton(const CTouchButton &Other) = delete;
188
189 CTouchButton &operator=(const CTouchButton &Other) = delete;
190 CTouchButton &operator=(CTouchButton &&Other) noexcept;
191
192 CTouchControls *m_pTouchControls;
193
194 CUnitRect m_UnitRect; // {0,0,BUTTON_SIZE_MINIMUM,BUTTON_SIZE_MINIMUM} = default
195 CUIRect m_ScreenRect;
196
197 EButtonShape m_Shape; // Rect = default
198 int m_BackgroundCorners; // only used with EButtonShape::RECT
199
200 std::vector<CButtonVisibility> m_vVisibilities;
201 std::unique_ptr<CTouchButtonBehavior> m_pBehavior; // nullptr = default. In button editor the default is bind behavior with nothing.
202
203 bool m_VisibilityCached;
204 std::chrono::nanoseconds m_VisibilityStartTime;
205
206 void UpdatePointers();
207 void UpdateScreenFromUnitRect();
208 void UpdateBackgroundCorners();
209
210 vec2 ClampTouchPosition(vec2 TouchPosition) const;
211 bool IsInside(vec2 TouchPosition) const;
212 void UpdateVisibilityGame();
213 void UpdateVisibilityEditor();
214 bool IsVisible() const;
215 // Force using Selected for button colors, Rect for rendering rects.
216 void Render(std::optional<bool> Selected = std::nullopt, std::optional<CUnitRect> Rect = std::nullopt) const;
217 void WriteToConfiguration(CJsonWriter *pWriter);
218 };
219
220 class CTouchButtonBehavior
221 {
222 public:
223 CTouchButton *m_pTouchButton;
224 CTouchControls *m_pTouchControls;
225
226 bool m_Active; // variables below must only be used when active
227 IInput::CTouchFinger m_Finger;
228 vec2 m_ActivePosition;
229 vec2 m_AccumulatedDelta;
230 std::chrono::nanoseconds m_ActivationStartTime;
231
232 virtual ~CTouchButtonBehavior() = default;
233 virtual void Init(CTouchButton *pTouchButton);
234
235 void Reset();
236 void SetActive(const IInput::CTouchFingerState &FingerState);
237 void SetInactive(bool ByFinger);
238 bool IsActive() const;
239 bool IsActive(const IInput::CTouchFinger &Finger) const;
240
241 virtual CButtonLabel GetLabel() const = 0;
242 virtual void OnActivate() {}
243 virtual void OnDeactivate(bool ByFinger) {}
244 virtual void OnUpdate() {}
245 virtual void WriteToConfiguration(CJsonWriter *pWriter) = 0;
246 virtual const char *GetBehaviorType() const = 0;
247 };
248
249 /**
250 * Abstract class for predefined behaviors.
251 *
252 * Subclasses must implemented the concrete behavior and provide the label.
253 */
254 class CPredefinedTouchButtonBehavior : public CTouchButtonBehavior
255 {
256 public:
257 static constexpr const char *const BEHAVIOR_TYPE = "predefined";
258
259 CPredefinedTouchButtonBehavior(const char *pId) :
260 m_pId(pId) {}
261
262 /**
263 * Implements the serialization for predefined behaviors. Subclasses
264 * may override this, but they should call the parent function first.
265 */
266 void WriteToConfiguration(CJsonWriter *pWriter) override;
267 const char *GetBehaviorType() const override { return BEHAVIOR_TYPE; }
268 const char *GetPredefinedType() { return m_pId; }
269
270 private:
271 const char *m_pId;
272 };
273
274 class CIngameMenuTouchButtonBehavior : public CPredefinedTouchButtonBehavior
275 {
276 public:
277 static constexpr const char *const BEHAVIOR_ID = "ingame-menu";
278
279 CIngameMenuTouchButtonBehavior() :
280 CPredefinedTouchButtonBehavior(BEHAVIOR_ID) {}
281
282 CButtonLabel GetLabel() const override;
283 void OnDeactivate(bool ByFinger) override;
284 };
285
286 class CExtraMenuTouchButtonBehavior : public CPredefinedTouchButtonBehavior
287 {
288 public:
289 static constexpr const char *const BEHAVIOR_ID = "extra-menu";
290
291 CExtraMenuTouchButtonBehavior(int Number);
292
293 CButtonLabel GetLabel() const override;
294 void OnDeactivate(bool ByFinger) override;
295 int GetNumber() const { return m_Number; }
296 void WriteToConfiguration(CJsonWriter *pWriter) override;
297
298 private:
299 int m_Number;
300 char m_aLabel[16];
301 };
302
303 class CEmoticonTouchButtonBehavior : public CPredefinedTouchButtonBehavior
304 {
305 public:
306 static constexpr const char *const BEHAVIOR_ID = "emoticon";
307
308 CEmoticonTouchButtonBehavior() :
309 CPredefinedTouchButtonBehavior(BEHAVIOR_ID) {}
310
311 CButtonLabel GetLabel() const override;
312 void OnDeactivate(bool ByFinger) override;
313 };
314
315 class CSpectateTouchButtonBehavior : public CPredefinedTouchButtonBehavior
316 {
317 public:
318 static constexpr const char *const BEHAVIOR_ID = "spectate";
319
320 CSpectateTouchButtonBehavior() :
321 CPredefinedTouchButtonBehavior(BEHAVIOR_ID) {}
322
323 CButtonLabel GetLabel() const override;
324 void OnDeactivate(bool ByFinger) override;
325 };
326
327 class CSwapActionTouchButtonBehavior : public CPredefinedTouchButtonBehavior
328 {
329 public:
330 static constexpr const char *const BEHAVIOR_ID = "swap-action";
331
332 CSwapActionTouchButtonBehavior() :
333 CPredefinedTouchButtonBehavior(BEHAVIOR_ID) {}
334
335 CButtonLabel GetLabel() const override;
336 void OnActivate() override;
337 void OnDeactivate(bool ByFinger) override;
338
339 private:
340 int m_ActiveAction = NUM_ACTIONS;
341 };
342
343 class CUseActionTouchButtonBehavior : public CPredefinedTouchButtonBehavior
344 {
345 public:
346 static constexpr const char *const BEHAVIOR_ID = "use-action";
347
348 CUseActionTouchButtonBehavior() :
349 CPredefinedTouchButtonBehavior(BEHAVIOR_ID) {}
350
351 CButtonLabel GetLabel() const override;
352 void OnActivate() override;
353 void OnDeactivate(bool ByFinger) override;
354
355 private:
356 int m_ActiveAction = NUM_ACTIONS;
357 };
358
359 class CJoystickTouchButtonBehavior : public CPredefinedTouchButtonBehavior
360 {
361 public:
362 CJoystickTouchButtonBehavior(const char *pId) :
363 CPredefinedTouchButtonBehavior(pId) {}
364
365 CButtonLabel GetLabel() const override;
366 void OnActivate() override;
367 void OnDeactivate(bool ByFinger) override;
368 void OnUpdate() override;
369 int ActiveAction() const { return m_ActiveAction; }
370 virtual int SelectedAction() const = 0;
371
372 private:
373 int m_ActiveAction = NUM_ACTIONS;
374 };
375
376 class CJoystickActionTouchButtonBehavior : public CJoystickTouchButtonBehavior
377 {
378 public:
379 static constexpr const char *const BEHAVIOR_ID = "joystick-action";
380
381 CJoystickActionTouchButtonBehavior() :
382 CJoystickTouchButtonBehavior(BEHAVIOR_ID) {}
383
384 int SelectedAction() const override;
385 };
386
387 class CJoystickAimTouchButtonBehavior : public CJoystickTouchButtonBehavior
388 {
389 public:
390 static constexpr const char *const BEHAVIOR_ID = "joystick-aim";
391
392 CJoystickAimTouchButtonBehavior() :
393 CJoystickTouchButtonBehavior(BEHAVIOR_ID) {}
394
395 int SelectedAction() const override;
396 };
397
398 class CJoystickFireTouchButtonBehavior : public CJoystickTouchButtonBehavior
399 {
400 public:
401 static constexpr const char *const BEHAVIOR_ID = "joystick-fire";
402
403 CJoystickFireTouchButtonBehavior() :
404 CJoystickTouchButtonBehavior(BEHAVIOR_ID) {}
405
406 int SelectedAction() const override;
407 };
408
409 class CJoystickHookTouchButtonBehavior : public CJoystickTouchButtonBehavior
410 {
411 public:
412 static constexpr const char *const BEHAVIOR_ID = "joystick-hook";
413
414 CJoystickHookTouchButtonBehavior() :
415 CJoystickTouchButtonBehavior(BEHAVIOR_ID) {}
416
417 int SelectedAction() const override;
418 };
419
420 /**
421 * Generic behavior implementation that executes a console command like a bind.
422 */
423 class CBindTouchButtonBehavior : public CTouchButtonBehavior
424 {
425 public:
426 static constexpr const char *const BEHAVIOR_TYPE = "bind";
427
428 CBindTouchButtonBehavior(const char *pLabel, CButtonLabel::EType LabelType, const char *pCommand) :
429 m_Label(pLabel),
430 m_LabelType(LabelType),
431 m_Command(pCommand) {}
432
433 CButtonLabel GetLabel() const override;
434 const char *GetCommand() const { return m_Command.c_str(); }
435 void OnActivate() override;
436 void OnDeactivate(bool ByFinger) override;
437 void OnUpdate() override;
438 void WriteToConfiguration(CJsonWriter *pWriter) override;
439 const char *GetBehaviorType() const override { return BEHAVIOR_TYPE; }
440
441 private:
442 std::string m_Label;
443 CButtonLabel::EType m_LabelType;
444 std::string m_Command;
445
446 bool m_Repeating = false;
447 std::chrono::nanoseconds m_LastUpdateTime;
448 std::chrono::nanoseconds m_AccumulatedRepeatingTime;
449 };
450
451 /**
452 * Generic behavior implementation that switches between executing one of two or more console commands.
453 */
454 class CBindToggleTouchButtonBehavior : public CTouchButtonBehavior
455 {
456 public:
457 static constexpr const char *const BEHAVIOR_TYPE = "bind-toggle";
458
459 class CCommand
460 {
461 public:
462 std::string m_Label;
463 CButtonLabel::EType m_LabelType;
464 std::string m_Command;
465
466 CCommand(const char *pLabel, CButtonLabel::EType LabelType, const char *pCommand) :
467 m_Label(pLabel),
468 m_LabelType(LabelType),
469 m_Command(pCommand) {}
470 CCommand() :
471 m_LabelType(CButtonLabel::EType::PLAIN) {}
472 };
473
474 CBindToggleTouchButtonBehavior(std::vector<CCommand> &&vCommands) :
475 m_vCommands(std::move(vCommands)) {}
476
477 CButtonLabel GetLabel() const override;
478 std::vector<CCommand> GetCommand() const { return m_vCommands; }
479 size_t GetActiveCommandIndex() const { return m_ActiveCommandIndex; }
480 void OnActivate() override;
481 void WriteToConfiguration(CJsonWriter *pWriter) override;
482 const char *GetBehaviorType() const override { return BEHAVIOR_TYPE; }
483
484 private:
485 std::vector<CCommand> m_vCommands;
486 size_t m_ActiveCommandIndex = 0;
487 };
488
489private:
490 /**
491 * Mode of direct touch input while ingame.
492 *
493 * Saved to the touch controls configuration.
494 */
495 EDirectTouchIngameMode m_DirectTouchIngame = EDirectTouchIngameMode::ACTION;
496
497 /**
498 * Mode of direct touch input while spectating.
499 *
500 * Saved to the touch controls configuration.
501 */
502 EDirectTouchSpectateMode m_DirectTouchSpectate = EDirectTouchSpectateMode::AIM;
503
504 /**
505 * Background color of inactive touch buttons.
506 *
507 * Saved to the touch controls configuration.
508 */
509 ColorRGBA m_BackgroundColorInactive = ColorRGBA(0.0f, 0.0f, 0.0f, 0.25f);
510
511 /**
512 * Background color of active touch buttons.
513 *
514 * Saved to the touch controls configuration.
515 */
516 ColorRGBA m_BackgroundColorActive = ColorRGBA(0.2f, 0.2f, 0.2f, 0.25f);
517
518 /**
519 * All touch buttons.
520 *
521 * Saved to the touch controls configuration.
522 */
523 std::vector<CTouchButton> m_vTouchButtons;
524
525 /**
526 * The activation states of the different extra menus which are toggle by the extra menu button behavior.
527 */
528 bool m_aExtraMenuActive[(int)EButtonVisibility::EXTRA_MENU_5 - (int)EButtonVisibility::EXTRA_MENU_1 + 1] = {false};
529
530 /**
531 * The currently selected action which is used for direct touch and is changed and used by some button behaviors.
532 */
533 int m_ActionSelected = ACTION_FIRE;
534
535 /**
536 * Counts how many joysticks are pressed.
537 */
538 int m_JoystickPressCount = 0;
539
540 /**
541 * The action that was last activated with direct touch input, which will determine the finger that will
542 * be used to update the mouse position from direct touch input.
543 */
544 int m_DirectTouchLastAction = ACTION_FIRE;
545
546 class CActionState
547 {
548 public:
549 bool m_Active = false;
550 IInput::CTouchFinger m_Finger;
551 };
552
553 /**
554 * The states of the different actions for direct touch input.
555 */
556 CActionState m_aDirectTouchActionStates[NUM_ACTIONS];
557
558 /**
559 * These fingers were activating buttons that became invisible and were therefore deactivated. The fingers
560 * are stored until they are released so they do not activate direct touch input or touch buttons anymore.
561 */
562 std::vector<IInput::CTouchFinger> m_vStaleFingers;
563
564 /**
565 * Whether editing mode is currently active.
566 */
567 bool m_EditingActive = false;
568
569 /**
570 * Whether there are changes to the current configuration in editing mode.
571 */
572 bool m_EditingChanges = false;
573
574 void InitVisibilityFunctions();
575 int NextActiveAction(int Action) const;
576 int NextDirectTouchAction() const;
577 void UpdateButtonsGame(const std::vector<IInput::CTouchFingerState> &vTouchFingerStates);
578 void ResetButtons();
579 void RenderButtonsGame();
580 vec2 CalculateScreenSize() const;
581
582 bool ParseConfiguration(const void *pFileData, unsigned FileLength);
583 std::optional<EDirectTouchIngameMode> ParseDirectTouchIngameMode(const json_value *pModeValue);
584 std::optional<EDirectTouchSpectateMode> ParseDirectTouchSpectateMode(const json_value *pModeValue);
585 std::optional<ColorRGBA> ParseColor(const json_value *pColorValue, const char *pAttributeName, std::optional<ColorRGBA> DefaultColor) const;
586 std::optional<CTouchButton> ParseButton(const json_value *pButtonObject);
587 std::unique_ptr<CTouchButtonBehavior> ParseBehavior(const json_value *pBehaviorObject);
588 std::unique_ptr<CPredefinedTouchButtonBehavior> ParsePredefinedBehavior(const json_value *pBehaviorObject);
589 std::unique_ptr<CExtraMenuTouchButtonBehavior> ParseExtraMenuBehavior(const json_value *pBehaviorObject);
590 std::unique_ptr<CBindTouchButtonBehavior> ParseBindBehavior(const json_value *pBehaviorObject);
591 std::unique_ptr<CBindToggleTouchButtonBehavior> ParseBindToggleBehavior(const json_value *pBehaviorObject);
592 void WriteConfiguration(CJsonWriter *pWriter);
593
594 std::vector<ivec2> m_vTargets;
595 std::vector<CUnitRect> m_vLastUpdateRects;
596 std::vector<CUnitRect> m_vXSortedRects;
597 std::vector<CUnitRect> m_vYSortedRects;
598 int m_LastWidth = -10;
599 int m_LastHeight = -10;
600 void BuildPositionXY(std::vector<CUnitRect> vVisibleButtonRects, CUnitRect MyRect);
601 std::optional<CUnitRect> FindPositionXY(std::vector<CUnitRect> &vVisibleButtonRects, CUnitRect MyRect);
602
603 // This is how editor render buttons.
604 void RenderButtonsEditor();
605 // This is how editor deal with touch inputs.
606 void UpdateButtonsEditor(const std::vector<IInput::CTouchFingerState> &vTouchFingerStates);
607 void UpdateSampleButton(const CTouchButton &SrcButton);
608
609 // For process fingerstates in button editor.
610 bool m_PreventSaving = false;
611 std::optional<IInput::CTouchFingerState> m_ActiveFingerState;
612 std::optional<IInput::CTouchFingerState> m_ZoomFingerState;
613 std::optional<IInput::CTouchFingerState> m_LongPressFingerState;
614 vec2 m_ZoomStartPos = vec2(0.0f, 0.0f);
615 vec2 m_AccumulatedDelta = vec2(0.0f, 0.0f);
616 std::vector<IInput::CTouchFingerState> m_vDeletedFingerState;
617 std::array<bool, (size_t)EButtonVisibility::NUM_VISIBILITIES> m_aVirtualVisibilities;
618
619 // Partially copied so it looks the same as m_pSelectedButton. Follows along the fingers while sliding.
620 std::unique_ptr<CTouchButton> m_pSampleButton = nullptr;
621 // For rendering. Calculated from m_pSampleButton's m_UnitRect, will not overlapping with any rect.
622 std::optional<CUnitRect> m_ShownRect;
623 CTouchButton *m_pSelectedButton = nullptr;
624
625 bool m_UnsavedChanges = false;
626 bool m_PreviewAllButtons = false;
627
628public:
629 CTouchButton *NewButton();
630 void DeleteSelectedButton();
631 bool IsRectOverlapping(CUnitRect MyRect, EButtonShape Shape) const;
632 std::optional<CUnitRect> UpdatePosition(CUnitRect MyRect, EButtonShape Shape, bool Ignore = false); // If Ignore == true, then the function will also try to avoid m_pSelectedButton.
633 void ResetButtonPointers();
634 void ResetVirtualVisibilities();
635 CUIRect CalculateScreenFromUnitRect(CUnitRect Unit, EButtonShape Shape = EButtonShape::RECT) const;
636 CUnitRect CalculateHitbox(const CUnitRect &Rect, EButtonShape Shape) const;
637
638 // Getters and setters.
639 bool HasUnsavedChanges() const { return m_UnsavedChanges; }
640 void SetUnsavedChanges(bool UnsavedChanges) { m_UnsavedChanges = UnsavedChanges; }
641 std::array<bool, (size_t)EButtonVisibility::NUM_VISIBILITIES> VirtualVisibilities() const { return m_aVirtualVisibilities; }
642 void ReverseVirtualVisibilities(int Number) { m_aVirtualVisibilities[Number] = !m_aVirtualVisibilities[Number]; }
643 std::optional<CUnitRect> ShownRect() const { return m_ShownRect; }
644 void SetShownRect(std::optional<CUnitRect> Rect) { m_ShownRect = Rect; }
645 CTouchButton *SelectedButton() const { return m_pSelectedButton; }
646 void SetSelectedButton(CTouchButton *TargetButton) { m_pSelectedButton = TargetButton; }
647 void RemakeSampleButton() { m_pSampleButton = std::make_unique<CTouchButton>(args: this); }
648 CTouchButton *SampleButton() const { return m_pSampleButton.get(); }
649 bool IsButtonEditing() const { return m_pSelectedButton != nullptr || m_pSampleButton != nullptr; }
650 ColorRGBA DefaultBackgroundColorInactive() const { return ColorRGBA(0.0f, 0.0f, 0.0f, 0.25f); }
651 ColorRGBA DefaultBackgroundColorActive() const { return ColorRGBA(0.2f, 0.2f, 0.2f, 0.25f); }
652 ColorRGBA BackgroundColorInactive() const { return m_BackgroundColorInactive; }
653 ColorRGBA BackgroundColorActive() const { return m_BackgroundColorActive; }
654 void SetBackgroundColorInactive(ColorRGBA Color) { m_BackgroundColorInactive = Color; }
655 void SetBackgroundColorActive(ColorRGBA Color) { m_BackgroundColorActive = Color; }
656 std::vector<CTouchButton *> GetButtonsEditor();
657 bool PreviewAllButtons() const { return m_PreviewAllButtons; }
658 void SetPreviewAllButtons(bool Preview) { m_PreviewAllButtons = Preview; }
659
660 // Set the EPopupType and call
661 enum class EPopupType
662 {
663 // Unsaved settings when changing selected button.
664 BUTTON_CHANGED,
665 // FindPositionXY can't find an empty space for the selected button(Currently it's overlapping).
666 NO_SPACE,
667 // Selected button is not visible.
668 BUTTON_INVISIBLE,
669 NUM_POPUPS
670 };
671
672 // These things must be set before opening the menu for calling the popup.
673 // After setting these, use GameClient()->m_Menus.SetActive(true), then the popup could be called automatically if EPopupType is not NUM_POPUPS.
674 class CPopupParam
675 {
676 public:
677 EPopupType m_PopupType = EPopupType::NUM_POPUPS;
678 CTouchButton *m_pOldSelectedButton = nullptr;
679 CTouchButton *m_pNewSelectedButton = nullptr;
680 bool m_KeepMenuOpen = false;
681 };
682
683 CPopupParam RequiredPopup();
684
685 // The issues won't be resolved until the Button Editor is rendered. If you want to solve issues right now don't use this.
686 // This is usually for update cached settings in button editor.
687 enum class EIssueType
688 {
689 CACHE_SETTINGS, // Update Cached settings from m_pTargetButton.
690 SAVE_SETTINGS, // Save Cached settings to m_pTargetButton.
691 CACHE_POSITION, // Update position from m_pTargetButton.
692 NUM_ISSUES
693 };
694
695 class CIssueParam
696 {
697 public:
698 bool m_Resolved = true;
699 CTouchButton *m_pTargetButton = nullptr;
700 };
701
702 bool AnyIssueNotResolved() const;
703 std::array<CTouchControls::CIssueParam, (unsigned)CTouchControls::EIssueType::NUM_ISSUES> Issues();
704
705private:
706 CPopupParam m_PopupParam;
707 std::array<CIssueParam, (int)EIssueType::NUM_ISSUES> m_aIssueParam;
708};
709
710#endif
711