Baloo Widgets

kblocklayout.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2007 Sebastian Trueg <trueg@kde.org>
3
4 KBlockLayout is based on the FlowLayout example from QT4.
5 SPDX-FileCopyrightText: 2004-2006 Trolltech ASA
6 SPDX-FileCopyrightText: 2010 Nokia Corporation and /or its subsidiary(-ies) <qt-info@nokia.com>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#include "kblocklayout.h"
12
13#include <QList>
14#include <QStyle>
15#include <QWidget>
16
17class KBlockLayout::Private
18{
19public:
20 Private()
21 : alignment(Qt::AlignLeft | Qt::AlignTop)
22 {
23 }
24
25 int smartSpacing(QStyle::PixelMetric pm) const
26 {
27 QObject *parent = q->parent();
28 if (!parent) {
29 return -1;
30 } else if (parent->isWidgetType()) {
31 auto pw = static_cast<QWidget *>(parent);
32 return pw->style()->pixelMetric(pm, nullptr, pw);
33 } else {
34 return static_cast<QLayout *>(parent)->spacing();
35 }
36 }
37
38 QList<QLayoutItem *> itemList;
39
40 int m_hSpace;
41 int m_vSpace;
42
43 Qt::Alignment alignment;
44
45 KBlockLayout *q = nullptr;
46};
47
48KBlockLayout::KBlockLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
49 : QLayout(parent)
50 , d(new Private())
51{
52 d->q = this;
53 setContentsMargins(margin, margin, margin, margin);
54 setSpacing(hSpacing, vSpacing);
55}
56
57KBlockLayout::KBlockLayout(int margin, int hSpacing, int vSpacing)
58 : d(new Private())
59{
60 d->q = this;
61 setContentsMargins(margin, margin, margin, margin);
62 setSpacing(hSpacing, vSpacing);
63}
64
65KBlockLayout::~KBlockLayout()
66{
67 QLayoutItem *item;
68 while ((item = takeAt(0)))
69 delete item;
70 delete d;
71}
72
74{
75 d->alignment = a;
77}
78
79Qt::Alignment KBlockLayout::alignment() const
80{
81 return d->alignment;
82}
83
84int KBlockLayout::horizontalSpacing() const
85{
86 if (d->m_hSpace >= 0) {
87 return d->m_hSpace;
88 } else {
89 return d->smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
90 }
91}
92
93int KBlockLayout::verticalSpacing() const
94{
95 if (d->m_vSpace >= 0) {
96 return d->m_vSpace;
97 } else {
98 return d->smartSpacing(QStyle::PM_LayoutVerticalSpacing);
99 }
100}
101
102void KBlockLayout::setSpacing(int h, int v)
103{
104 d->m_hSpace = h;
105 d->m_vSpace = v;
107}
108
109void KBlockLayout::addItem(QLayoutItem *item)
110{
111 d->itemList.append(item);
112}
113
114int KBlockLayout::count() const
115{
116 return d->itemList.size();
117}
118
119QLayoutItem *KBlockLayout::itemAt(int index) const
120{
121 return d->itemList.value(index);
122}
123
124QLayoutItem *KBlockLayout::takeAt(int index)
125{
126 if (index >= 0 && index < d->itemList.size())
127 return d->itemList.takeAt(index);
128 else
129 return nullptr;
130}
131
132Qt::Orientations KBlockLayout::expandingDirections() const
133{
134 return {};
135}
136
137bool KBlockLayout::hasHeightForWidth() const
138{
139 return true;
140}
141
142int KBlockLayout::heightForWidth(int width) const
143{
144 int height = doLayout(QRect(0, 0, width, 0), true);
145 return height;
146}
147
148void KBlockLayout::setGeometry(const QRect &rect)
149{
151 doLayout(rect, false);
152}
153
154int KBlockLayout::getMargin() const
155{
156 int left, top, right, bottom;
157 getContentsMargins(&left, &top, &right, &bottom);
158 if (left == top && top == right && right == bottom) {
159 return left;
160 } else {
161 return -1;
162 }
163}
164
165QSize KBlockLayout::sizeHint() const
166{
167 // TODO: try to get the items into a square
168 QSize size;
169 for (QLayoutItem *item : std::as_const(d->itemList)) {
170 const QSize itemSize = item->minimumSize();
171 size.rwidth() += itemSize.width();
172 if (itemSize.height() > size.height()) {
173 size.setHeight(itemSize.height());
174 }
175 }
176
177 size.rwidth() += horizontalSpacing() * d->itemList.count();
178 size += QSize(2 * getMargin(), 2 * getMargin());
179 return size;
180}
181
182QSize KBlockLayout::minimumSize() const
183{
184 QSize size;
185 for (QLayoutItem *item : std::as_const(d->itemList)) {
186 size = size.expandedTo(item->minimumSize());
187 }
188
189 size += QSize(2 * getMargin(), 2 * getMargin());
190 return size;
191}
192
193struct Row {
194 Row(const QList<QLayoutItem *> &i, int h, int w)
195 : items(i)
196 , height(h)
197 , width(w)
198 {
199 }
200
202 int height;
203 int width;
204};
205
206int KBlockLayout::doLayout(const QRect &rect, bool testOnly) const
207{
208 int x = rect.x();
209 int y = rect.y();
210 int lineHeight = 0;
211
212 // 1. calculate lines
213 QList<Row> rows;
214 QList<QLayoutItem *> rowItems;
215 for (int i = 0; i < d->itemList.count(); ++i) {
216 QLayoutItem *item = d->itemList[i];
217 int nextX = x + item->sizeHint().width() + horizontalSpacing();
218 if (nextX - horizontalSpacing() > rect.right() && lineHeight > 0) {
219 rows.append(Row(rowItems, lineHeight, x - horizontalSpacing()));
220 rowItems.clear();
221
222 x = rect.x();
223 y = y + lineHeight + verticalSpacing();
224 nextX = x + item->sizeHint().width() + horizontalSpacing();
225 lineHeight = 0;
226 }
227
228 rowItems.append(item);
229
230 x = nextX;
231 lineHeight = qMax(lineHeight, item->sizeHint().height());
232 }
233 // append the last row
234 rows.append(Row(rowItems, lineHeight, x - horizontalSpacing()));
235
236 int finalHeight = y + lineHeight - rect.y();
237 if (testOnly)
238 return finalHeight;
239
240 // 2. place the items
241 y = rect.y();
242 for (const Row &row : std::as_const(rows)) {
243 x = rect.x();
244 if (alignment() & Qt::AlignRight)
245 x += (rect.width() - row.width);
246 else if (alignment() & Qt::AlignHCenter)
247 x += (rect.width() - row.width) / 2;
248
249 for (QLayoutItem *item : std::as_const(row.items)) {
250 int yy = y;
251 if (alignment() & Qt::AlignBottom)
252 yy += (row.height - item->sizeHint().height());
253 else if (alignment() & Qt::AlignVCenter)
254 yy += (row.height - item->sizeHint().height()) / 2;
255 item->setGeometry(QRect(QPoint(x, yy), item->sizeHint()));
256
257 x += item->sizeHint().width() + horizontalSpacing();
258
259 if (alignment() & Qt::AlignJustify)
260 x += (rect.width() - row.width) / qMax(row.items.count() - 1, 1);
261 }
262
263 y = y + row.height + verticalSpacing();
264 }
265
266 return finalHeight;
267}
The KBlockLayout arranges widget in rows and columns like a text editor does.
void setAlignment(Qt::Alignment)
Set the alignment to use.
void getContentsMargins(int *left, int *top, int *right, int *bottom) const const
virtual void setGeometry(const QRect &r) override
void update()
virtual QSize minimumSize() const const=0
virtual void setGeometry(const QRect &r)=0
virtual QSize sizeHint() const const=0
void append(QList< T > &&value)
void clear()
qsizetype count() const const
qsizetype size() const const
T takeAt(qsizetype i)
T value(qsizetype i) const const
bool isWidgetType() const const
QObject * parent() const const
int right() const const
int width() const const
int x() const const
int y() const const
QSize expandedTo(const QSize &otherSize) const const
int height() const const
int & rwidth()
void setHeight(int height)
int width() const const
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
AlignLeft
typedef Orientations
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 24 2024 12:00:13 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.