Skip to content

Commit ead9141

Browse files
committed
widgets/wrapper: add distinct top/bottom/left/right margins
1 parent ca26210 commit ead9141

File tree

5 files changed

+230
-51
lines changed

5 files changed

+230
-51
lines changed

src/widgets/ClippingWrapperRectangle.qml

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import QtQuick
55
/// a child item. If you don't need clipping, use @@WrapperRectangle.
66
///
77
/// > [!NOTE] ClippingWrapperRectangle is a @@MarginWrapperManager based component.
8-
/// > You should read its documentation as well.
8+
/// > See its documentation for information on how margins and sizes are calculated.
99
///
1010
/// > [!WARNING] You should not set @@Item.x, @@Item.y, @@Item.width,
1111
/// > @@Item.height or @@Item.anchors on the child item, as they are used
@@ -14,11 +14,32 @@ import QtQuick
1414
ClippingRectangle {
1515
id: root
1616

17-
/// The minimum margin between the child item and the ClippingWrapperRectangle's
18-
/// edges. Defaults to 0.
17+
/// The default for @@topMargin, @@bottomMargin, @@leftMargin and @@rightMargin.
18+
/// Defaults to 0.
1919
property /*real*/alias margin: manager.margin
20-
/// If the child item should be resized larger than its implicit size if
21-
/// the WrapperRectangle is resized larger than its implicit size. Defaults to false.
20+
/// An extra margin applied in addition to @@topMargin, @@bottomMargin,
21+
/// @@leftMargin, and @@rightMargin.
22+
/// If @@contentInsideBorder is true, the rectangle's border width will be added
23+
/// to this property. Defaults to 0.
24+
property /*real*/alias extraMargin: manager.extraMargin
25+
/// The requested top margin of the content item, not counting @@extraMargin.
26+
///
27+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
28+
property /*real*/alias topMargin: manager.topMargin
29+
/// The requested bottom margin of the content item, not counting @@extraMargin.
30+
///
31+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
32+
property /*real*/alias bottomMargin: manager.bottomMargin
33+
/// The requested left margin of the content item, not counting @@extraMargin.
34+
///
35+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
36+
property /*real*/alias leftMargin: manager.leftMargin
37+
/// The requested right margin of the content item, not counting @@extraMargin.
38+
///
39+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
40+
property /*real*/alias rightMargin: manager.rightMargin
41+
/// Determines if child item should be resized larger than its implicit size if
42+
/// the parent is resized larger than its implicit size. Defaults to false.
2243
property /*bool*/alias resizeChild: manager.resizeChild
2344
/// See @@WrapperManager.child for details.
2445
property alias child: manager.child

src/widgets/WrapperItem.qml

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import QtQuick
66
/// for positioning multiple items.
77
///
88
/// > [!NOTE] WrapperItem is a @@MarginWrapperManager based component.
9-
/// > You should read its documentation as well.
9+
/// > See its documentation for information on how margins and sizes are calculated.
1010
///
1111
/// ### Example: Adding a margin to an item
1212
/// The snippet below adds a 10px margin to all sides of the @@QtQuick.Text item.
@@ -30,11 +30,30 @@ import QtQuick
3030
///
3131
/// [QtQuick.Layouts]: https://doc.qt.io/qt-6/qtquicklayouts-index.html
3232
Item {
33-
/// The minimum margin between the child item and the WrapperItem's edges.
33+
/// The default for @@topMargin, @@bottomMargin, @@leftMargin and @@rightMargin.
3434
/// Defaults to 0.
3535
property /*real*/alias margin: manager.margin
36-
/// If the child item should be resized larger than its implicit size if
37-
/// the WrapperItem is resized larger than its implicit size. Defaults to false.
36+
/// An extra margin applied in addition to @@topMargin, @@bottomMargin,
37+
/// @@leftMargin, and @@rightMargin. Defaults to 0.
38+
property /*real*/alias extraMargin: manager.extraMargin
39+
/// The requested top margin of the content item, not counting @@extraMargin.
40+
///
41+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
42+
property /*real*/alias topMargin: manager.topMargin
43+
/// The requested bottom margin of the content item, not counting @@extraMargin.
44+
///
45+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
46+
property /*real*/alias bottomMargin: manager.bottomMargin
47+
/// The requested left margin of the content item, not counting @@extraMargin.
48+
///
49+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
50+
property /*real*/alias leftMargin: manager.leftMargin
51+
/// The requested right margin of the content item, not counting @@extraMargin.
52+
///
53+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
54+
property /*real*/alias rightMargin: manager.rightMargin
55+
/// Determines if child item should be resized larger than its implicit size if
56+
/// the parent is resized larger than its implicit size. Defaults to false.
3857
property /*bool*/alias resizeChild: manager.resizeChild
3958
/// See @@WrapperManager.child for details.
4059
property /*Item*/alias child: manager.child

src/widgets/WrapperRectangle.qml

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import QtQuick
66
/// border, see @@ClippingWrapperRectangle.
77
///
88
/// > [!NOTE] WrapperRectangle is a @@MarginWrapperManager based component.
9-
/// > You should read its documentation as well.
9+
/// > See its documentation for information on how margins and sizes are calculated.
1010
///
1111
/// > [!WARNING] You should not set @@Item.x, @@Item.y, @@Item.width,
1212
/// > @@Item.height or @@Item.anchors on the child item, as they are used
@@ -16,20 +16,40 @@ Rectangle {
1616
id: root
1717

1818
/// If true (default), the rectangle's border width will be added
19-
/// to the margin.
19+
/// to @@extraMargin.
2020
property bool contentInsideBorder: true
21-
/// The minimum margin between the child item and the WrapperRectangle's
22-
/// edges. If @@contentInsideBorder is true, this excludes the border,
23-
/// otherwise it includes it. Defaults to 0.
24-
property real margin: 0
25-
/// If the child item should be resized larger than its implicit size if
26-
/// the WrapperRectangle is resized larger than its implicit size. Defaults to false.
21+
/// The default for @@topMargin, @@bottomMargin, @@leftMargin and @@rightMargin.
22+
/// Defaults to 0.
23+
property /*real*/alias margin: manager.margin
24+
/// An extra margin applied in addition to @@topMargin, @@bottomMargin,
25+
/// @@leftMargin, and @@rightMargin.
26+
/// If @@contentInsideBorder is true, the rectangle's border width will be added
27+
/// to this property. Defaults to 0.
28+
property real extraMargin: 0
29+
/// The requested top margin of the content item, not counting @@extraMargin.
30+
///
31+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
32+
property /*real*/alias topMargin: manager.topMargin
33+
/// The requested bottom margin of the content item, not counting @@extraMargin.
34+
///
35+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
36+
property /*real*/alias bottomMargin: manager.bottomMargin
37+
/// The requested left margin of the content item, not counting @@extraMargin.
38+
///
39+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
40+
property /*real*/alias leftMargin: manager.leftMargin
41+
/// The requested right margin of the content item, not counting @@extraMargin.
42+
///
43+
/// Defaults to @@margin, and may be reset by assigning `undefined`.
44+
property /*real*/alias rightMargin: manager.rightMargin
45+
/// Determines if child item should be resized larger than its implicit size if
46+
/// the parent is resized larger than its implicit size. Defaults to false.
2747
property /*bool*/alias resizeChild: manager.resizeChild
2848
/// See @@WrapperManager.child for details.
2949
property alias child: manager.child
3050

3151
MarginWrapperManager {
3252
id: manager
33-
margin: (root.contentInsideBorder ? root.border.width : 0) + root.margin
53+
extraMargin: (root.contentInsideBorder ? root.border.width : 0) + root.extraMargin
3454
}
3555
}

src/widgets/marginwrapper.cpp

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "marginwrapper.hpp"
2-
#include <algorithm>
32

43
#include <qobject.h>
54
#include <qquickitem.h>
@@ -17,6 +16,35 @@ MarginWrapperManager::MarginWrapperManager(QObject* parent): WrapperManager(pare
1716
this,
1817
&MarginWrapperManager::onChildChanged
1918
);
19+
20+
this->bTopMargin.setBinding([this] {
21+
return this->bExtraMargin
22+
+ (this->bTopMarginSet.value() ? this->bTopMarginValue : this->bMargin);
23+
});
24+
25+
this->bBottomMargin.setBinding([this] {
26+
return this->bExtraMargin
27+
+ (this->bBottomMarginSet.value() ? this->bBottomMarginValue : this->bMargin);
28+
});
29+
30+
this->bLeftMargin.setBinding([this] {
31+
return this->bExtraMargin
32+
+ (this->bLeftMarginSet.value() ? this->bLeftMarginValue : this->bMargin);
33+
});
34+
35+
this->bRightMargin.setBinding([this] {
36+
return this->bExtraMargin
37+
+ (this->bRightMarginSet.value() ? this->bRightMarginValue : this->bMargin);
38+
});
39+
40+
// Coalesces updates via binding infrastructure
41+
this->bUpdateWatcher.setBinding([this] {
42+
this->bTopMargin.value();
43+
this->bBottomMargin.value();
44+
this->bLeftMargin.value();
45+
this->bRightMargin.value();
46+
return 0;
47+
});
2048
}
2149

2250
void MarginWrapperManager::componentComplete() {
@@ -41,15 +69,6 @@ void MarginWrapperManager::componentComplete() {
4169
if (!this->mChild) this->updateGeometry();
4270
}
4371

44-
qreal MarginWrapperManager::margin() const { return this->mMargin; }
45-
46-
void MarginWrapperManager::setMargin(qreal margin) {
47-
if (margin == this->mMargin) return;
48-
this->mMargin = margin;
49-
this->updateGeometry();
50-
emit this->marginChanged();
51-
}
52-
5372
bool MarginWrapperManager::resizeChild() const { return this->mResizeChild; }
5473

5574
void MarginWrapperManager::setResizeChild(bool resizeChild) {
@@ -82,33 +101,36 @@ void MarginWrapperManager::onChildChanged() {
82101
}
83102

84103
qreal MarginWrapperManager::targetChildWidth() const {
85-
auto max = this->mWrapper->width() - this->mMargin * 2;
104+
auto max = this->mWrapper->width() - (this->bLeftMargin + this->bRightMargin);
86105

87106
if (this->mResizeChild) return max;
88-
else return std::min(this->mChild->implicitWidth(), max);
107+
else return this->mChild->implicitWidth();
89108
}
90109

91110
qreal MarginWrapperManager::targetChildHeight() const {
92-
auto max = this->mWrapper->height() - this->mMargin * 2;
111+
auto max = this->mWrapper->height() - (this->bTopMargin + this->bBottomMargin);
93112

94113
if (this->mResizeChild) return max;
95-
else return std::min(this->mChild->implicitHeight(), max);
114+
else return this->mChild->implicitHeight();
96115
}
97116

98117
qreal MarginWrapperManager::targetChildX() const {
99-
if (this->mResizeChild) return this->mMargin;
118+
if (this->mResizeChild) return this->bLeftMargin;
100119
else {
101-
return std::max(this->mMargin, this->mWrapper->width() / 2 - this->mChild->implicitWidth() / 2);
120+
auto total = this->bLeftMargin + this->bRightMargin;
121+
auto mul = total == 0 ? 0.5 : this->bLeftMargin / total;
122+
auto margin = this->mWrapper->width() - this->mChild->implicitWidth();
123+
return margin * mul;
102124
}
103125
}
104126

105127
qreal MarginWrapperManager::targetChildY() const {
106-
if (this->mResizeChild) return this->mMargin;
128+
if (this->mResizeChild) return this->bTopMargin;
107129
else {
108-
return std::max(
109-
this->mMargin,
110-
this->mWrapper->height() / 2 - this->mChild->implicitHeight() / 2
111-
);
130+
auto total = this->bTopMargin + this->bBottomMargin;
131+
auto mul = total == 0 ? 0.5 : this->bTopMargin / total;
132+
auto margin = this->mWrapper->height() - this->mChild->implicitHeight();
133+
return margin * mul;
112134
}
113135
}
114136

@@ -126,7 +148,9 @@ void MarginWrapperManager::updateChildY() {
126148

127149
void MarginWrapperManager::onChildImplicitWidthChanged() {
128150
if (!this->mChild || !this->mWrapper) return;
129-
this->mWrapper->setImplicitWidth(this->mChild->implicitWidth() + this->mMargin * 2);
151+
this->mWrapper->setImplicitWidth(
152+
this->mChild->implicitWidth() + this->bLeftMargin + this->bRightMargin
153+
);
130154

131155
// If the implicit width change does not result in an actual width change,
132156
// this will not be called anywhere else.
@@ -135,7 +159,9 @@ void MarginWrapperManager::onChildImplicitWidthChanged() {
135159

136160
void MarginWrapperManager::onChildImplicitHeightChanged() {
137161
if (!this->mChild || !this->mWrapper) return;
138-
this->mWrapper->setImplicitHeight(this->mChild->implicitHeight() + this->mMargin * 2);
162+
this->mWrapper->setImplicitHeight(
163+
this->mChild->implicitHeight() + this->bTopMargin + this->bBottomMargin
164+
);
139165

140166
// If the implicit height change does not result in an actual height change,
141167
// this will not be called anywhere else.
@@ -146,15 +172,19 @@ void MarginWrapperManager::updateGeometry() {
146172
if (!this->mWrapper) return;
147173

148174
if (this->mChild) {
149-
this->mWrapper->setImplicitWidth(this->mChild->implicitWidth() + this->mMargin * 2);
150-
this->mWrapper->setImplicitHeight(this->mChild->implicitHeight() + this->mMargin * 2);
175+
this->mWrapper->setImplicitWidth(
176+
this->mChild->implicitWidth() + this->bLeftMargin + this->bRightMargin
177+
);
178+
this->mWrapper->setImplicitHeight(
179+
this->mChild->implicitHeight() + this->bTopMargin + this->bBottomMargin
180+
);
151181
this->mChild->setX(this->targetChildX());
152182
this->mChild->setY(this->targetChildY());
153183
this->mChild->setWidth(this->targetChildWidth());
154184
this->mChild->setHeight(this->targetChildHeight());
155185
} else {
156-
this->mWrapper->setImplicitWidth(this->mMargin * 2);
157-
this->mWrapper->setImplicitHeight(this->mMargin * 2);
186+
this->mWrapper->setImplicitWidth(this->bLeftMargin + this->bRightMargin);
187+
this->mWrapper->setImplicitHeight(this->bTopMargin + this->bBottomMargin);
158188
}
159189
}
160190

0 commit comments

Comments
 (0)