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