AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AWindowBase.h
    1/*
    2 * AUI Framework - Declarative UI toolkit for modern C++20
    3 * Copyright (C) 2020-2025 Alex2772 and Contributors
    4 *
    5 * SPDX-License-Identifier: MPL-2.0
    6 *
    7 * This Source Code Form is subject to the terms of the Mozilla Public
    8 * License, v. 2.0. If a copy of the MPL was not distributed with this
    9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
   10 */
   11
   12//
   13// Created by alex2 on 6/9/2021.
   14//
   15
   16#pragma once
   17
   18#include <AUI/View/AViewContainer.h>
   19#include "AUI/Performance/APerformanceFrame.h"
   20#include "AUI/Performance/APerformanceSection.h"
   21#include "AWindowManager.h"
   22#include "AOverlappingSurface.h"
   23#include "ADragNDrop.h"
   24#include "AUI/Util/ATouchScroller.h"
   25#include "ATouchscreenKeyboardPolicy.h"
   26#include <chrono>
   27#include <optional>
   28
   29namespace testing {
   30    class UITest;
   31}
   32
   33class API_AUI_VIEWS AWindowBase: public AViewContainer {
   34    friend class SoftwareRenderer;
   35    friend class IPlatformAbstraction;
   36    friend class testing::UITest;
   37    friend struct IRenderingContext::Init;
   38
   39public:
   40    using BeforeFrameQueue = AMessageQueue<AFakeMutex, IRenderer&>;
   41
   42    AWindowBase();
   43
   49    struct Profiling {
   54
   59
   65
   71    };
   72
   73
   88    virtual void blockUserInput(bool blockUserInput = true);
   89
   90    virtual ~AWindowBase();
   91
   92
  103
  107    [[nodiscard]]
  108    bool isPreventingClickOnPointerRelease() const noexcept {
  109        return mPreventClickOnPointerRelease.valueOr(false);
  110    }
  111
  115    template<aui::invocable<const _<AView>&> Callback>
  116    void iterateOverFocusChain(Callback&& callback) {
  117        for (auto view = mFocusedView.lock(); view;) {
  118            callback(view);
  119
  120            auto container = _cast<AViewContainer>(view);
  121            if (!container) return;
  122            view = container->focusChainTarget();
  123        }
  124    }
  125
  134    [[nodiscard]]
  135    virtual unsigned frameMillis() const noexcept = 0;
  136
  137    static AWindowManager& getWindowManager() {
  138        return *getWindowManagerImpl();
  139    }
  140    template<typename WindowManager, typename... Args>
  141    static void setWindowManager(Args&&... args) {
  142        destroyWindowManager(); // destroys previous window manager so IEventLoop::Handle sets window manager to the
  143                                // previous one BEFORE the new window manager is set
  144        getWindowManagerImpl() = std::make_unique<WindowManager>(std::forward<Args>(args)...);
  145    }
  146    static void destroyWindowManager() {
  147        getWindowManagerImpl() = nullptr;
  148    }
  149
  150    const _unique<IRenderingContext>& getRenderingContext() const {
  151        return mRenderingContext;
  152    }
  153
  154    [[nodiscard]]
  155    BeforeFrameQueue& beforeFrameQueue() noexcept {
  156        return mBeforeFrameQueue;
  157    }
  158
  159    void updateDpi();
  160
  166    float getDpiRatio()
  167    {
  168        return mDpiRatio;
  169    }
  170
  171    _<AView> getFocusedView() const
  172    {
  173        return mFocusedView.lock();
  174    }
  175
  176    void setFocusedView(const _<AView>& view);
  177    void updateFocusChain();
  178    void onPointerPressed(const APointerPressedEvent& event) override;
  179
  180    void onPointerMove(glm::vec2 pos, const APointerMoveEvent& event) override;
  181
  182    void closeOverlappingSurfacesOnClick();
  183
  184    bool isFocused() const {
  185        return mIsFocused;
  186    }
  187
  188    [[nodiscard]]
  189    const glm::ivec2& getMousePos() const {
  190        return mMousePos;
  191    }
  192
  193    void onKeyDown(AInput::Key key) override;
  194
  195#pragma clang diagnostic push
  196#pragma ide diagnostic ignored "HidingNonVirtualFunction"
  197    virtual void redraw() {
  198        AView::redraw();
  199    }
  200#pragma clang diagnostic pop
  201
  202    virtual void focusNextView();
  203    virtual void flagRedraw();
  204
  205    void makeCurrent() {
  206        currentWindowStorage() = this;
  207    }
  208
  237                                                    const glm::ivec2& size,
  238                                                    bool closeOnClick = true) {
  239        return createOverlappingSurface([&](unsigned attempt) -> AOptional<glm::ivec2> {
  240            switch (attempt) {
  241                case 0: return position;
  242                case 1: return glm::clamp(position, {0, 0}, {getSize() - size});
  243                default: return std::nullopt;
  244            }
  245        }, size, closeOnClick);
  246    }
  247
  258    _<AOverlappingSurface> createOverlappingSurface(const std::function<AOptional<glm::ivec2>(unsigned)>& positionFactory,
  259                                                    const glm::ivec2& size,
  260                                                    bool closeOnClick = true) {
  261        glm::ivec2 position = {0, 0};
  262        auto maxPos = getSize() - size;
  263        for (unsigned index = 0; ; ++index) {
  264            auto optionalPosition = positionFactory(index);
  265            if (optionalPosition) {
  266                position = *optionalPosition;
  267
  268                if (position.x >= 0 && position.y >= 0 && glm::all(glm::lessThan(position, maxPos))) {
  269                    break;
  270                }
  271            } else {
  272                break;
  273            }
  274        }
  275
  276        auto tmp = createOverlappingSurfaceImpl(position, size);
  277        tmp->mParentWindow = this;
  278        tmp->mCloseOnClick = closeOnClick;
  279        mOverlappingSurfaces << tmp;
  280        return tmp;
  281    }
  282    void closeOverlappingSurface(AOverlappingSurface* surface) {
  283        if (mOverlappingSurfaces.erase(aui::ptr::fake(surface)) > 0) {
  284            closeOverlappingSurfaceImpl(surface);
  285        }
  286    }
  287
  288    void onFocusLost() override;
  289    void render(ARenderContext context) override;
  290    void applyGeometryToChildren() override;
  291    void onPointerReleased(const APointerReleasedEvent& event) override;
  292
  305    virtual bool onDragEnter(const ADragNDrop::EnterEvent& event);
  306    virtual void onDragLeave();
  307    virtual void onDragDrop(const ADragNDrop::DropEvent& event);
  308
  313
  318
  324
  325    void onScroll(const AScrollEvent& event) override;
  326
  330    virtual void forceUpdateCursor();
  331
  332    bool onGesture(const glm::ivec2& origin, const AGestureEvent& event) override;
  333
  337    static constexpr std::chrono::milliseconds DOUBLECLICK_MAX_DURATION = std::chrono::milliseconds(500);
  338
  343    size_t getFps() {
  344        return mLastCapturedFps;
  345    }
  346
  347    void setTouchscreenKeyboardPolicy(ATouchscreenKeyboardPolicy policy) noexcept {
  348        mKeyboardPolicy = policy;
  349    }
  350
  351    struct ScalingParams {
  355        float scalingFactor = 1.f;
  360        AOptional<glm::uvec2> minimalWindowSizeDp = std::nullopt;
  361    };
  362
  368
  373        return mProfiling;
  374    }
  375
  376    void markMinContentSizeInvalid() override;
  377
  378signals:
  379    emits<>            dpiChanged;
  380    emits<glm::ivec2>  mouseMove;
  381    emits<AInput::Key> keyDown;
  382    emits<>            redrawn;
  383    emits<>            layoutUpdateComplete;
  384
  389
  390
  395
  396#if AUI_PROFILING
  397    emits<APerformanceSection::Datas> performanceFrameComplete;
  398#endif
  399
  400protected:
  401    bool mIsFocused = true;
  402
  407
  411    bool mForceUpdateCursorGuard = false;
  412
  413    bool mPerformDoubleClickOnPointerRelease = false;
  414
  415    std::chrono::milliseconds mLastButtonPressedTime = std::chrono::milliseconds::zero();
  416    AOptional<APointerIndex> mLastButtonPressed;
  417    glm::vec2 mLastPosition = {0, 0};
  418
  419    _unique<IRenderingContext> mRenderingContext;
  420
  421    static AWindowBase*& currentWindowStorage();
  422
  426    virtual _<AOverlappingSurface> createOverlappingSurfaceImpl(const glm::ivec2& position, const glm::ivec2& size) = 0;
  427    virtual void closeOverlappingSurfaceImpl(AOverlappingSurface* surface) = 0;
  428
  429    virtual void createDevtoolsWindow();
  430
  431    static _unique<AWindowManager>& getWindowManagerImpl();
  432
  433    virtual float fetchDpiFromSystem() const;
  434
  435    virtual void showTouchscreenKeyboardImpl();
  436    virtual void hideTouchscreenKeyboardImpl();
  437
  438    void markPixelDataInvalid(ARect<int> invalidArea) override;
  439
  440private:
  441    void processTouchscreenKeyboardRequest();
  442
  443    _weak<AView> mFocusedView;
  444    aui::lazy<Profiling> mProfiling = [] { return Profiling{}; };
  445    float mDpiRatio = 1.f;
  446    ScalingParams mScalingParams;
  447
  448    BeforeFrameQueue mBeforeFrameQueue;
  449
  450    ATouchscreenKeyboardPolicy mKeyboardPolicy = ATouchscreenKeyboardPolicy::SHOWN_IF_NEEDED;
  451
  452    enum class KeyboardRequest {
  453        NO_OP,
  454        SHOW,
  455        HIDE
  456    };
  457
  458    KeyboardRequest mKeyboardRequestedState = KeyboardRequest::NO_OP;
  459
  460    glm::ivec2 mMousePos = {0, 0};
  461    ASet<_<AOverlappingSurface>> mOverlappingSurfaces;
  462
  463    struct Scroll {
  464        APointerIndex pointer;
  465        ATouchScroller scroller;
  466    };
  467
  471    ASmallVector<Scroll, 10 /* typical max number of fingers */> mScrolls;
  472
  473    std::chrono::time_point<std::chrono::high_resolution_clock> mLastTimeFpsCaptured = std::chrono::high_resolution_clock::now();
  474    size_t mFpsCounter = 0;
  475    size_t mLastCapturedFps = 0;
  476
  477#if AUI_SHOW_TOUCHES
  478    struct ShowTouches {
  479        glm::vec2 press;
  480        AVector<glm::vec2> moves;
  481        AOptional<glm::vec2> release;
  482    };
  483    AMap<APointerIndex, ShowTouches> mShowTouches;
  484#endif
  485};
  486
  487
  494#define AUI_ASSERT_UI_THREAD_ONLY() { AUI_ASSERTX(AWindow::current() == nullptr || AThread::current() == AWindow::current()->getThread(), "this method should be used in ui thread only."); }
  495
  502#define AUI_ASSERT_WORKER_THREAD_ONLY() { AUI_ASSERTX(AWindow::current() == nullptr || AThread::current() != AWindow::current()->getThread(), "this method should be used in worker thread only."); }
  503
Universal thread-safe message (callback) queue implementation.
Definition AMessageQueue.h:29
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition AOptional.h:33
Definition AOverlappingSurface.h:19
auto size() const
Size, including content area, border and padding.
Definition AView.h:114
void redraw()
Request window manager to redraw this AView.
glm::ivec2 getSize() const noexcept
Size, including content area, border and padding.
Definition AView.h:217
auto position() const
Top left corner's position relative to top left corner's position of the parent AView.
Definition AView.h:102
Definition AWindowBase.h:33
float getDpiRatio()
Returns current dpi ratio.
Definition AWindowBase.h:166
bool mForceUpdateCursorGuard
If true, AWindowBase::forceUpdateCursor takes no action.
Definition AWindowBase.h:411
bool isPreventingClickOnPointerRelease() const noexcept
Definition AWindowBase.h:108
virtual bool onDragEnter(const ADragNDrop::EnterEvent &event)
Called when the user holds a drag-n-drop object over the window.
AOptional< bool > mPreventClickOnPointerRelease
Definition AWindowBase.h:406
void markPixelDataInvalid(ARect< int > invalidArea) override
A view requests to redraw it and passes it's coords relative to this.
virtual _< AOverlappingSurface > createOverlappingSurfaceImpl(const glm::ivec2 &position, const glm::ivec2 &size)=0
bool onGesture(const glm::ivec2 &origin, const AGestureEvent &event) override
void iterateOverFocusChain(Callback &&callback)
Iterates over focus chain, from parent to child.
Definition AWindowBase.h:116
_< AOverlappingSurface > createOverlappingSurface(const glm::ivec2 &position, const glm::ivec2 &size, bool closeOnClick=true)
Definition AWindowBase.h:236
virtual void blockUserInput(bool blockUserInput=true)
Enables or disables user input for this window.
virtual unsigned frameMillis() const noexcept=0
Returns previous frame's rendering duration in millis.
void onPointerPressed(const APointerPressedEvent &event) override
Called on pointer (mouse) released event.
emits touchscreenKeyboardHidden
On touch screen keyboard hide.
Definition AWindowBase.h:394
aui::lazy< Profiling > & profiling()
Get profiling settings (mutable).
Definition AWindowBase.h:372
void preventClickOnPointerRelease()
Prevents click action on upcoming pointer release.
void onPointerReleased(const APointerReleasedEvent &event) override
Called on pointer (mouse) released event.
bool shouldDisplayHoverAnimations() const
Determines whether views should display hover animations.
size_t getFps()
Definition AWindowBase.h:343
void onPointerMove(glm::vec2 pos, const APointerMoveEvent &event) override
Handles pointer hover events.
void requestHideTouchscreenKeyboard()
On a mobile touchscreen device, requests hiding system virtual keyboard.
void onScroll(const AScrollEvent &event) override
void render(ARenderContext context) override
Draws this AView. Noone should call this function except rendering routine.
void requestShowTouchscreenKeyboard()
On a mobile touchscreen device, requests system virtual keyboard.
_< AOverlappingSurface > createOverlappingSurface(const std::function< AOptional< glm::ivec2 >(unsigned)> &positionFactory, const glm::ivec2 &size, bool closeOnClick=true)
Definition AWindowBase.h:258
emits touchscreenKeyboardShown
On touch screen keyboard show.
Definition AWindowBase.h:388
virtual void forceUpdateCursor()
Updates cursor by triggering onPointerMove on the same position (mMousePos).
static constexpr std::chrono::milliseconds DOUBLECLICK_MAX_DURATION
double click will be captured only if time elapsed since the previous click is less than DOUBLECLICK_...
Definition AWindowBase.h:337
void setScalingParams(ScalingParams params)
Sets scaling params.
Definition AWindowManager.h:21
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:179
Definition UITestCase.h:26
ASignal< Args... > emits
A signal declaration.
Definition ASignal.h:577
Definition ADragNDrop.h:67
Definition ADragNDrop.h:62
Pointing method move event.
Definition APointerMoveEvent.h:21
Pointing method press event.
Definition APointerPressedEvent.h:21
Pointing method press event.
Definition APointerReleasedEvent.h:19
Basic easy-to-use property implementation containing T.
Definition AProperty.h:30
Axis aligned 2D rectangle.
Definition ARect.h:24
Render context passed to AView::render.
Definition ARenderContext.h:43
Pointing method scroll event.
Definition AScrollEvent.h:20
Profiling (debugging) settings for this window.
Definition AWindowBase.h:49
AProperty< bool > highlightRedrawRequests
Highlight redraw requests.
Definition AWindowBase.h:58
AProperty< _weak< AView > > highlightView
View to highlight.
Definition AWindowBase.h:53
AProperty< bool > breakpointOnMarkMinContentSizeInvalid
When set to true, the next time window's markMinContentSizeInvalid, debugger is invoked....
Definition AWindowBase.h:70
AProperty< bool > renderToTextureDecay
Visually displays render-to-texture caching by decreasing brightness of pixels that didn't updated in...
Definition AWindowBase.h:64
Definition AWindowBase.h:351
AOptional< glm::uvec2 > minimalWindowSizeDp
If set, DPI ratio will be adjusted to be small enough for proper displaying layout of given size.
Definition AWindowBase.h:360
float scalingFactor
DPI ratio will be multiplied by this factor.
Definition AWindowBase.h:355
Definition IRenderingContext.h:38
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:52
A value that initializes when accessed for the first time.
Definition values.h:184
static _< T > fake(T *raw)
Creates fake shared pointer to T* raw with empty destructor, which does nothing. It's useful when som...
Definition SharedPtrTypes.h:429