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 testing::UITest;
   36    friend struct IRenderingContext::Init;
   37
   38public:
   39    using BeforeFrameQueue = AMessageQueue<AFakeMutex, IRenderer&>;
   40
   41    AWindowBase();
   42
   48    struct Profiling {
   53
   58
   64
   70    };
   71
   72
   87    virtual void blockUserInput(bool blockUserInput = true);
   88
   89    virtual ~AWindowBase();
   90
   91
  102
  106    [[nodiscard]]
  107    bool isPreventingClickOnPointerRelease() const noexcept {
  108        return mPreventClickOnPointerRelease.valueOr(false);
  109    }
  110
  114    template<aui::invocable<const _<AView>&> Callback>
  115    void iterateOverFocusChain(Callback&& callback) {
  116        for (auto view = mFocusedView.lock(); view;) {
  117            callback(view);
  118
  119            auto container = _cast<AViewContainer>(view);
  120            if (!container) return;
  121            view = container->focusChainTarget();
  122        }
  123    }
  124
  133    [[nodiscard]]
  134    virtual unsigned frameMillis() const noexcept = 0;
  135
  136    static AWindowManager& getWindowManager() {
  137        return *getWindowManagerImpl();
  138    }
  139    template<typename WindowManager, typename... Args>
  140    static void setWindowManager(Args&&... args) {
  141        destroyWindowManager(); // destroys previous window manager so IEventLoop::Handle sets window manager to the
  142                                // previous one BEFORE the new window manager is set
  143        getWindowManagerImpl() = std::make_unique<WindowManager>(std::forward<Args>(args)...);
  144    }
  145    static void destroyWindowManager() {
  146        getWindowManagerImpl() = nullptr;
  147    }
  148
  149    const _unique<IRenderingContext>& getRenderingContext() const {
  150        return mRenderingContext;
  151    }
  152
  153    [[nodiscard]]
  154    BeforeFrameQueue& beforeFrameQueue() noexcept {
  155        return mBeforeFrameQueue;
  156    }
  157
  158    void updateDpi();
  159
  165    float getDpiRatio()
  166    {
  167        return mDpiRatio;
  168    }
  169
  170    _<AView> getFocusedView() const
  171    {
  172        return mFocusedView.lock();
  173    }
  174
  175    void setFocusedView(const _<AView>& view);
  176    void updateFocusChain();
  177    void onPointerPressed(const APointerPressedEvent& event) override;
  178
  179    void onPointerMove(glm::vec2 pos, const APointerMoveEvent& event) override;
  180
  181    void closeOverlappingSurfacesOnClick();
  182
  183    bool isFocused() const {
  184        return mIsFocused;
  185    }
  186
  187    [[nodiscard]]
  188    const glm::ivec2& getMousePos() const {
  189        return mMousePos;
  190    }
  191
  192    void onKeyDown(AInput::Key key) override;
  193
  194
  195    virtual void focusNextView();
  196    virtual void flagRedraw();
  197
  198    void makeCurrent() {
  199        currentWindowStorage() = this;
  200    }
  201
  230                                                    const glm::ivec2& size,
  231                                                    bool closeOnClick = true) {
  232        return createOverlappingSurface([&](unsigned attempt) -> AOptional<glm::ivec2> {
  233            switch (attempt) {
  234                case 0: return position;
  235                case 1: return glm::clamp(position, {0, 0}, {getSize() - size});
  236                default: return std::nullopt;
  237            }
  238        }, size, closeOnClick);
  239    }
  240
  251    _<AOverlappingSurface> createOverlappingSurface(const std::function<AOptional<glm::ivec2>(unsigned)>& positionFactory,
  252                                                    const glm::ivec2& size,
  253                                                    bool closeOnClick = true) {
  254        glm::ivec2 position = {0, 0};
  255        auto maxPos = getSize() - size;
  256        for (unsigned index = 0; ; ++index) {
  257            auto optionalPosition = positionFactory(index);
  258            if (optionalPosition) {
  259                position = *optionalPosition;
  260
  261                if (position.x >= 0 && position.y >= 0 && glm::all(glm::lessThan(position, maxPos))) {
  262                    break;
  263                }
  264            } else {
  265                break;
  266            }
  267        }
  268
  269        auto tmp = createOverlappingSurfaceImpl(position, size);
  270        tmp->mParentWindow = this;
  271        tmp->mCloseOnClick = closeOnClick;
  272        mOverlappingSurfaces << tmp;
  273        return tmp;
  274    }
  275    void closeOverlappingSurface(AOverlappingSurface* surface) {
  276        if (mOverlappingSurfaces.erase(aui::ptr::fake(surface)) > 0) {
  277            closeOverlappingSurfaceImpl(surface);
  278        }
  279    }
  280
  281    void onFocusLost() override;
  282    void render(ARenderContext context) override;
  283    void applyGeometryToChildren() override;
  284    void onPointerReleased(const APointerReleasedEvent& event) override;
  285
  298    virtual bool onDragEnter(const ADragNDrop::EnterEvent& event);
  299    virtual void onDragLeave();
  300    virtual void onDragDrop(const ADragNDrop::DropEvent& event);
  301
  306
  311
  317
  318    void onScroll(const AScrollEvent& event) override;
  319
  323    virtual void forceUpdateCursor();
  324
  325    bool onGesture(const glm::ivec2& origin, const AGestureEvent& event) override;
  326
  330    static constexpr std::chrono::milliseconds DOUBLECLICK_MAX_DURATION = std::chrono::milliseconds(500);
  331
  336    size_t getFps() {
  337        return mLastCapturedFps;
  338    }
  339
  340    void setTouchscreenKeyboardPolicy(ATouchscreenKeyboardPolicy policy) noexcept {
  341        mKeyboardPolicy = policy;
  342    }
  343
  344    struct ScalingParams {
  348        float scalingFactor = 1.f;
  353        AOptional<glm::uvec2> minimalWindowSizeDp = std::nullopt;
  354    };
  355
  361
  366        return mProfiling;
  367    }
  368
  369    void markMinContentSizeInvalid() override;
  370
  371signals:
  372    emits<>            dpiChanged;
  373    emits<glm::ivec2>  mouseMove;
  374    emits<AInput::Key> keyDown;
  375    emits<>            redrawn;
  376    emits<>            layoutUpdateComplete;
  377
  382
  383
  388
  389#if AUI_PROFILING
  390    emits<APerformanceSection::Datas> performanceFrameComplete;
  391#endif
  392
  393protected:
  394    bool mIsFocused = true;
  395
  400
  404    bool mForceUpdateCursorGuard = false;
  405
  406    bool mPerformDoubleClickOnPointerRelease = false;
  407
  408    std::chrono::milliseconds mLastButtonPressedTime = std::chrono::milliseconds::zero();
  409    AOptional<APointerIndex> mLastButtonPressed;
  410    glm::vec2 mLastPosition = {0, 0};
  411
  412    _unique<IRenderingContext> mRenderingContext;
  413
  414    static AWindowBase*& currentWindowStorage();
  415
  419    virtual _<AOverlappingSurface> createOverlappingSurfaceImpl(const glm::ivec2& position, const glm::ivec2& size) = 0;
  420    virtual void closeOverlappingSurfaceImpl(AOverlappingSurface* surface) = 0;
  421
  422    virtual void createDevtoolsWindow();
  423
  424    static _unique<AWindowManager>& getWindowManagerImpl();
  425
  426    virtual float fetchDpiFromSystem() const;
  427
  428    virtual void showTouchscreenKeyboardImpl();
  429    virtual void hideTouchscreenKeyboardImpl();
  430
  431    void markPixelDataInvalid(ARect<int> invalidArea) override;
  432
  433private:
  434    void processTouchscreenKeyboardRequest();
  435
  436    _weak<AView> mFocusedView;
  437    aui::lazy<Profiling> mProfiling = [] { return Profiling{}; };
  438    float mDpiRatio = 1.f;
  439    ScalingParams mScalingParams;
  440
  441    BeforeFrameQueue mBeforeFrameQueue;
  442
  443    ATouchscreenKeyboardPolicy mKeyboardPolicy = ATouchscreenKeyboardPolicy::SHOWN_IF_NEEDED;
  444
  445    enum class KeyboardRequest {
  446        NO_OP,
  447        SHOW,
  448        HIDE
  449    };
  450
  451    KeyboardRequest mKeyboardRequestedState = KeyboardRequest::NO_OP;
  452
  453    glm::ivec2 mMousePos = {0, 0};
  454    ASet<_<AOverlappingSurface>> mOverlappingSurfaces;
  455
  456    struct Scroll {
  457        APointerIndex pointer;
  458        ATouchScroller scroller;
  459    };
  460
  464    ASmallVector<Scroll, 10 /* typical max number of fingers */> mScrolls;
  465
  466    std::chrono::time_point<std::chrono::high_resolution_clock> mLastTimeFpsCaptured = std::chrono::high_resolution_clock::now();
  467    size_t mFpsCounter = 0;
  468    size_t mLastCapturedFps = 0;
  469
  470#if AUI_SHOW_TOUCHES
  471    struct ShowTouches {
  472        glm::vec2 press;
  473        AVector<glm::vec2> moves;
  474        AOptional<glm::vec2> release;
  475    };
  476    AMap<APointerIndex, ShowTouches> mShowTouches;
  477#endif
  478};
  479
  480
  487#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."); }
  488
  495#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."); }
  496
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
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:165
bool mForceUpdateCursorGuard
If true, AWindowBase::forceUpdateCursor takes no action.
Definition AWindowBase.h:404
bool isPreventingClickOnPointerRelease() const noexcept
Definition AWindowBase.h:107
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:399
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:115
_< AOverlappingSurface > createOverlappingSurface(const glm::ivec2 &position, const glm::ivec2 &size, bool closeOnClick=true)
Definition AWindowBase.h:229
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:387
aui::lazy< Profiling > & profiling()
Get profiling settings (mutable).
Definition AWindowBase.h:365
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:336
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:251
emits touchscreenKeyboardShown
On touch screen keyboard show.
Definition AWindowBase.h:381
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:330
void setScalingParams(ScalingParams params)
Sets scaling params.
Definition AWindowManager.h:23
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:179
Definition UITestCase.h:26
ASignal< Args... > emits
A signal declaration.
Definition ASignal.h:572
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:48
AProperty< bool > highlightRedrawRequests
Highlight redraw requests.
Definition AWindowBase.h:57
AProperty< _weak< AView > > highlightView
View to highlight.
Definition AWindowBase.h:52
AProperty< bool > breakpointOnMarkMinContentSizeInvalid
When set to true, the next time window's markMinContentSizeInvalid, debugger is invoked....
Definition AWindowBase.h:69
AProperty< bool > renderToTextureDecay
Visually displays render-to-texture caching by decreasing brightness of pixels that didn't updated in...
Definition AWindowBase.h:63
Definition AWindowBase.h:344
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:353
float scalingFactor
DPI ratio will be multiplied by this factor.
Definition AWindowBase.h:348
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