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