diff --git a/src/window/proxywindow.cpp b/src/window/proxywindow.cpp index 23dd3635..df9b6b3d 100644 --- a/src/window/proxywindow.cpp +++ b/src/window/proxywindow.cpp @@ -4,8 +4,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -461,12 +463,71 @@ QQmlListProperty ProxyWindowBase::data() { void ProxyWindowBase::onWidthChanged() { this->mContentItem->setWidth(this->width()); } void ProxyWindowBase::onHeightChanged() { this->mContentItem->setHeight(this->height()); } +QPointF ProxyWindowBase::itemPosition(QQuickItem* item) const { + if (!item) { + qCritical() << "Cannot map position of null item."; + return {}; + } + + return this->mContentItem->mapFromItem(item, 0, 0); +} + +QRectF ProxyWindowBase::itemRect(QQuickItem* item) const { + if (!item) { + qCritical() << "Cannot map position of null item."; + return {}; + } + + return this->mContentItem->mapFromItem(item, item->boundingRect()); +} + +QPointF ProxyWindowBase::mapFromItem(QQuickItem* item, QPointF point) const { + if (!item) { + qCritical() << "Cannot map position of null item."; + return {}; + } + + return this->mContentItem->mapFromItem(item, point); +} + +QPointF ProxyWindowBase::mapFromItem(QQuickItem* item, qreal x, qreal y) const { + if (!item) { + qCritical() << "Cannot map position of null item."; + return {}; + } + + return this->mContentItem->mapFromItem(item, x, y); +} + +QRectF ProxyWindowBase::mapFromItem(QQuickItem* item, QRectF rect) const { + if (!item) { + qCritical() << "Cannot map position of null item."; + return {}; + } + + return this->mContentItem->mapFromItem(item, rect); +} + +QRectF +ProxyWindowBase::mapFromItem(QQuickItem* item, qreal x, qreal y, qreal width, qreal height) const { + if (!item) { + qCritical() << "Cannot map position of null item."; + return {}; + } + + return this->mContentItem->mapFromItem(item, x, y, width, height); +} + ProxyWindowAttached::ProxyWindowAttached(QQuickItem* parent): QsWindowAttached(parent) { this->updateWindow(); } -QObject* ProxyWindowAttached::window() const { return this->mWindow; } -QQuickItem* ProxyWindowAttached::contentItem() const { return this->mWindow->contentItem(); } +QObject* ProxyWindowAttached::window() const { return this->mWindowInterface; } +ProxyWindowBase* ProxyWindowAttached::proxyWindow() const { return this->mWindow; } + +QQuickItem* ProxyWindowAttached::contentItem() const { + return this->mWindow ? this->mWindow->contentItem() : nullptr; +} void ProxyWindowAttached::updateWindow() { auto* window = static_cast(this->parent())->window(); // NOLINT @@ -481,6 +542,7 @@ void ProxyWindowAttached::updateWindow() { void ProxyWindowAttached::setWindow(ProxyWindowBase* window) { if (window == this->mWindow) return; this->mWindow = window; + this->mWindowInterface = window ? qobject_cast(window->parent()) : nullptr; emit this->windowChanged(); } diff --git a/src/window/proxywindow.hpp b/src/window/proxywindow.hpp index f6acbca8..42039414 100644 --- a/src/window/proxywindow.hpp +++ b/src/window/proxywindow.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,8 @@ #include #include #include +#include +#include #include #include "../core/qmlscreen.hpp" @@ -67,6 +70,14 @@ public: void operator=(ProxyWindowBase&) = delete; void operator=(ProxyWindowBase&&) = delete; + Q_INVOKABLE [[nodiscard]] QPointF itemPosition(QQuickItem* item) const; + Q_INVOKABLE [[nodiscard]] QRectF itemRect(QQuickItem* item) const; + Q_INVOKABLE [[nodiscard]] QPointF mapFromItem(QQuickItem* item, QPointF point) const; + Q_INVOKABLE [[nodiscard]] QPointF mapFromItem(QQuickItem* item, qreal x, qreal y) const; + Q_INVOKABLE [[nodiscard]] QRectF mapFromItem(QQuickItem* item, QRectF rect) const; + Q_INVOKABLE [[nodiscard]] QRectF + mapFromItem(QQuickItem* item, qreal x, qreal y, qreal width, qreal height) const; + void onReload(QObject* oldInstance) override; void ensureQWindow(); void createWindow(); @@ -201,6 +212,7 @@ public: explicit ProxyWindowAttached(QQuickItem* parent); [[nodiscard]] QObject* window() const override; + [[nodiscard]] ProxyWindowBase* proxyWindow() const override; [[nodiscard]] QQuickItem* contentItem() const override; protected: @@ -208,6 +220,7 @@ protected: private: ProxyWindowBase* mWindow = nullptr; + WindowInterface* mWindowInterface = nullptr; void setWindow(ProxyWindowBase* window); }; diff --git a/src/window/windowinterface.cpp b/src/window/windowinterface.cpp index b5cf4930..20057d64 100644 --- a/src/window/windowinterface.cpp +++ b/src/window/windowinterface.cpp @@ -1,14 +1,96 @@ #include "windowinterface.hpp" +#include #include #include +#include #include "proxywindow.hpp" +QPointF WindowInterface::itemPosition(QQuickItem* item) const { + return this->proxyWindow()->itemPosition(item); +} + +QRectF WindowInterface::itemRect(QQuickItem* item) const { + return this->proxyWindow()->itemRect(item); +} + +QPointF WindowInterface::mapFromItem(QQuickItem* item, QPointF point) const { + return this->proxyWindow()->mapFromItem(item, point); +} + +QPointF WindowInterface::mapFromItem(QQuickItem* item, qreal x, qreal y) const { + return this->proxyWindow()->mapFromItem(item, x, y); +} + +QRectF WindowInterface::mapFromItem(QQuickItem* item, QRectF rect) const { + return this->proxyWindow()->mapFromItem(item, rect); +} + +QRectF +WindowInterface::mapFromItem(QQuickItem* item, qreal x, qreal y, qreal width, qreal height) const { + return this->proxyWindow()->mapFromItem(item, x, y, width, height); +} + QsWindowAttached::QsWindowAttached(QQuickItem* parent): QObject(parent) { QObject::connect(parent, &QQuickItem::windowChanged, this, &QsWindowAttached::updateWindow); } +QPointF QsWindowAttached::itemPosition(QQuickItem* item) const { + if (auto* proxyWindow = this->proxyWindow()) { + return proxyWindow->itemPosition(item); + } else { + qCritical() << "Cannot call itemPosition before item is a member of a window."; + return {}; + } +} + +QRectF QsWindowAttached::itemRect(QQuickItem* item) const { + if (auto* proxyWindow = this->proxyWindow()) { + return proxyWindow->itemRect(item); + } else { + qCritical() << "Cannot call itemRect before item is a member of a window."; + return {}; + } +} + +QPointF QsWindowAttached::mapFromItem(QQuickItem* item, QPointF point) const { + if (auto* proxyWindow = this->proxyWindow()) { + return proxyWindow->mapFromItem(item, point); + } else { + qCritical() << "Cannot call mapFromItem before item is a member of a window."; + return {}; + } +} + +QPointF QsWindowAttached::mapFromItem(QQuickItem* item, qreal x, qreal y) const { + if (auto* proxyWindow = this->proxyWindow()) { + return proxyWindow->mapFromItem(item, x, y); + } else { + qCritical() << "Cannot call mapFromItem before item is a member of a window."; + return {}; + } +} + +QRectF QsWindowAttached::mapFromItem(QQuickItem* item, QRectF rect) const { + if (auto* proxyWindow = this->proxyWindow()) { + return proxyWindow->mapFromItem(item, rect); + } else { + qCritical() << "Cannot call mapFromItem before item is a member of a window."; + return {}; + } +} + +QRectF +QsWindowAttached::mapFromItem(QQuickItem* item, qreal x, qreal y, qreal width, qreal height) const { + if (auto* proxyWindow = this->proxyWindow()) { + return proxyWindow->mapFromItem(item, x, y, width, height); + } else { + qCritical() << "Cannot call mapFromItem before item is a member of a window."; + return {}; + } +} + QsWindowAttached* WindowInterface::qmlAttachedProperties(QObject* object) { while (object && !qobject_cast(object)) { object = object->parent(); diff --git a/src/window/windowinterface.hpp b/src/window/windowinterface.hpp index 894a5aa9..b8edff23 100644 --- a/src/window/windowinterface.hpp +++ b/src/window/windowinterface.hpp @@ -42,6 +42,9 @@ public: /// It provides the following properties /// - `window` - the `QSWindow` object. /// - `contentItem` - the `contentItem` property of the window. +/// +/// @@itemPosition(), @@itemRect(), and @@mapFromItem() can also be called directly +/// on the attached object. class WindowInterface: public Reloadable { Q_OBJECT; // clang-format off @@ -150,6 +153,49 @@ class WindowInterface: public Reloadable { public: explicit WindowInterface(QObject* parent = nullptr): Reloadable(parent) {} + /// Returns the given Item's position relative to the window. Does not update reactively. + /// + /// Equivalent to calling `window.contentItem.mapFromItem(item, 0, 0)` + /// + /// See also: @@QtQuick.Item.mapFromItem() + Q_INVOKABLE [[nodiscard]] QPointF itemPosition(QQuickItem* item) const; + /// Returns the given Item's geometry relative to the window. Does not update reactively. + /// + /// Equivalent to calling `window.contentItem.mapFromItem(item, 0, 0, 0, 0)` + /// + /// See also: @@QtQuick.Item.mapFromItem() + Q_INVOKABLE [[nodiscard]] QRectF itemRect(QQuickItem* item) const; + /// Maps the given point in the coordinate space of `item` to one in the coordinate space + /// of this window. Does not update reactively. + /// + /// Equivalent to calling `window.contentItem.mapFromItem(item, point)` + /// + /// See also: @@QtQuick.Item.mapFromItem() + Q_INVOKABLE [[nodiscard]] QPointF mapFromItem(QQuickItem* item, QPointF point) const; + /// Maps the given point in the coordinate space of `item` to one in the coordinate space + /// of this window. Does not update reactively. + /// + /// Equivalent to calling `window.contentItem.mapFromItem(item, x, y)` + /// + /// See also: @@QtQuick.Item.mapFromItem() + Q_INVOKABLE [[nodiscard]] QPointF mapFromItem(QQuickItem* item, qreal x, qreal y) const; + /// Maps the given rect in the coordinate space of `item` to one in the coordinate space + /// of this window. Does not update reactively. + /// + /// Equivalent to calling `window.contentItem.mapFromItem(item, rect)` + /// + /// See also: @@QtQuick.Item.mapFromItem() + Q_INVOKABLE [[nodiscard]] QRectF mapFromItem(QQuickItem* item, QRectF rect) const; + // clang-format off + /// Maps the given rect in the coordinate space of `item` to one in the coordinate space + /// of this window. Does not update reactively. + /// + /// Equivalent to calling `window.contentItem.mapFromItem(item, x, y, width, height)` + /// + /// See also: @@QtQuick.Item.mapFromItem() + Q_INVOKABLE [[nodiscard]] QRectF mapFromItem(QQuickItem* item, qreal x, qreal y, qreal width, qreal height) const; + // clang-format on + [[nodiscard]] virtual ProxyWindowBase* proxyWindow() const = 0; [[nodiscard]] virtual QQuickItem* contentItem() const = 0; @@ -213,8 +259,18 @@ class QsWindowAttached: public QObject { public: [[nodiscard]] virtual QObject* window() const = 0; + [[nodiscard]] virtual ProxyWindowBase* proxyWindow() const = 0; [[nodiscard]] virtual QQuickItem* contentItem() const = 0; + Q_INVOKABLE [[nodiscard]] QPointF itemPosition(QQuickItem* item) const; + Q_INVOKABLE [[nodiscard]] QRectF itemRect(QQuickItem* item) const; + Q_INVOKABLE [[nodiscard]] QPointF mapFromItem(QQuickItem* item, QPointF point) const; + Q_INVOKABLE [[nodiscard]] QPointF mapFromItem(QQuickItem* item, qreal x, qreal y) const; + Q_INVOKABLE [[nodiscard]] QRectF mapFromItem(QQuickItem* item, QRectF rect) const; + + Q_INVOKABLE [[nodiscard]] QRectF + mapFromItem(QQuickItem* item, qreal x, qreal y, qreal width, qreal height) const; + signals: void windowChanged();