Baloo Widgets

kblocklayout.cpp
1 /*
2  SPDX-FileCopyrightText: 2006-2007 Sebastian Trueg <[email protected]>
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) <[email protected]>
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 
17 class KBlockLayout::Private
18 {
19 public:
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 
48 KBlockLayout::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 
57 KBlockLayout::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 
65 KBlockLayout::~KBlockLayout()
66 {
67  QLayoutItem *item;
68  while ((item = takeAt(0)))
69  delete item;
70  delete d;
71 }
72 
74 {
75  d->alignment = a;
76 }
77 
78 Qt::Alignment KBlockLayout::alignment() const
79 {
80  return d->alignment;
81 }
82 
83 int KBlockLayout::horizontalSpacing() const
84 {
85  if (d->m_hSpace >= 0) {
86  return d->m_hSpace;
87  } else {
88  return d->smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
89  }
90 }
91 
92 int KBlockLayout::verticalSpacing() const
93 {
94  if (d->m_vSpace >= 0) {
95  return d->m_vSpace;
96  } else {
97  return d->smartSpacing(QStyle::PM_LayoutVerticalSpacing);
98  }
99 }
100 
101 void KBlockLayout::setSpacing(int h, int v)
102 {
103  d->m_hSpace = h;
104  d->m_vSpace = v;
106 }
107 
108 void KBlockLayout::addItem(QLayoutItem *item)
109 {
110  d->itemList.append(item);
111 }
112 
113 int KBlockLayout::count() const
114 {
115  return d->itemList.size();
116 }
117 
118 QLayoutItem *KBlockLayout::itemAt(int index) const
119 {
120  return d->itemList.value(index);
121 }
122 
123 QLayoutItem *KBlockLayout::takeAt(int index)
124 {
125  if (index >= 0 && index < d->itemList.size())
126  return d->itemList.takeAt(index);
127  else
128  return nullptr;
129 }
130 
131 Qt::Orientations KBlockLayout::expandingDirections() const
132 {
133  return {};
134 }
135 
136 bool KBlockLayout::hasHeightForWidth() const
137 {
138  return true;
139 }
140 
141 int KBlockLayout::heightForWidth(int width) const
142 {
143  int height = doLayout(QRect(0, 0, width, 0), true);
144  return height;
145 }
146 
147 void KBlockLayout::setGeometry(const QRect &rect)
148 {
149  QLayout::setGeometry(rect);
150  doLayout(rect, false);
151 }
152 
153 int KBlockLayout::getMargin() const
154 {
155  int left, top, right, bottom;
156  getContentsMargins(&left, &top, &right, &bottom);
157  if (left == top && top == right && right == bottom) {
158  return left;
159  } else {
160  return -1;
161  }
162 }
163 
164 QSize KBlockLayout::sizeHint() const
165 {
166  // TODO: try to get the items into a square
167  QSize size;
168  for (QLayoutItem *item : std::as_const(d->itemList)) {
169  const QSize itemSize = item->minimumSize();
170  size.rwidth() += itemSize.width();
171  if (itemSize.height() > size.height()) {
172  size.setHeight(itemSize.height());
173  }
174  }
175 
176  size.rwidth() += horizontalSpacing() * d->itemList.count();
177  size += QSize(2 * getMargin(), 2 * getMargin());
178  return size;
179 }
180 
181 QSize KBlockLayout::minimumSize() const
182 {
183  QSize size;
184  for (QLayoutItem *item : std::as_const(d->itemList)) {
185  size = size.expandedTo(item->minimumSize());
186  }
187 
188  size += QSize(2 * getMargin(), 2 * getMargin());
189  return size;
190 }
191 
192 struct Row {
193  Row(const QList<QLayoutItem *> &i, int h, int w)
194  : items(i)
195  , height(h)
196  , width(w)
197  {
198  }
199 
200  QList<QLayoutItem *> items;
201  int height;
202  int width;
203 };
204 
205 int KBlockLayout::doLayout(const QRect &rect, bool testOnly) const
206 {
207  int x = rect.x();
208  int y = rect.y();
209  int lineHeight = 0;
210 
211  // 1. calculate lines
212  QList<Row> rows;
213  QList<QLayoutItem *> rowItems;
214  for (int i = 0; i < d->itemList.count(); ++i) {
215  QLayoutItem *item = d->itemList[i];
216  int nextX = x + item->sizeHint().width() + horizontalSpacing();
217  if (nextX - horizontalSpacing() > rect.right() && lineHeight > 0) {
218  rows.append(Row(rowItems, lineHeight, x - horizontalSpacing()));
219  rowItems.clear();
220 
221  x = rect.x();
222  y = y + lineHeight + verticalSpacing();
223  nextX = x + item->sizeHint().width() + horizontalSpacing();
224  lineHeight = 0;
225  }
226 
227  rowItems.append(item);
228 
229  x = nextX;
230  lineHeight = qMax(lineHeight, item->sizeHint().height());
231  }
232  // append the last row
233  rows.append(Row(rowItems, lineHeight, x - horizontalSpacing()));
234 
235  int finalHeight = y + lineHeight - rect.y();
236  if (testOnly)
237  return finalHeight;
238 
239  // 2. place the items
240  y = rect.y();
241  for (const Row &row : std::as_const(rows)) {
242  x = rect.x();
243  if (alignment() & Qt::AlignRight)
244  x += (rect.width() - row.width);
245  else if (alignment() & Qt::AlignHCenter)
246  x += (rect.width() - row.width) / 2;
247 
248  for (QLayoutItem *item : std::as_const(row.items)) {
249  int yy = y;
250  if (alignment() & Qt::AlignBottom)
251  yy += (row.height - item->sizeHint().height());
252  else if (alignment() & Qt::AlignVCenter)
253  yy += (row.height - item->sizeHint().height()) / 2;
254  item->setGeometry(QRect(QPoint(x, yy), item->sizeHint()));
255 
256  x += item->sizeHint().width() + horizontalSpacing();
257 
258  if (alignment() & Qt::AlignJustify)
259  x += (rect.width() - row.width) / qMax(row.items.count() - 1, 1);
260  }
261 
262  y = y + row.height + verticalSpacing();
263  }
264 
265  return finalHeight;
266 }
void append(const T &value)
AlignLeft
QTextStream & right(QTextStream &stream)
virtual void setGeometry(const QRect &r) override
int right() const const
QTextStream & left(QTextStream &stream)
int width() const const
int x() const const
int y() const const
int width() const const
virtual void setGeometry(const QRect &r)=0
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
QStyle * style() const const
int height() const const
typedef Orientations
void setAlignment(Qt::Alignment)
Set the alignment to use.
int & rwidth()
QSize expandedTo(const QSize &otherSize) const const
bool isWidgetType() const const
The KBlockLayout arranges widget in rows and columns like a text editor does.
Definition: kblocklayout.h:20
void clear()
virtual QSize minimumSize() const const=0
virtual QSize sizeHint() const const=0
QObject * parent() const const
void setHeight(int height)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 04:10:01 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.