From 033e8108716bb348b97574c5a978ba715fd4edd4 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 19 Nov 2024 02:52:49 -0800 Subject: [PATCH] widgets: add ClippingWrapperRectangle --- src/widgets/CMakeLists.txt | 1 + src/widgets/ClippingWrapperRectangle.qml | 35 ++++++++++++++++++++++++ src/widgets/WrapperItem.qml | 1 - src/widgets/WrapperRectangle.qml | 4 +-- src/widgets/module.md | 1 + src/widgets/wrapper.cpp | 17 +++++++++++- src/widgets/wrapper.hpp | 8 ++++++ 7 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/widgets/ClippingWrapperRectangle.qml diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 3f8de41f..29e760a3 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -12,6 +12,7 @@ qt_add_qml_module(quickshell-widgets ClippingRectangle.qml WrapperItem.qml WrapperRectangle.qml + ClippingWrapperRectangle.qml ) qt6_add_shaders(quickshell-widgets "widgets-cliprect" diff --git a/src/widgets/ClippingWrapperRectangle.qml b/src/widgets/ClippingWrapperRectangle.qml new file mode 100644 index 00000000..26014a68 --- /dev/null +++ b/src/widgets/ClippingWrapperRectangle.qml @@ -0,0 +1,35 @@ +import QtQuick + +///! ClippingRectangle that handles sizes and positioning for a single visual child. +/// This component is useful for adding a clipping border or background rectangle to +/// a child item. If you don't need clipping, use @@WrapperRectangle. +/// +/// > [!NOTE] ClippingWrapperRectangle is a @@MarginWrapperManager based component. +/// > You should read its documentation as well. +/// +/// > [!WARNING] You should not set @@Item.x, @@Item.y, @@Item.width, +/// > @@Item.height or @@Item.anchors on the child item, as they are used +/// > by WrapperItem to position it. Instead set @@Item.implicitWidth and +/// > @@Item.implicitHeight. +ClippingRectangle { + id: root + + /// The minimum margin between the child item and the ClippingWrapperRectangle's + /// edges. Defaults to 0. + property /*real*/alias margin: manager.margin + /// If the child item should be resized larger than its implicit size if + /// the WrapperRectangle is resized larger than its implicit size. Defaults to false. + property /*bool*/alias resizeChild: manager.resizeChild + /// See @@WrapperManager.child for details. + property alias child: manager.child + + implicitWidth: root.contentItem.implicitWidth + (root.contentInsideBorder ? root.border.width * 2 : 0) + implicitHeight: root.contentItem.implicitHeight + (root.contentInsideBorder ? root.border.width * 2 : 0) + + resources: [ + MarginWrapperManager { + id: manager + wrapper: root.contentItem + } + ] +} diff --git a/src/widgets/WrapperItem.qml b/src/widgets/WrapperItem.qml index dfa7c0fd..e1701cac 100644 --- a/src/widgets/WrapperItem.qml +++ b/src/widgets/WrapperItem.qml @@ -1,5 +1,4 @@ import QtQuick -import Quickshell.Widgets ///! Item that handles sizes and positioning for a single visual child. /// This component is useful when you need to wrap a single component in diff --git a/src/widgets/WrapperRectangle.qml b/src/widgets/WrapperRectangle.qml index c198c47b..e1c2c833 100644 --- a/src/widgets/WrapperRectangle.qml +++ b/src/widgets/WrapperRectangle.qml @@ -1,9 +1,9 @@ import QtQuick -import Quickshell.Widgets ///! Rectangle that handles sizes and positioning for a single visual child. /// This component is useful for adding a border or background rectangle to -/// a child item. +/// a child item. If you need to clip the child item to the rectangle's +/// border, see @@ClippingWrapperRectangle. /// /// > [!NOTE] WrapperRectangle is a @@MarginWrapperManager based component. /// > You should read its documentation as well. diff --git a/src/widgets/module.md b/src/widgets/module.md index 77d4a3a5..4009b790 100644 --- a/src/widgets/module.md +++ b/src/widgets/module.md @@ -11,5 +11,6 @@ qml_files = [ "ClippingRectangle.qml", "WrapperItem.qml", "WrapperRectangle.qml", + "ClippingWrapperRectangle.qml", ] ----- diff --git a/src/widgets/wrapper.cpp b/src/widgets/wrapper.cpp index 4e502cee..40d7755d 100644 --- a/src/widgets/wrapper.cpp +++ b/src/widgets/wrapper.cpp @@ -11,7 +11,11 @@ namespace qs::widgets { void WrapperManager::componentComplete() { - this->mWrapper = qobject_cast(this->parent()); + if (this->mAssignedWrapper) { + this->mWrapper = this->mAssignedWrapper; + } else { + this->mWrapper = qobject_cast(this->parent()); + } if (!this->mWrapper) { QString pstr; @@ -118,6 +122,17 @@ void WrapperManager::onChildDestroyed() { emit this->childChanged(); } +QQuickItem* WrapperManager::wrapper() const { return this->mWrapper; } + +void WrapperManager::setWrapper(QQuickItem* wrapper) { + if (this->mWrapper) { + qmlWarning(this) << "Cannot set wrapper after WrapperManager initialization."; + return; + } + + this->mAssignedWrapper = wrapper; +} + void WrapperManager::printChildCountWarning() const { qmlWarning(this->mWrapper) << "Wrapper component cannot have more than one visual child."; qmlWarning(this->mWrapper) << "Remove all additional children, or pick a specific component " diff --git a/src/widgets/wrapper.hpp b/src/widgets/wrapper.hpp index 95b3adea..993cfd51 100644 --- a/src/widgets/wrapper.hpp +++ b/src/widgets/wrapper.hpp @@ -98,6 +98,9 @@ class WrapperManager /// When read, `child` will always return the (potentially null) selected child, /// and not `undefined`. Q_PROPERTY(QQuickItem* child READ child WRITE setProspectiveChild RESET unsetChild NOTIFY childChanged FINAL); + /// The wrapper managed by this manager. Defaults to the manager's parent. + /// This property may not be changed after Component.onCompleted. + Q_PROPERTY(QQuickItem* wrapper READ wrapper WRITE setWrapper NOTIFY wrapperChanged FINAL); // clang-format on QML_ELEMENT; @@ -112,8 +115,12 @@ public: void setProspectiveChild(QQuickItem* child); void unsetChild(); + [[nodiscard]] QQuickItem* wrapper() const; + void setWrapper(QQuickItem* wrapper); + signals: void childChanged(); + void wrapperChanged(); QSDOC_HIDE void initializedChildChanged(); private slots: @@ -131,6 +138,7 @@ protected: void updateGeometry(); QQuickItem* mWrapper = nullptr; + QQuickItem* mAssignedWrapper = nullptr; QPointer mDefaultChild; QQuickItem* mChild = nullptr; Flags flags;