]> sigrok.org Git - pulseview.git/blob - pv/widgets/flowlayout.cpp
DecodeTrace: Add buttons to show/hide all classes in a row
[pulseview.git] / pv / widgets / flowlayout.cpp
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
105                 return nullptr;
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
144                 int h = item->geometry().y() + item->geometry().height();
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);
209                 return pw->style()->pixelMetric(pm, nullptr, pw);
210         } else
211                 return static_cast<QLayout*>(parent)->spacing();
212 }