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