widgets/wrapper: support overriding implicit size

This commit is contained in:
outfoxxed 2025-05-24 01:55:55 -07:00
parent e135de9ec6
commit 3cf96ecf97
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
7 changed files with 146 additions and 26 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -2,6 +2,7 @@
#include <qobject.h>
#include <qquickitem.h>
#include <qtmetamacros.h>
#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

View file

@ -1,5 +1,6 @@
#pragma once
#include <qflags.h>
#include <qobject.h>
#include <qproperty.h>
#include <qqmlintegration.h>
@ -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<qreal> 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<bool> 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

View file

@ -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