diff --git a/src/core/popupanchor.cpp b/src/core/popupanchor.cpp index 32d36dc5..a1ada033 100644 --- a/src/core/popupanchor.cpp +++ b/src/core/popupanchor.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "../window/proxywindow.hpp" @@ -126,12 +127,21 @@ void PopupAnchor::setRect(Box rect) { this->mUserRect = rect; emit this->rectChanged(); - this->setWindowRect(rect); + this->setWindowRect(rect.qrect().marginsRemoved(this->mMargins.qmargins())); } -void PopupAnchor::setWindowRect(Box rect) { - if (rect.w <= 0) rect.w = 1; - if (rect.h <= 0) rect.h = 1; +void PopupAnchor::setMargins(Margins margins) { + if (margins == this->mMargins) return; + + this->mMargins = margins; + emit this->marginsChanged(); + + this->setWindowRect(this->mUserRect.qrect().marginsRemoved(margins.qmargins())); +} + +void PopupAnchor::setWindowRect(QRect rect) { + if (rect.width() <= 0) rect.setWidth(1); + if (rect.height() <= 0) rect.setHeight(1); if (rect == this->state.rect) return; this->state.rect = rect; @@ -177,12 +187,14 @@ void PopupAnchor::updatePlacement(const QPoint& anchorpoint, const QSize& size) void PopupAnchor::updateAnchor() { if (this->mItem && this->mProxyWindow) { - auto rect = this->mProxyWindow->contentItem()->mapRectFromItem( + auto baseRect = + this->mUserRect.isEmpty() ? this->mItem->boundingRect() : this->mUserRect.qrect(); + auto rect = this->mProxyWindow->contentItem()->mapFromItem( this->mItem, - this->mUserRect.isEmpty() ? this->mItem->boundingRect() : this->mUserRect.qrect() + baseRect.marginsRemoved(this->mMargins.qmargins()) ); - this->setWindowRect(rect); + this->setWindowRect(rect.toRect()); } emit this->anchoring(); @@ -207,7 +219,7 @@ void PopupPositioner::reposition(PopupAnchor* anchor, QWindow* window, bool only auto adjustment = anchor->adjustment(); auto screenGeometry = parentWindow->screen()->geometry(); - auto anchorRectGeometry = anchor->windowRect().qrect().translated(parentGeometry.topLeft()); + auto anchorRectGeometry = anchor->windowRect().translated(parentGeometry.topLeft()); auto anchorEdges = anchor->edges(); auto anchorGravity = anchor->gravity(); diff --git a/src/core/popupanchor.hpp b/src/core/popupanchor.hpp index 49668398..a9b121ed 100644 --- a/src/core/popupanchor.hpp +++ b/src/core/popupanchor.hpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include "../window/proxywindow.hpp" @@ -61,7 +63,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(PopupAdjustment::Flags); struct PopupAnchorState { bool operator==(const PopupAnchorState& other) const; - Box rect = {0, 0, 1, 1}; + QRect rect = {0, 0, 1, 1}; Edges::Flags edges = Edges::Top | Edges::Left; Edges::Flags gravity = Edges::Bottom | Edges::Right; PopupAdjustment::Flags adjustment = PopupAdjustment::Slide; @@ -90,12 +92,19 @@ class PopupAnchor: public QObject { /// The anchorpoints the popup will attach to, relative to @@item or @@window. /// Which anchors will be used is determined by the @@edges, @@gravity, and @@adjustment. /// + /// If using @@item, the default anchor rectangle matches the dimensions of the item. + /// /// If you leave @@edges, @@gravity and @@adjustment at their default values, /// setting more than `x` and `y` does not matter. The anchor rect cannot /// be smaller than 1x1 pixels. /// /// [coordinate mapping functions]: https://doc.qt.io/qt-6/qml-qtquick-item.html#mapFromItem-method Q_PROPERTY(Box rect READ rect WRITE setRect RESET resetRect NOTIFY rectChanged); + /// A margin applied to the anchor rect. + /// + /// This is most useful when @@item is used and @@rect is left at its default + /// value (matching the Item's dimensions). + Q_PROPERTY(Margins margins READ margins WRITE setMargins NOTIFY marginsChanged); /// The point on the anchor rectangle the popup should anchor to. /// Opposing edges suchs as `Edges.Left | Edges.Right` are not allowed. /// @@ -138,13 +147,16 @@ public: [[nodiscard]] QQuickItem* item() const { return this->mItem; } void setItem(QQuickItem* item); - [[nodiscard]] Box windowRect() const { return this->state.rect; } - void setWindowRect(Box rect); + [[nodiscard]] QRect windowRect() const { return this->state.rect; } + void setWindowRect(QRect rect); [[nodiscard]] Box rect() const { return this->mUserRect; } void setRect(Box rect); void resetRect(); + [[nodiscard]] Margins margins() const { return this->mMargins; } + void setMargins(Margins margins); + [[nodiscard]] Edges::Flags edges() const { return this->state.edges; } void setEdges(Edges::Flags edges); @@ -168,6 +180,7 @@ signals: QSDOC_HIDE void backingWindowVisibilityChanged(); QSDOC_HIDE void windowRectChanged(); void rectChanged(); + void marginsChanged(); void edgesChanged(); void gravityChanged(); void adjustmentChanged(); @@ -183,6 +196,7 @@ private: ProxyWindowBase* mProxyWindow = nullptr; PopupAnchorState state; Box mUserRect; + Margins mMargins; std::optional lastState; }; diff --git a/src/wayland/popupanchor.cpp b/src/wayland/popupanchor.cpp index 1c9e1ccb..3baee9fe 100644 --- a/src/wayland/popupanchor.cpp +++ b/src/wayland/popupanchor.cpp @@ -46,13 +46,11 @@ void WaylandPopupPositioner::reposition(PopupAnchor* anchor, QWindow* window, bo auto anchorRect = anchor->windowRect(); if (auto* p = window->transientParent()) { - anchorRect.x = QHighDpi::toNativePixels(anchorRect.x, p); - anchorRect.y = QHighDpi::toNativePixels(anchorRect.y, p); - anchorRect.w = QHighDpi::toNativePixels(anchorRect.w, p); - anchorRect.h = QHighDpi::toNativePixels(anchorRect.h, p); + anchorRect = QHighDpi::toNativePixels(anchorRect, p); } - positioner.set_anchor_rect(anchorRect.x, anchorRect.y, anchorRect.w, anchorRect.h); + positioner + .set_anchor_rect(anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); XdgPositioner::anchor anchorFlag = XdgPositioner::anchor_none; switch (anchor->edges()) { @@ -107,15 +105,12 @@ void WaylandPopupPositioner::setFlags(PopupAnchor* anchor, QWindow* window) { auto anchorRect = anchor->windowRect(); if (auto* p = window->transientParent()) { - anchorRect.x = QHighDpi::toNativePixels(anchorRect.x, p); - anchorRect.y = QHighDpi::toNativePixels(anchorRect.y, p); - anchorRect.w = QHighDpi::toNativePixels(anchorRect.w, p); - anchorRect.h = QHighDpi::toNativePixels(anchorRect.h, p); + anchorRect = QHighDpi::toNativePixels(anchorRect, p); } // clang-format off window->setProperty("_q_waylandPopupConstraintAdjustment", anchor->adjustment().toInt()); - window->setProperty("_q_waylandPopupAnchorRect", anchorRect.qrect()); + window->setProperty("_q_waylandPopupAnchorRect", anchorRect); window->setProperty("_q_waylandPopupAnchor", QVariant::fromValue(Edges::toQt(anchor->edges()))); window->setProperty("_q_waylandPopupGravity", QVariant::fromValue(Edges::toQt(anchor->gravity()))); // clang-format on