From 5bbd0333efd33ae1ddbd0d56f16857c6bc903505 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Mon, 19 Feb 2024 00:36:51 -0800 Subject: [PATCH] refactor(wayland): start factoring wayland out of ShellWindow --- CMakeLists.txt | 1 + src/cpp/layershell.cpp | 113 ++++++++++++----------- src/cpp/layershell.hpp | 194 ++++++++++++---------------------------- src/cpp/shellwindow.cpp | 1 + src/cpp/shellwindow.hpp | 134 +++++++++++++++++++++++++++ 5 files changed, 257 insertions(+), 186 deletions(-) create mode 100644 src/cpp/shellwindow.cpp create mode 100644 src/cpp/shellwindow.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a999fb29..7ee0b797 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ qt_add_executable(quickshell src/cpp/watcher.cpp src/cpp/region.cpp src/cpp/persistentprops.cpp + src/cpp/shellwindow.cpp ) qt_add_qml_module(quickshell URI QuickShell) diff --git a/src/cpp/layershell.cpp b/src/cpp/layershell.cpp index 9a4a99ec..05039064 100644 --- a/src/cpp/layershell.cpp +++ b/src/cpp/layershell.cpp @@ -12,56 +12,67 @@ #include #include "proxywindow.hpp" +#include "shellwindow.hpp" -void ProxyShellWindow::setupWindow() { +WaylandShellWindow::WaylandShellWindow(QObject* parent): + ProxyShellWindow(parent), mWayland(new WaylandShellWindowExtensions(this)) {} + +void WaylandShellWindow::setupWindow() { this->shellWindow = LayerShellQt::Window::get(this->window); - this->ProxyWindowBase::setupWindow(); + this->ProxyShellWindow::setupWindow(); // clang-format off QObject::connect(this->shellWindow, &LayerShellQt::Window::anchorsChanged, this, &ProxyShellWindow::anchorsChanged); QObject::connect(this->shellWindow, &LayerShellQt::Window::marginsChanged, this, &ProxyShellWindow::marginsChanged); - QObject::connect(this->shellWindow, &LayerShellQt::Window::layerChanged, this, &ProxyShellWindow::layerChanged); - QObject::connect(this->shellWindow, &LayerShellQt::Window::keyboardInteractivityChanged, this, &ProxyShellWindow::keyboardFocusChanged); - QObject::connect(this->window, &QWindow::widthChanged, this, &ProxyShellWindow::updateExclusionZone); - QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyShellWindow::updateExclusionZone); - QObject::connect(this, &ProxyShellWindow::anchorsChanged, this, &ProxyShellWindow::updateExclusionZone); - QObject::connect(this, &ProxyShellWindow::marginsChanged, this, &ProxyShellWindow::updateExclusionZone); + QObject::connect( + this->shellWindow, &LayerShellQt::Window::layerChanged, + this->mWayland, &WaylandShellWindowExtensions::layerChanged + ); + QObject::connect( + this->shellWindow, &LayerShellQt::Window::keyboardInteractivityChanged, + this->mWayland, &WaylandShellWindowExtensions::keyboardFocusChanged + ); + + QObject::connect(this->window, &QWindow::widthChanged, this, &WaylandShellWindow::updateExclusionZone); + QObject::connect(this->window, &QWindow::heightChanged, this, &WaylandShellWindow::updateExclusionZone); + QObject::connect(this, &ProxyShellWindow::anchorsChanged, this, &WaylandShellWindow::updateExclusionZone); + QObject::connect(this, &ProxyShellWindow::marginsChanged, this, &WaylandShellWindow::updateExclusionZone); // clang-format on this->setAnchors(this->mAnchors); this->setMargins(this->mMargins); this->setExclusionMode(this->mExclusionMode); // also sets exclusion zone - this->setLayer(this->mLayer); + this->mWayland->setLayer(this->mLayer); this->shellWindow->setScope(this->mScope); - this->setKeyboardFocus(this->mKeyboardFocus); + this->mWayland->setKeyboardFocus(this->mKeyboardFocus); this->connected = true; } -QQuickWindow* ProxyShellWindow::disownWindow() { +QQuickWindow* WaylandShellWindow::disownWindow() { QObject::disconnect(this->shellWindow, nullptr, this, nullptr); return this->ProxyWindowBase::disownWindow(); } -void ProxyShellWindow::setWidth(qint32 width) { +void WaylandShellWindow::setWidth(qint32 width) { this->mWidth = width; // only update the actual size if not blocked by anchors auto anchors = this->anchors(); - if (!anchors.mLeft || !anchors.mRight) this->ProxyWindowBase::setWidth(width); + if (!anchors.mLeft || !anchors.mRight) this->ProxyShellWindow::setWidth(width); } -void ProxyShellWindow::setHeight(qint32 height) { +void WaylandShellWindow::setHeight(qint32 height) { this->mHeight = height; // only update the actual size if not blocked by anchors auto anchors = this->anchors(); - if (!anchors.mTop || !anchors.mBottom) this->ProxyWindowBase::setHeight(height); + if (!anchors.mTop || !anchors.mBottom) this->ProxyShellWindow::setHeight(height); } -void ProxyShellWindow::setAnchors(Anchors anchors) { +void WaylandShellWindow::setAnchors(Anchors anchors) { if (this->window == nullptr) { this->mAnchors = anchors; return; @@ -79,7 +90,7 @@ void ProxyShellWindow::setAnchors(Anchors anchors) { this->shellWindow->setAnchors(lsAnchors); } -Anchors ProxyShellWindow::anchors() const { +Anchors WaylandShellWindow::anchors() const { if (this->window == nullptr) return this->mAnchors; auto lsAnchors = this->shellWindow->anchors(); @@ -93,7 +104,7 @@ Anchors ProxyShellWindow::anchors() const { return anchors; } -void ProxyShellWindow::setExclusiveZone(qint32 zone) { +void WaylandShellWindow::setExclusiveZone(qint32 zone) { if (zone < 0) zone = 0; if (this->connected && zone == this->mExclusionZone) return; this->mExclusionZone = zone; @@ -104,14 +115,14 @@ void ProxyShellWindow::setExclusiveZone(qint32 zone) { } } -qint32 ProxyShellWindow::exclusiveZone() const { +qint32 WaylandShellWindow::exclusiveZone() const { if (this->window == nullptr) return this->mExclusionZone; else return this->shellWindow->exclusionZone(); } -ExclusionMode::Enum ProxyShellWindow::exclusionMode() const { return this->mExclusionMode; } +ExclusionMode::Enum WaylandShellWindow::exclusionMode() const { return this->mExclusionMode; } -void ProxyShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) { +void WaylandShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) { if (this->connected && exclusionMode == this->mExclusionMode) return; this->mExclusionMode = exclusionMode; @@ -128,7 +139,7 @@ void ProxyShellWindow::setExclusionMode(ExclusionMode::Enum exclusionMode) { } } -void ProxyShellWindow::setMargins(Margins margins) { +void WaylandShellWindow::setMargins(Margins margins) { if (this->window == nullptr) this->mMargins = margins; else { auto lsMargins = QMargins(margins.mLeft, margins.mTop, margins.mRight, margins.mBottom); @@ -136,7 +147,7 @@ void ProxyShellWindow::setMargins(Margins margins) { } } -Margins ProxyShellWindow::margins() const { +Margins WaylandShellWindow::margins() const { if (this->window == nullptr) return this->mMargins; auto lsMargins = this->shellWindow->margins(); @@ -149,9 +160,9 @@ Margins ProxyShellWindow::margins() const { return margins; } -void ProxyShellWindow::setLayer(Layer::Enum layer) { - if (this->window == nullptr) { - this->mLayer = layer; +void WaylandShellWindowExtensions::setLayer(Layer::Enum layer) { + if (this->window->window == nullptr) { + this->window->mLayer = layer; return; } @@ -166,14 +177,14 @@ void ProxyShellWindow::setLayer(Layer::Enum layer) { } // clang-format on - this->shellWindow->setLayer(lsLayer); + this->window->shellWindow->setLayer(lsLayer); } -Layer::Enum ProxyShellWindow::layer() const { - if (this->window == nullptr) return this->mLayer; +Layer::Enum WaylandShellWindowExtensions::layer() const { + if (this->window->window == nullptr) return this->window->mLayer; auto layer = Layer::Top; - auto lsLayer = this->shellWindow->layer(); + auto lsLayer = this->window->shellWindow->layer(); // clang-format off switch (lsLayer) { @@ -187,19 +198,19 @@ Layer::Enum ProxyShellWindow::layer() const { return layer; } -void ProxyShellWindow::setScope(const QString& scope) { - if (this->window == nullptr) this->mScope = scope; - else this->shellWindow->setScope(scope); +void WaylandShellWindowExtensions::setScope(const QString& scope) { + if (this->window->window == nullptr) this->window->mScope = scope; + else this->window->shellWindow->setScope(scope); } -QString ProxyShellWindow::scope() const { - if (this->window == nullptr) return this->mScope; - else return this->shellWindow->scope(); +QString WaylandShellWindowExtensions::scope() const { + if (this->window->window == nullptr) return this->window->mScope; + else return this->window->shellWindow->scope(); } -void ProxyShellWindow::setKeyboardFocus(KeyboardFocus::Enum focus) { - if (this->window == nullptr) { - this->mKeyboardFocus = focus; +void WaylandShellWindowExtensions::setKeyboardFocus(KeyboardFocus::Enum focus) { + if (this->window->window == nullptr) { + this->window->mKeyboardFocus = focus; return; } @@ -213,14 +224,14 @@ void ProxyShellWindow::setKeyboardFocus(KeyboardFocus::Enum focus) { } // clang-format on - this->shellWindow->setKeyboardInteractivity(lsFocus); + this->window->shellWindow->setKeyboardInteractivity(lsFocus); } -KeyboardFocus::Enum ProxyShellWindow::keyboardFocus() const { - if (this->window == nullptr) return this->mKeyboardFocus; +KeyboardFocus::Enum WaylandShellWindowExtensions::keyboardFocus() const { + if (this->window->window == nullptr) return this->window->mKeyboardFocus; auto focus = KeyboardFocus::None; - auto lsFocus = this->shellWindow->keyboardInteractivity(); + auto lsFocus = this->window->shellWindow->keyboardInteractivity(); // clang-format off switch (lsFocus) { @@ -233,9 +244,9 @@ KeyboardFocus::Enum ProxyShellWindow::keyboardFocus() const { return focus; } -void ProxyShellWindow::setScreenConfiguration(ScreenConfiguration::Enum configuration) { - if (this->window == nullptr) { - this->mScreenConfiguration = configuration; +void WaylandShellWindowExtensions::setScreenConfiguration(ScreenConfiguration::Enum configuration) { + if (this->window->window == nullptr) { + this->window->mScreenConfiguration = configuration; return; } @@ -248,14 +259,14 @@ void ProxyShellWindow::setScreenConfiguration(ScreenConfiguration::Enum configur } // clang-format on - this->shellWindow->setScreenConfiguration(lsConfiguration); + this->window->shellWindow->setScreenConfiguration(lsConfiguration); } -ScreenConfiguration::Enum ProxyShellWindow::screenConfiguration() const { - if (this->window == nullptr) return this->mScreenConfiguration; +ScreenConfiguration::Enum WaylandShellWindowExtensions::screenConfiguration() const { + if (this->window->window == nullptr) return this->window->mScreenConfiguration; auto configuration = ScreenConfiguration::Window; - auto lsConfiguration = this->shellWindow->screenConfiguration(); + auto lsConfiguration = this->window->shellWindow->screenConfiguration(); // clang-format off switch (lsConfiguration) { @@ -267,7 +278,7 @@ ScreenConfiguration::Enum ProxyShellWindow::screenConfiguration() const { return configuration; } -void ProxyShellWindow::updateExclusionZone() { +void WaylandShellWindow::updateExclusionZone() { if (this->window != nullptr && this->exclusionMode() == ExclusionMode::Auto) { auto anchors = this->anchors(); diff --git a/src/cpp/layershell.hpp b/src/cpp/layershell.hpp index 182dabf9..6f0c0d7b 100644 --- a/src/cpp/layershell.hpp +++ b/src/cpp/layershell.hpp @@ -3,62 +3,10 @@ #include #include #include -#include -#include -#include #include #include -#include -#include -#include "proxywindow.hpp" - -class Anchors { - Q_GADGET; - Q_PROPERTY(bool left MEMBER mLeft); - Q_PROPERTY(bool right MEMBER mRight); - Q_PROPERTY(bool top MEMBER mTop); - Q_PROPERTY(bool bottom MEMBER mBottom); - -public: - bool mLeft = false; - bool mRight = false; - bool mTop = false; - bool mBottom = false; -}; - -class Margins { - Q_GADGET; - Q_PROPERTY(qint32 left MEMBER mLeft); - Q_PROPERTY(qint32 right MEMBER mRight); - Q_PROPERTY(qint32 top MEMBER mTop); - Q_PROPERTY(qint32 bottom MEMBER mBottom); - -public: - qint32 mLeft = 0; - qint32 mRight = 0; - qint32 mTop = 0; - qint32 mBottom = 0; -}; - -namespace ExclusionMode { // NOLINT -Q_NAMESPACE; -QML_ELEMENT; - -enum Enum { - /// Respect the exclusion zone of other shell layers and optionally set one - Normal = 0, - /// Ignore exclusion zones of other shell layers. You cannot set an exclusion zone in this mode. - Ignore = 1, - /// Decide the exclusion zone based on the window dimensions and anchors. - /// - /// Will attempt to reseve exactly enough space for the window and its margins if - /// exactly 3 anchors are connected. - Auto = 2, -}; -Q_ENUM_NS(Enum); - -} // namespace ExclusionMode +#include "shellwindow.hpp" namespace Layer { // NOLINT Q_NAMESPACE; @@ -109,78 +57,69 @@ Q_ENUM_NS(Enum); } // namespace ScreenConfiguration -///! Decorationless window attached to screen edges by anchors. -/// Decorationless window attached to screen edges by anchors. -/// -/// #### Example -/// The following snippet creates a white bar attached to the bottom of [TODO] screen. -/// -/// ```qml -/// ShellWindow { -/// anchors { -/// left: true -/// bottom: true -/// right: true -/// } -/// -/// Text { -/// anchors.horizontalCenter: parent.horizontalCenter -/// anchors.verticalCenter: parent.verticalCenter -/// text: "Hello!" -/// } -/// } -/// ``` -class ProxyShellWindow: public ProxyWindowBase { - // clang-format off +class WaylandShellWindowExtensions; + +class WaylandShellWindow: public ProxyShellWindow { + Q_OBJECT; + Q_PROPERTY(WaylandShellWindowExtensions* wayland MEMBER mWayland CONSTANT); + QML_NAMED_ELEMENT(ShellWindow); + +public: + explicit WaylandShellWindow(QObject* parent = nullptr); + + WaylandShellWindowExtensions* wayland(); + + void setupWindow() override; + QQuickWindow* disownWindow() override; + + void setWidth(qint32 width) override; + void setHeight(qint32 height) override; + + void setAnchors(Anchors anchors) override; + [[nodiscard]] Anchors anchors() const override; + + void setExclusiveZone(qint32 zone) override; + [[nodiscard]] qint32 exclusiveZone() const override; + + void setExclusionMode(ExclusionMode::Enum exclusionMode) override; + [[nodiscard]] ExclusionMode::Enum exclusionMode() const override; + + void setMargins(Margins margins) override; + [[nodiscard]] Margins margins() const override; + +protected slots: + void updateExclusionZone(); + +private: + WaylandShellWindowExtensions* mWayland = nullptr; + + LayerShellQt::Window* shellWindow = nullptr; + Layer::Enum mLayer = Layer::Top; + QString mScope; + KeyboardFocus::Enum mKeyboardFocus = KeyboardFocus::None; + ScreenConfiguration::Enum mScreenConfiguration = ScreenConfiguration::Window; + + bool connected = false; + + friend class WaylandShellWindowExtensions; +}; + +class WaylandShellWindowExtensions: public QObject { Q_OBJECT; - /// Anchors attach a shell window to the sides of the screen. - /// By default all anchors are disabled to avoid blocking the entire screen due to a misconfiguration. - /// - /// > [!INFO] When two opposite anchors are attached at the same time, the corrosponding dimension - /// > (width or height) will be forced to equal the screen width/height. - /// > Margins can be used to create anchored windows that are also disconnected from the monitor sides. - Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged); - /// The amount of space reserved for the shell layer relative to its anchors. - /// - /// > [!INFO] Some systems will require exactly 3 anchors to be attached for the exclusion zone to take - /// > effect. - Q_PROPERTY(qint32 exclusionZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged); - /// Defaults to `ExclusionMode.Normal`. - Q_PROPERTY(ExclusionMode::Enum exclusionMode READ exclusionMode WRITE setExclusionMode NOTIFY exclusionModeChanged); - /// Offsets from the sides of the screen. - /// - /// > [!INFO] Only applies to edges with anchors - Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged); /// The shell layer the window sits in. Defaults to `Layer.Top`. Q_PROPERTY(Layer::Enum layer READ layer WRITE setLayer NOTIFY layerChanged); Q_PROPERTY(QString scope READ scope WRITE setScope); /// The degree of keyboard focus taken. Defaults to `KeyboardFocus.None`. - Q_PROPERTY(KeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY keyboardFocusChanged); - Q_PROPERTY(ScreenConfiguration::Enum screenConfiguration READ screenConfiguration WRITE setScreenConfiguration); - QML_NAMED_ELEMENT(ShellWindow); - // clang-format on + Q_PROPERTY(KeyboardFocus::Enum keyboardFocus READ keyboardFocus WRITE setKeyboardFocus NOTIFY + keyboardFocusChanged); + Q_PROPERTY(ScreenConfiguration::Enum screenConfiguration READ screenConfiguration WRITE + setScreenConfiguration); + QML_ELEMENT; + QML_UNCREATABLE("WaylandShellWindowExtensions cannot be created"); public: - void setupWindow() override; - QQuickWindow* disownWindow() override; - - QQmlListProperty data(); - - void setWidth(qint32 width) override; - - void setHeight(qint32 height) override; - - void setAnchors(Anchors anchors); - [[nodiscard]] Anchors anchors() const; - - void setExclusiveZone(qint32 zone); - [[nodiscard]] qint32 exclusiveZone() const; - - void setExclusionMode(ExclusionMode::Enum exclusionMode); - [[nodiscard]] ExclusionMode::Enum exclusionMode() const; - - void setMargins(Margins margins); - [[nodiscard]] Margins margins() const; + explicit WaylandShellWindowExtensions(WaylandShellWindow* window): + QObject(window), window(window) {} void setLayer(Layer::Enum layer); [[nodiscard]] Layer::Enum layer() const; @@ -195,26 +134,11 @@ public: [[nodiscard]] ScreenConfiguration::Enum screenConfiguration() const; signals: - void anchorsChanged(); - void marginsChanged(); - void exclusionZoneChanged(); - void exclusionModeChanged(); void layerChanged(); void keyboardFocusChanged(); -private slots: - void updateExclusionZone(); - private: - LayerShellQt::Window* shellWindow = nullptr; - ExclusionMode::Enum mExclusionMode = ExclusionMode::Normal; - qint32 mExclusionZone = 0; - Anchors mAnchors; - Margins mMargins; - Layer::Enum mLayer = Layer::Top; - QString mScope; - KeyboardFocus::Enum mKeyboardFocus = KeyboardFocus::None; - ScreenConfiguration::Enum mScreenConfiguration = ScreenConfiguration::Window; + WaylandShellWindow* window; - bool connected = false; + friend class WaylandShellWindow; }; diff --git a/src/cpp/shellwindow.cpp b/src/cpp/shellwindow.cpp new file mode 100644 index 00000000..6b36f7e2 --- /dev/null +++ b/src/cpp/shellwindow.cpp @@ -0,0 +1 @@ +#include "shellwindow.hpp" // NOLINT diff --git a/src/cpp/shellwindow.hpp b/src/cpp/shellwindow.hpp new file mode 100644 index 00000000..25a123af --- /dev/null +++ b/src/cpp/shellwindow.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proxywindow.hpp" + +class Anchors { + Q_GADGET; + Q_PROPERTY(bool left MEMBER mLeft); + Q_PROPERTY(bool right MEMBER mRight); + Q_PROPERTY(bool top MEMBER mTop); + Q_PROPERTY(bool bottom MEMBER mBottom); + +public: + bool mLeft = false; + bool mRight = false; + bool mTop = false; + bool mBottom = false; +}; + +class Margins { + Q_GADGET; + Q_PROPERTY(qint32 left MEMBER mLeft); + Q_PROPERTY(qint32 right MEMBER mRight); + Q_PROPERTY(qint32 top MEMBER mTop); + Q_PROPERTY(qint32 bottom MEMBER mBottom); + +public: + qint32 mLeft = 0; + qint32 mRight = 0; + qint32 mTop = 0; + qint32 mBottom = 0; +}; + +namespace ExclusionMode { // NOLINT +Q_NAMESPACE; +QML_ELEMENT; + +enum Enum { + /// Respect the exclusion zone of other shell layers and optionally set one + Normal = 0, + /// Ignore exclusion zones of other shell layers. You cannot set an exclusion zone in this mode. + Ignore = 1, + /// Decide the exclusion zone based on the window dimensions and anchors. + /// + /// Will attempt to reseve exactly enough space for the window and its margins if + /// exactly 3 anchors are connected. + Auto = 2, +}; +Q_ENUM_NS(Enum); + +} // namespace ExclusionMode + +///! Decorationless window attached to screen edges by anchors. +/// Decorationless window attached to screen edges by anchors. +/// +/// #### Example +/// The following snippet creates a white bar attached to the bottom of the screen. +/// +/// ```qml +/// ShellWindow { +/// anchors { +/// left: true +/// bottom: true +/// right: true +/// } +/// +/// Text { +/// anchors.horizontalCenter: parent.horizontalCenter +/// anchors.verticalCenter: parent.verticalCenter +/// text: "Hello!" +/// } +/// } +/// ``` +class ProxyShellWindow: public ProxyWindowBase { + // clang-format off + Q_OBJECT; + /// Anchors attach a shell window to the sides of the screen. + /// By default all anchors are disabled to avoid blocking the entire screen due to a misconfiguration. + /// + /// > [!INFO] When two opposite anchors are attached at the same time, the corrosponding dimension + /// > (width or height) will be forced to equal the screen width/height. + /// > Margins can be used to create anchored windows that are also disconnected from the monitor sides. + Q_PROPERTY(Anchors anchors READ anchors WRITE setAnchors NOTIFY anchorsChanged); + /// The amount of space reserved for the shell layer relative to its anchors. + /// + /// > [!INFO] Some systems will require exactly 3 anchors to be attached for the exclusion zone to take + /// > effect. + Q_PROPERTY(qint32 exclusionZone READ exclusiveZone WRITE setExclusiveZone NOTIFY exclusionZoneChanged); + /// Defaults to `ExclusionMode.Normal`. + Q_PROPERTY(ExclusionMode::Enum exclusionMode READ exclusionMode WRITE setExclusionMode NOTIFY exclusionModeChanged); + /// Offsets from the sides of the screen. + /// + /// > [!INFO] Only applies to edges with anchors + Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged); + // clang-format on + +public: + explicit ProxyShellWindow(QObject* parent = nullptr): ProxyWindowBase(parent) {} + + QQmlListProperty data(); + + virtual void setAnchors(Anchors anchors) = 0; + [[nodiscard]] virtual Anchors anchors() const = 0; + + virtual void setExclusiveZone(qint32 zone) = 0; + [[nodiscard]] virtual qint32 exclusiveZone() const = 0; + + virtual void setExclusionMode(ExclusionMode::Enum exclusionMode) = 0; + [[nodiscard]] virtual ExclusionMode::Enum exclusionMode() const = 0; + + virtual void setMargins(Margins margins) = 0; + [[nodiscard]] virtual Margins margins() const = 0; + +signals: + void anchorsChanged(); + void marginsChanged(); + void exclusionZoneChanged(); + void exclusionModeChanged(); + +protected: + ExclusionMode::Enum mExclusionMode = ExclusionMode::Normal; + qint32 mExclusionZone = 0; + Anchors mAnchors; + Margins mMargins; +};