1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include <QtWidgets>
52
53#include "flowlayout.h"
54//! [1]
55FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
56 : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
57{
58 setContentsMargins(margin, margin, margin, margin);
59}
60
61FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
62 : m_hSpace(hSpacing), m_vSpace(vSpacing)
63{
64 setContentsMargins(margin, margin, margin, margin);
65}
66//! [1]
67
68//! [2]
69FlowLayout::~FlowLayout()
70{
71 QLayoutItem *item;
72 while ((item = takeAt(0)))
73 delete item;
74}
75//! [2]
76
77//! [3]
78void FlowLayout::addItem(QLayoutItem *item)
79{
80 itemList.append(item);
81}
82//! [3]
83
84//! [4]
85int FlowLayout::horizontalSpacing() const
86{
87 if (m_hSpace >= 0) {
88 return m_hSpace;
89 } else {
90 return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
91 }
92}
93
94int FlowLayout::verticalSpacing() const
95{
96 if (m_vSpace >= 0) {
97 return m_vSpace;
98 } else {
99 return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
100 }
101}
102//! [4]
103
104//! [5]
105int FlowLayout::count() const
106{
107 return itemList.size();
108}
109
110QLayoutItem *FlowLayout::itemAt(int index) const
111{
112 return itemList.value(index);
113}
114
115QLayoutItem *FlowLayout::takeAt(int index)
116{
117 if (index >= 0 && index < itemList.size())
118 return itemList.takeAt(index);
119 return nullptr;
120}
121//! [5]
122
123//! [6]
124Qt::Orientations FlowLayout::expandingDirections() const
125{
126 return { };
127}
128//! [6]
129
130//! [7]
131bool FlowLayout::hasHeightForWidth() const
132{
133 return true;
134}
135
136int FlowLayout::heightForWidth(int width) const
137{
138 int height = doLayout(QRect(0, 0, width, 0), true);
139 return height;
140}
141//! [7]
142
143//! [8]
144void FlowLayout::setGeometry(const QRect &rect)
145{
146 QLayout::setGeometry(rect);
147 doLayout(rect, false);
148}
149
150QSize FlowLayout::sizeHint() const
151{
152 return minimumSize();
153}
154
155QSize FlowLayout::minimumSize() const
156{
157 QSize size;
158 for (const QLayoutItem *item : qAsConst(itemList))
159 size = size.expandedTo(item->minimumSize());
160
161 const QMargins margins = contentsMargins();
162 size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
163 return size;
164}
165//! [8]
166
167//! [9]
168int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
169{
170 int left, top, right, bottom;
171 getContentsMargins(&left, &top, &right, &bottom);
172 QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
173 int x = effectiveRect.x();
174 int y = effectiveRect.y();
175 int lineHeight = 0;
176//! [9]
177
178//! [10]
179 for (QLayoutItem *item : qAsConst(itemList)) {
180 const QWidget *wid = item->widget();
181 int spaceX = horizontalSpacing();
182 if (spaceX == -1)
183 spaceX = wid->style()->layoutSpacing(
184 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
185 int spaceY = verticalSpacing();
186 if (spaceY == -1)
187 spaceY = wid->style()->layoutSpacing(
188 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
189//! [10]
190//! [11]
191 int nextX = x + item->sizeHint().width() + spaceX;
192 if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
193 x = effectiveRect.x();
194 y = y + lineHeight + spaceY;
195 nextX = x + item->sizeHint().width() + spaceX;
196 lineHeight = 0;
197 }
198
199 if (!testOnly)
200 item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
201
202 x = nextX;
203 lineHeight = qMax(lineHeight, item->sizeHint().height());
204 }
205 return y + lineHeight - rect.y() + bottom;
206}
207//! [11]
208//! [12]
209int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
210{
211 QObject *parent = this->parent();
212 if (!parent) {
213 return -1;
214 } else if (parent->isWidgetType()) {
215 QWidget *pw = static_cast<QWidget *>(parent);
216 return pw->style()->pixelMetric(pm, nullptr, pw);
217 } else {
218 return static_cast<QLayout *>(parent)->spacing();
219 }
220}
221//! [12]
222