1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the examples of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial Usage
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
35 **
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "FlowLayout.h"
43
FlowLayout(QWidget * parent,int margin,int hSpacing,int vSpacing)44 FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
45 : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
46 {
47 setContentsMargins(margin, margin, margin, margin);
48 }
49
FlowLayout(int margin,int hSpacing,int vSpacing)50 FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
51 : m_hSpace(hSpacing), m_vSpace(vSpacing)
52 {
53 setContentsMargins(margin, margin, margin, margin);
54 }
55
~FlowLayout()56 FlowLayout::~FlowLayout(){
57 QLayoutItem *item;
58 while ((item = takeAt(0)))
59 delete item;
60 }
61
addItem(QLayoutItem * item)62 void FlowLayout::addItem(QLayoutItem *item){
63 itemList.append(item);
64 }
65
horizontalSpacing() const66 int FlowLayout::horizontalSpacing() const {
67 if (m_hSpace >= 0) {
68 return m_hSpace;
69 } else {
70 return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
71 }
72 }
73
verticalSpacing() const74 int FlowLayout::verticalSpacing() const {
75 if (m_vSpace >= 0) {
76 return m_vSpace;
77 } else {
78 return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
79 }
80 }
81
count() const82 int FlowLayout::count() const {
83 return itemList.size();
84 }
85
itemAt(int index) const86 QLayoutItem *FlowLayout::itemAt(int index) const {
87 return itemList.value(index);
88 }
89
takeAt(int index)90 QLayoutItem *FlowLayout::takeAt(int index){
91 if (index >= 0 && index < itemList.size())
92 return itemList.takeAt(index);
93 else
94 return 0;
95 }
96
expandingDirections() const97 Qt::Orientations FlowLayout::expandingDirections() const {
98 return 0;
99 }
100
hasHeightForWidth() const101 bool FlowLayout::hasHeightForWidth() const {
102 return true;
103 }
104
heightForWidth(int width) const105 int FlowLayout::heightForWidth(int width) const {
106 int height = doLayout(QRect(0, 0, width, 0), true);
107 return height;
108 }
109
setGeometry(const QRect & rect)110 void FlowLayout::setGeometry(const QRect &rect) {
111 QLayout::setGeometry(rect);
112 doLayout(rect, false);
113 }
114
sizeHint() const115 QSize FlowLayout::sizeHint() const {
116 return minimumSize();
117 }
118
moveLeft(QLayoutItem * item)119 bool FlowLayout::moveLeft(QLayoutItem *item){
120 const int index = itemList.indexOf(item);
121
122 if (index <= 0)
123 return false;
124
125 itemList.takeAt(index);
126 itemList.insert(index-1, item);
127
128 doLayout(geometry(), false);
129
130 return true;
131 }
132
moveRight(QLayoutItem * item)133 bool FlowLayout::moveRight(QLayoutItem *item){
134 const int index = itemList.indexOf(item);
135
136 if ((index < 0) || (index >= itemList.count()-1))
137 return false;
138
139 itemList.takeAt(index);
140 itemList.insert(index+1, item);
141
142 doLayout(geometry(), false);
143
144 return true;
145 }
146
minimumSize() const147 QSize FlowLayout::minimumSize() const {
148 QSize size;
149 for (const auto &item : itemList)
150 size = size.expandedTo(item->minimumSize());
151
152 size += QSize(2*margin(), 2*margin());
153 return size;
154 }
155
place(QWidget * on,QWidget * what)156 void FlowLayout::place(QWidget *on, QWidget *what){
157 if (!(on && what))
158 return;
159
160 QLayoutItem *i_on = NULL;
161 QLayoutItem *i_what = NULL;
162
163 for (const auto &item : itemList) {
164 if (item->widget() == on)
165 i_on = item;
166 else if (item->widget() == what)
167 i_what = item;
168
169 if (i_on && i_what)
170 break;
171 }
172
173 if (!(i_on && i_what))
174 return;
175
176 int index_on = itemList.indexOf(i_on);
177 int index_what = itemList.indexOf(i_what);
178
179 itemList.takeAt(index_what);
180 itemList.insert(index_on, i_what);
181
182 doLayout(geometry(), false);
183 }
184
doLayout(const QRect & rect,bool testOnly) const185 int FlowLayout::doLayout(const QRect &rect, bool testOnly) const {
186 int left, top, right, bottom;
187 getContentsMargins(&left, &top, &right, &bottom);
188 QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
189 int x = effectiveRect.x();
190 int y = effectiveRect.y();
191 int lineHeight = 0;
192
193 for (const auto &item : itemList) {
194 QWidget *wid = item->widget();
195 int spaceX = horizontalSpacing();
196 if (spaceX == -1)
197 spaceX = wid->style()->layoutSpacing(
198 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
199 int spaceY = verticalSpacing();
200 if (spaceY == -1)
201 spaceY = wid->style()->layoutSpacing(
202 QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
203
204 int nextX = x + item->sizeHint().width() + spaceX;
205 if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
206 x = effectiveRect.x();
207 y = y + lineHeight + spaceY;
208 nextX = x + item->sizeHint().width() + spaceX;
209 lineHeight = 0;
210 }
211
212 if (!testOnly)
213 item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
214
215 x = nextX;
216 lineHeight = qMax(lineHeight, item->sizeHint().height());
217 }
218 return y + lineHeight - rect.y() + bottom;
219 }
220
smartSpacing(QStyle::PixelMetric pm) const221 int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const {
222 QObject *parent = this->parent();
223 if (!parent) {
224 return -1;
225 } else if (parent->isWidgetType()) {
226 QWidget *pw = static_cast<QWidget *>(parent);
227 return pw->style()->pixelMetric(pm, 0, pw);
228 } else {
229 return static_cast<QLayout *>(parent)->spacing();
230 }
231 }
232
233