1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/qloggingcategory.h>
5#include <QtQuickLayouts/private/qquickflexboxlayoutitem_p.h>
6#include <yoga/YGNode.h>
7
8QT_BEGIN_NAMESPACE
9
10Q_LOGGING_CATEGORY(lcQuickFlexLayoutItem, "qt.quick.flexlayouts.item")
11
12static constexpr YGWrap QtToYGFlexboxWrap(QQuickFlexboxLayout::FlexboxWrap qtWrap) {
13 switch (qtWrap) {
14 case QQuickFlexboxLayout::NoWrap: return YGWrap::YGWrapNoWrap;
15 case QQuickFlexboxLayout::Wrap: return YGWrap::YGWrapWrap;
16 case QQuickFlexboxLayout::WrapReverse: return YGWrap::YGWrapWrapReverse;
17 default: {
18 qWarning(msg: "Not a valid wrap");
19 return YGWrap{};
20 }
21 }
22};
23
24static constexpr YGFlexDirection QtToYGFlexboxDirection(QQuickFlexboxLayout::FlexboxDirection qtDirection) {
25 switch (qtDirection) {
26 case QQuickFlexboxLayout::Column: return YGFlexDirection::YGFlexDirectionColumn;
27 case QQuickFlexboxLayout::ColumnReverse: return YGFlexDirection::YGFlexDirectionColumnReverse;
28 case QQuickFlexboxLayout::Row: return YGFlexDirection::YGFlexDirectionRow;
29 case QQuickFlexboxLayout::RowReverse: return YGFlexDirection::YGFlexDirectionRowReverse;
30 default: {
31 qWarning(msg: "Not a valid direction");
32 return YGFlexDirection{};
33 }
34 }
35};
36
37static constexpr YGAlign QtToYGFlexboxAlignment(QQuickFlexboxLayout::FlexboxAlignment qtAlignment) {
38 switch (qtAlignment) {
39 case QQuickFlexboxLayout::AlignAuto: return YGAlign::YGAlignAuto;
40 case QQuickFlexboxLayout::AlignStart: return YGAlign::YGAlignFlexStart;
41 case QQuickFlexboxLayout::AlignCenter: return YGAlign::YGAlignCenter;
42 case QQuickFlexboxLayout::AlignEnd: return YGAlign::YGAlignFlexEnd;
43 case QQuickFlexboxLayout::AlignStretch: return YGAlign::YGAlignStretch;
44 case QQuickFlexboxLayout::AlignBaseline: return YGAlign::YGAlignBaseline;
45 case QQuickFlexboxLayout::AlignSpaceBetween: return YGAlign::YGAlignSpaceBetween;
46 case QQuickFlexboxLayout::AlignSpaceAround: return YGAlign::YGAlignSpaceAround;
47 case QQuickFlexboxLayout::AlignSpaceEvenly: {
48 return YGAlign{};
49 }
50 default: {
51 qWarning(msg: "Not a valid alignment");
52 return YGAlign{};
53 }
54 }
55};
56
57static constexpr YGJustify QtToYGFlexboxJustify(QQuickFlexboxLayout::FlexboxJustify qtJustify) {
58 switch (qtJustify) {
59 case QQuickFlexboxLayout::JustifyStart: return YGJustify::YGJustifyFlexStart;
60 case QQuickFlexboxLayout::JustifyCenter: return YGJustify::YGJustifyCenter;
61 case QQuickFlexboxLayout::JustifyEnd: return YGJustify::YGJustifyFlexEnd;
62 case QQuickFlexboxLayout::JustifySpaceBetween: return YGJustify::YGJustifySpaceBetween;
63 case QQuickFlexboxLayout::JustifySpaceAround: return YGJustify::YGJustifySpaceAround;
64 case QQuickFlexboxLayout::JustifySpaceEvenly: return YGJustify::YGJustifySpaceEvenly;
65 default: {
66 qWarning(msg: "Not a valid justify");
67 return YGJustify{};
68 }
69 }
70};
71
72static constexpr YGEdge QtToYGFlexboxEdge(QQuickFlexboxLayout::FlexboxEdge qtEdge) {
73 switch (qtEdge) {
74 case QQuickFlexboxLayout::EdgeLeft: return YGEdge::YGEdgeLeft;
75 case QQuickFlexboxLayout::EdgeRight: return YGEdge::YGEdgeRight;
76 case QQuickFlexboxLayout::EdgeTop: return YGEdge::YGEdgeTop;
77 case QQuickFlexboxLayout::EdgeBottom: return YGEdge::YGEdgeBottom;
78 case QQuickFlexboxLayout::EdgeAll: return YGEdge::YGEdgeAll;
79 default: {
80 qWarning(msg: "Not a valid edge");
81 return YGEdge{};
82 }
83 }
84};
85
86static constexpr YGGutter QtToYGFlexboxGap(QQuickFlexboxLayout::FlexboxGap qtGap) {
87 switch (qtGap) {
88 case QQuickFlexboxLayout::GapRow: return YGGutter::YGGutterRow;
89 case QQuickFlexboxLayout::GapColumn: return YGGutter::YGGutterColumn;
90 case QQuickFlexboxLayout::GapAll: return YGGutter::YGGutterAll;
91 default: {
92 qWarning(msg: "Not a valid gap");
93 return YGGutter{};
94 }
95 }
96};
97
98QQuickFlexboxLayoutItem::QQuickFlexboxLayoutItem(QQuickItem *item)
99 : m_item(item)
100{
101 Q_ASSERT(m_item != nullptr);
102 m_yogaNode = YGNodeNew();
103 resetDefault();
104}
105
106QQuickFlexboxLayoutItem::~QQuickFlexboxLayoutItem()
107{
108 YGNodeFree(node: m_yogaNode);
109}
110
111void QQuickFlexboxLayoutItem::setMinSize(const QSizeF &size)
112{
113 YGNodeStyleSetMinWidth(node: m_yogaNode, minWidth: static_cast<float>(size.width()));
114 YGNodeStyleSetMinHeight(node: m_yogaNode, minHeight: static_cast<float>(size.height()));
115}
116
117void QQuickFlexboxLayoutItem::setSize(const QSizeF &size)
118{
119 YGNodeStyleSetWidth(node: m_yogaNode, width: static_cast<float>(size.width()));
120 YGNodeStyleSetHeight(node: m_yogaNode, height: static_cast<float>(size.height()));
121}
122
123void QQuickFlexboxLayoutItem::setWidth(const qreal &width)
124{
125 YGNodeStyleSetWidth(node: m_yogaNode, width: static_cast<float>(width));
126}
127
128void QQuickFlexboxLayoutItem::setHeight(const qreal &height)
129{
130 YGNodeStyleSetHeight(node: m_yogaNode, height: static_cast<float>(height));
131}
132
133void QQuickFlexboxLayoutItem::setMaxSize(const QSizeF &size)
134{
135 YGNodeStyleSetMaxWidth(node: m_yogaNode, maxWidth: static_cast<float>(size.width()));
136 YGNodeStyleSetMaxHeight(node: m_yogaNode, maxHeight: static_cast<float>(size.height()));
137}
138
139void QQuickFlexboxLayoutItem::setFlexBasis(const qreal value, bool reset)
140{
141 YGNodeStyleSetFlexBasis(node: m_yogaNode, flexBasis: reset ? qQNaN() : value);
142}
143
144bool QQuickFlexboxLayoutItem::isFlexBasisUndefined() const
145{
146 float value = YGNodeStyleGetFlexBasis(node: m_yogaNode).value;
147 return (value == YGUndefined || qt_is_nan(f: value));
148}
149
150void QQuickFlexboxLayoutItem::setItemGrowAlongMainAxis(const qreal value)
151{
152 YGNodeStyleSetFlexGrow(node: m_yogaNode, flexGrow: value);
153}
154
155void QQuickFlexboxLayoutItem::setItemShrinkAlongMainAxis(const qreal value)
156{
157 YGNodeStyleSetFlexShrink(node: m_yogaNode, flexShrink: value);
158}
159
160void QQuickFlexboxLayoutItem::setItemStretchAlongCrossSection()
161{
162 YGNodeStyleSetAlignSelf(node: m_yogaNode, alignSelf: YGAlignStretch);
163}
164
165void QQuickFlexboxLayoutItem::setFlexDirection(QQuickFlexboxLayout::FlexboxDirection direction)
166{
167 YGNodeStyleSetFlexDirection(node: m_yogaNode, flexDirection: QtToYGFlexboxDirection(qtDirection: direction));
168}
169
170void QQuickFlexboxLayoutItem::setFlexWrap(QQuickFlexboxLayout::FlexboxWrap wrap)
171{
172 YGNodeStyleSetFlexWrap(node: m_yogaNode, flexWrap: QtToYGFlexboxWrap(qtWrap: wrap));
173}
174
175void QQuickFlexboxLayoutItem::setFlexAlignItemsProperty(QQuickFlexboxLayout::FlexboxAlignment align)
176{
177 YGNodeStyleSetAlignItems(node: m_yogaNode, alignItems: QtToYGFlexboxAlignment(qtAlignment: align));
178}
179
180void QQuickFlexboxLayoutItem::setFlexAlignContentProperty(QQuickFlexboxLayout::FlexboxAlignment align)
181{
182 YGNodeStyleSetAlignContent(node: m_yogaNode, alignContent: QtToYGFlexboxAlignment(qtAlignment: align));
183}
184
185void QQuickFlexboxLayoutItem::setFlexJustifyContentProperty(QQuickFlexboxLayout::FlexboxJustify justify)
186{
187 YGNodeStyleSetJustifyContent(node: m_yogaNode, justifyContent: QtToYGFlexboxJustify(qtJustify: justify));
188}
189
190void QQuickFlexboxLayoutItem::setFlexAlignSelfProperty(QQuickFlexboxLayout::FlexboxAlignment align)
191{
192 YGNodeStyleSetAlignSelf(node: m_yogaNode, alignSelf: QtToYGFlexboxAlignment(qtAlignment: align));
193}
194
195void QQuickFlexboxLayoutItem::setFlexMargin(QQuickFlexboxLayout::FlexboxEdge edge, const qreal value)
196{
197 YGNodeStyleSetMargin(node: m_yogaNode, edge: QtToYGFlexboxEdge(qtEdge: edge), margin: value);
198}
199
200void QQuickFlexboxLayoutItem::setFlexPadding(QQuickFlexboxLayout::FlexboxEdge edge, const qreal value)
201{
202 YGNodeStyleSetPadding(node: m_yogaNode, edge: QtToYGFlexboxEdge(qtEdge: edge), padding: value);
203}
204
205void QQuickFlexboxLayoutItem::setFlexGap(QQuickFlexboxLayout::FlexboxGap gap, const qreal value)
206{
207 YGNodeStyleSetGap(node: m_yogaNode, gutter: QtToYGFlexboxGap(qtGap: gap), gapLength: value);
208}
209
210bool QQuickFlexboxLayoutItem::isItemStreched() const
211{
212 return ((YGNodeStyleGetAlignSelf(node: m_yogaNode) == YGAlignStretch) ||
213 ((YGNodeStyleGetAlignSelf(node: m_yogaNode) == YGAlignAuto) &&
214 (YGNodeStyleGetAlignItems(node: m_yogaNode->getParent()) == YGAlignStretch)));
215}
216
217void QQuickFlexboxLayoutItem::inheritItemStretchAlongCrossSection()
218{
219 YGNodeStyleSetAlignSelf(node: m_yogaNode, alignSelf: YGAlignAuto);
220}
221
222void QQuickFlexboxLayoutItem::resetMargins()
223{
224 YGNodeStyleSetMargin(node: m_yogaNode, edge: YGEdgeLeft, margin: 0);
225 YGNodeStyleSetMargin(node: m_yogaNode, edge: YGEdgeTop, margin: 0);
226 YGNodeStyleSetMargin(node: m_yogaNode, edge: YGEdgeRight, margin: 0);
227 YGNodeStyleSetMargin(node: m_yogaNode, edge: YGEdgeBottom, margin: 0);
228}
229
230void QQuickFlexboxLayoutItem::resetPaddings()
231{
232 YGNodeStyleSetPadding(node: m_yogaNode, edge: YGEdgeAll, padding: 0);
233}
234
235void QQuickFlexboxLayoutItem::resetSize()
236{
237 YGNodeStyleSetWidth(node: m_yogaNode, width: YGUndefined);
238 YGNodeStyleSetHeight(node: m_yogaNode, height: YGUndefined);
239}
240
241QPoint QQuickFlexboxLayoutItem::position() const
242{
243 return QPoint(YGNodeLayoutGetLeft(node: m_yogaNode), YGNodeLayoutGetTop(node: m_yogaNode));
244}
245
246QSizeF QQuickFlexboxLayoutItem::size() const
247{
248 return QSizeF(YGNodeLayoutGetWidth(node: m_yogaNode), YGNodeLayoutGetHeight(node: m_yogaNode));
249}
250
251void QQuickFlexboxLayoutItem::insertChild(QQuickFlexboxLayoutItem *child, int index)
252{
253 YGNodeInsertChild(node: m_yogaNode, child: child->yogaItem(), index);
254 // TODO: We may need this only for the text node?
255 // YGNodeSetMeasureFunc(m_yogaNode, &QQuickFlexboxLayoutItem::measureFunc);
256}
257
258void QQuickFlexboxLayoutItem::resetDefault()
259{
260 // Context object is required here for callback functionality
261 // For instance, the measurement function would be called to determine the
262 // layout size
263 YGNodeSetContext(node: m_yogaNode, context: this);
264 resetMargins();
265 resetPaddings();
266 YGNodeStyleSetFlexBasis(node: m_yogaNode, flexBasis: YGUndefined);
267}
268
269bool QQuickFlexboxLayoutItem::hasMeasureFunc() const
270{
271 return YGNodeHasMeasureFunc(node: m_yogaNode);
272}
273
274void QQuickFlexboxLayoutItem::resetMeasureFunc()
275{
276 YGNodeSetMeasureFunc(node: m_yogaNode, measureFunc: nullptr);
277}
278
279SizeHints &QQuickFlexboxLayoutItem::cachedItemSizeHints() const
280{
281 return m_cachedSizeHint;
282}
283
284void QQuickFlexboxLayoutItem::computeLayout(const QSizeF &size)
285{
286 // Consider either NaN or Inf as YGUndefined
287 const float width = (qt_is_nan(d: size.width()) || qt_is_inf(d: size.width()) ||
288 !size.width()) ? YGUndefined : size.width();
289 const float height = (qt_is_nan(d: size.height()) || qt_is_inf(d: size.height()) ||
290 !size.height()) ? YGUndefined : size.height();
291 YGNodeCalculateLayout(node: m_yogaNode, availableWidth: width, availableHeight: height, ownerDirection: YGDirectionLTR);
292}
293
294QT_END_NAMESPACE
295

source code of qtdeclarative/src/quicklayouts/qquickflexboxlayoutitem.cpp