diff --git a/src/widgets/ClippingWrapperRectangle.qml b/src/widgets/ClippingWrapperRectangle.qml index 368c3c43..c8e65c85 100644 --- a/src/widgets/ClippingWrapperRectangle.qml +++ b/src/widgets/ClippingWrapperRectangle.qml @@ -41,6 +41,16 @@ ClippingRectangle { /// Determines if child item should be resized larger than its implicit size if /// the parent is resized larger than its implicit size. Defaults to false. property /*bool*/alias resizeChild: manager.resizeChild + /// Overrides the implicit width of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its left and right margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitWidth: manager.implicitWidth + /// Overrides the implicit height of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its top and bottom margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitHeight: manager.implicitHeight /// See @@WrapperManager.child for details. property alias child: manager.child diff --git a/src/widgets/WrapperItem.qml b/src/widgets/WrapperItem.qml index 90c62351..280e58ef 100644 --- a/src/widgets/WrapperItem.qml +++ b/src/widgets/WrapperItem.qml @@ -55,6 +55,16 @@ Item { /// Determines if child item should be resized larger than its implicit size if /// the parent is resized larger than its implicit size. Defaults to false. property /*bool*/alias resizeChild: manager.resizeChild + /// Overrides the implicit width of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its left and right margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitWidth: manager.implicitWidth + /// Overrides the implicit height of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its top and bottom margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitHeight: manager.implicitHeight /// See @@WrapperManager.child for details. property /*Item*/alias child: manager.child diff --git a/src/widgets/WrapperMouseArea.qml b/src/widgets/WrapperMouseArea.qml index 6d14a737..beeec222 100644 --- a/src/widgets/WrapperMouseArea.qml +++ b/src/widgets/WrapperMouseArea.qml @@ -43,6 +43,16 @@ MouseArea { /// Determines if child item should be resized larger than its implicit size if /// the parent is resized larger than its implicit size. Defaults to false. property /*bool*/alias resizeChild: manager.resizeChild + /// Overrides the implicit width of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its left and right margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitWidth: manager.implicitWidth + /// Overrides the implicit height of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its top and bottom margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitHeight: manager.implicitHeight /// See @@WrapperManager.child for details. property /*Item*/alias child: manager.child diff --git a/src/widgets/WrapperRectangle.qml b/src/widgets/WrapperRectangle.qml index 588e5e04..90c7b3a4 100644 --- a/src/widgets/WrapperRectangle.qml +++ b/src/widgets/WrapperRectangle.qml @@ -45,6 +45,16 @@ Rectangle { /// Determines if child item should be resized larger than its implicit size if /// the parent is resized larger than its implicit size. Defaults to false. property /*bool*/alias resizeChild: manager.resizeChild + /// Overrides the implicit width of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its left and right margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitWidth: manager.implicitWidth + /// Overrides the implicit height of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its top and bottom margin, + /// and may be reset by assigning `undefined`. + property /*real*/alias implicitHeight: manager.implicitHeight /// See @@WrapperManager.child for details. property alias child: manager.child diff --git a/src/widgets/marginwrapper.cpp b/src/widgets/marginwrapper.cpp index 623a5f95..2cb7dcda 100644 --- a/src/widgets/marginwrapper.cpp +++ b/src/widgets/marginwrapper.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "wrapper.hpp" @@ -10,22 +11,26 @@ namespace qs::widgets { MarginWrapperManager::MarginWrapperManager(QObject* parent): WrapperManager(parent) { this->bTopMargin.setBinding([this] { return this->bExtraMargin - + (this->bTopMarginSet.value() ? this->bTopMarginValue : this->bMargin); + + (this->bOverrides.value().testFlag(TopMargin) ? this->bTopMarginOverride : this->bMargin + ); }); this->bBottomMargin.setBinding([this] { return this->bExtraMargin - + (this->bBottomMarginSet.value() ? this->bBottomMarginValue : this->bMargin); + + (this->bOverrides.value().testFlag(BottomMargin) ? this->bBottomMarginOverride + : this->bMargin); }); this->bLeftMargin.setBinding([this] { return this->bExtraMargin - + (this->bLeftMarginSet.value() ? this->bLeftMarginValue : this->bMargin); + + (this->bOverrides.value().testFlag(LeftMargin) ? this->bLeftMarginOverride + : this->bMargin); }); this->bRightMargin.setBinding([this] { return this->bExtraMargin - + (this->bRightMarginSet.value() ? this->bRightMarginValue : this->bMargin); + + (this->bOverrides.value().testFlag(RightMargin) ? this->bRightMarginOverride + : this->bMargin); }); this->bChildX.setBinding([this] { @@ -63,11 +68,19 @@ MarginWrapperManager::MarginWrapperManager(QObject* parent): WrapperManager(pare }); this->bWrapperImplicitWidth.setBinding([this] { - return this->bChildImplicitWidth.value() + this->bLeftMargin + this->bRightMargin; + if (this->bOverrides.value().testFlag(ImplicitWidth)) { + return this->bImplicitWidthOverride.value(); + } else { + return this->bChildImplicitWidth.value() + this->bLeftMargin + this->bRightMargin; + } }); this->bWrapperImplicitHeight.setBinding([this] { - return this->bChildImplicitHeight.value() + this->bTopMargin + this->bBottomMargin; + if (this->bOverrides.value().testFlag(ImplicitHeight)) { + return this->bImplicitHeightOverride.value(); + } else { + return this->bChildImplicitHeight.value() + this->bLeftMargin + this->bRightMargin; + } }); } @@ -122,10 +135,12 @@ void MarginWrapperManager::onChildImplicitHeightChanged() { void MarginWrapperManager::setWrapperImplicitWidth() { if (this->mWrapper) this->mWrapper->setImplicitWidth(this->bWrapperImplicitWidth); + emit this->implicitWidthChanged(); } void MarginWrapperManager::setWrapperImplicitHeight() { if (this->mWrapper) this->mWrapper->setImplicitHeight(this->bWrapperImplicitHeight); + emit this->implicitHeightChanged(); } } // namespace qs::widgets diff --git a/src/widgets/marginwrapper.hpp b/src/widgets/marginwrapper.hpp index 7a98f07e..bb70416e 100644 --- a/src/widgets/marginwrapper.hpp +++ b/src/widgets/marginwrapper.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -69,6 +70,16 @@ class MarginWrapperManager: public WrapperManager { /// Determines if child item should be resized larger than its implicit size if /// the parent is resized larger than its implicit size. Defaults to false. Q_PROPERTY(bool resizeChild READ default WRITE default BINDABLE bindableResizeChild NOTIFY resizeChildChanged FINAL); + /// Overrides the implicit width of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its left and right margin, + /// and may be reset by assigning `undefined`. + Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth RESET resetImplicitWidth NOTIFY implicitWidthChanged FINAL); + /// Overrides the implicit height of the wrapper. + /// + /// Defaults to the implicit width of the content item plus its top and bottom margin, + /// and may be reset by assigning `undefined`. + Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight RESET resetImplicitHeight NOTIFY implicitHeightChanged FINAL); // clang-format on QML_ELEMENT; @@ -81,35 +92,61 @@ public: [[nodiscard]] QBindable bindableExtraMargin() { return &this->bExtraMargin; } [[nodiscard]] qreal topMargin() const { return this->bTopMargin.value(); } - void resetTopMargin() { this->bTopMarginSet = false; } + void resetTopMargin() { this->bOverrides = this->bOverrides.value() & ~TopMargin; } void setTopMargin(qreal topMargin) { - this->bTopMarginValue = topMargin; - this->bTopMarginSet = true; + this->bTopMarginOverride = topMargin; + this->bOverrides = this->bOverrides.value() | TopMargin; } [[nodiscard]] qreal bottomMargin() const { return this->bBottomMargin.value(); } - void resetBottomMargin() { this->bBottomMarginSet = false; } + void resetBottomMargin() { this->bOverrides = this->bOverrides.value() & ~BottomMargin; } void setBottomMargin(qreal bottomMargin) { - this->bBottomMarginValue = bottomMargin; - this->bBottomMarginSet = true; + this->bBottomMarginOverride = bottomMargin; + this->bOverrides = this->bOverrides.value() | BottomMargin; } [[nodiscard]] qreal leftMargin() const { return this->bLeftMargin.value(); } - void resetLeftMargin() { this->bLeftMarginSet = false; } + void resetLeftMargin() { this->bOverrides = this->bOverrides.value() & ~LeftMargin; } void setLeftMargin(qreal leftMargin) { - this->bLeftMarginValue = leftMargin; - this->bLeftMarginSet = true; + this->bLeftMarginOverride = leftMargin; + this->bOverrides = this->bOverrides.value() | LeftMargin; } [[nodiscard]] qreal rightMargin() const { return this->bRightMargin.value(); } - void resetRightMargin() { this->bRightMarginSet = false; } + void resetRightMargin() { this->bOverrides = this->bOverrides.value() & ~RightMargin; } void setRightMargin(qreal rightMargin) { - this->bRightMarginValue = rightMargin; - this->bRightMarginSet = true; + this->bRightMarginOverride = rightMargin; + this->bOverrides = this->bOverrides.value() | RightMargin; } [[nodiscard]] QBindable bindableResizeChild() { return &this->bResizeChild; } + [[nodiscard]] qreal implicitWidth() const { return this->bWrapperImplicitWidth.value(); } + void resetImplicitWidth() { this->bOverrides = this->bOverrides.value() & ~ImplicitWidth; } + void setImplicitWidth(qreal implicitWidth) { + this->bImplicitWidthOverride = implicitWidth; + this->bOverrides = this->bOverrides.value() | ImplicitWidth; + } + + [[nodiscard]] qreal implicitHeight() const { return this->bWrapperImplicitHeight.value(); } + void resetImplicitHeight() { this->bOverrides = this->bOverrides.value() & ~ImplicitHeight; } + void setImplicitHeight(qreal implicitHeight) { + this->bImplicitHeightOverride = implicitHeight; + this->bOverrides = this->bOverrides.value() | ImplicitHeight; + } + + // has to be public for flag operator definitions + enum OverrideFlag : quint8 { + ImplicitWidth = 0b1, + ImplicitHeight = 0b10, + TopMargin = 0b100, + BottomMargin = 0b1000, + LeftMargin = 0b10000, + RightMargin = 0b100000, + }; + + Q_DECLARE_FLAGS(OverrideFlags, OverrideFlag); + signals: void marginChanged(); void baseMarginChanged(); @@ -118,6 +155,8 @@ signals: void leftMarginChanged(); void rightMarginChanged(); void resizeChildChanged(); + void implicitWidthChanged(); + void implicitHeightChanged(); private slots: void onChildImplicitWidthChanged(); @@ -135,14 +174,13 @@ private: Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bMargin, &MarginWrapperManager::marginChanged); Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bExtraMargin, &MarginWrapperManager::baseMarginChanged); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, bool, bTopMarginSet); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, bool, bBottomMarginSet); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, bool, bLeftMarginSet); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, bool, bRightMarginSet); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bTopMarginValue); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bBottomMarginValue); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bLeftMarginValue); - Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bRightMarginValue); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, OverrideFlags, bOverrides); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bImplicitWidthOverride); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bImplicitHeightOverride); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bTopMarginOverride); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bBottomMarginOverride); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bLeftMarginOverride); + Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bRightMarginOverride); // computed Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bTopMargin, &MarginWrapperManager::topMarginChanged); @@ -167,4 +205,6 @@ private: // clang-format on }; +Q_DECLARE_OPERATORS_FOR_FLAGS(MarginWrapperManager::OverrideFlags); + } // namespace qs::widgets diff --git a/src/widgets/test/manual/marginwrapper.qml b/src/widgets/test/manual/marginwrapper.qml index c3307abe..d70ca97f 100644 --- a/src/widgets/test/manual/marginwrapper.qml +++ b/src/widgets/test/manual/marginwrapper.qml @@ -28,6 +28,8 @@ FloatingWindow { bottomMargin: separateMarginsCb.checked ? bottomMarginSlider.value : undefined leftMargin: separateMarginsCb.checked ? leftMarginSlider.value : undefined rightMargin: separateMarginsCb.checked ? rightMarginSlider.value : undefined + implicitWidth: parentImplicitSizeCb.checked ? parentImplicitWidthSlider.value : undefined + implicitHeight: parentImplicitSizeCb.checked ? parentImplicitHeightSlider.value : undefined } Rectangle { @@ -55,6 +57,11 @@ FloatingWindow { id: separateMarginsCb text: "Individual Margins" } + + CheckBox { + id: parentImplicitSizeCb + text: "Parent Implicit Size" + } } RowLayout { @@ -93,6 +100,24 @@ FloatingWindow { } } + RowLayout { + Layout.fillWidth: true + + Label { text: "Parent Implicit Width" } + Slider { + id: parentImplicitWidthSlider + Layout.fillWidth: true + from: 0; to: 300; value: 200 + } + + Label { text: "Parent Implicit Height" } + Slider { + id: parentImplicitHeightSlider + Layout.fillWidth: true + from: 0; to: 300; value: 200 + } + } + RowLayout { Layout.fillWidth: true