Baloo Widgets

kblocklayout.cpp
1 /*
2  * This file is part of the Baloo KDE project.
3  * Copyright (C) 2006-2007 Sebastian Trueg <[email protected]>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /*
22  KBlockLayout is based on the FlowLayout example from QT4.
23  Copyright (C) 2004-2006 Trolltech ASA. All rights reserved.
24  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
25  All rights reserved.
26  Contact: Nokia Corporation ([email protected])
27 */
28 
29 #include "kblocklayout.h"
30 
31 #include <QList>
32 #include <QStyle>
33 #include <QWidget>
34 
35 class KBlockLayout::Private
36 {
37 public:
38  Private()
39  : alignment(Qt::AlignLeft|Qt::AlignTop) {
40  }
41 
42  int smartSpacing(QStyle::PixelMetric pm) const
43  {
44  QObject *parent = q->parent();
45  if (!parent) {
46  return -1;
47  } else if (parent->isWidgetType()) {
48  QWidget *pw = static_cast<QWidget *>(parent);
49  return pw->style()->pixelMetric(pm, nullptr, pw);
50  } else {
51  return static_cast<QLayout *>(parent)->spacing();
52  }
53  }
54 
55  QList<QLayoutItem*> itemList;
56 
57  int m_hSpace;
58  int m_vSpace;
59 
60  Qt::Alignment alignment;
61 
62  KBlockLayout* q;
63 };
64 
65 
66 KBlockLayout::KBlockLayout( QWidget* parent, int margin, int hSpacing, int vSpacing )
67  : QLayout(parent),
68  d( new Private() )
69 {
70  d->q = this;
71  setContentsMargins(margin, margin, margin, margin);
72  setSpacing(hSpacing, vSpacing);
73 }
74 
75 KBlockLayout::KBlockLayout( int margin, int hSpacing, int vSpacing )
76  : d( new Private() )
77 {
78  d->q = this;
79  setContentsMargins(margin, margin, margin, margin);
80  setSpacing(hSpacing, vSpacing);
81 }
82 
83 KBlockLayout::~KBlockLayout()
84 {
85  QLayoutItem* item;
86  while ((item = takeAt(0)))
87  delete item;
88  delete d;
89 }
90 
92 {
93  d->alignment = a;
94 }
95 
96 Qt::Alignment KBlockLayout::alignment() const
97 {
98  return d->alignment;
99 }
100 
101 int KBlockLayout::horizontalSpacing() const
102 {
103  if (d->m_hSpace >= 0) {
104  return d->m_hSpace;
105  } else {
106  return d->smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
107  }
108 }
109 
110 int KBlockLayout::verticalSpacing() const
111 {
112  if (d->m_vSpace >= 0) {
113  return d->m_vSpace;
114  } else {
115  return d->smartSpacing(QStyle::PM_LayoutVerticalSpacing);
116  }
117 }
118 
119 void KBlockLayout::setSpacing( int h, int v )
120 {
121  d->m_hSpace = h;
122  d->m_vSpace = v;
123  QLayout::setSpacing( h );
124 }
125 
126 void KBlockLayout::addItem( QLayoutItem* item )
127 {
128  d->itemList.append(item);
129 }
130 
131 int KBlockLayout::count() const
132 {
133  return d->itemList.size();
134 }
135 
136 QLayoutItem *KBlockLayout::itemAt( int index ) const
137 {
138  return d->itemList.value(index);
139 }
140 
141 QLayoutItem *KBlockLayout::takeAt( int index )
142 {
143  if (index >= 0 && index < d->itemList.size())
144  return d->itemList.takeAt(index);
145  else
146  return nullptr;
147 }
148 
149 Qt::Orientations KBlockLayout::expandingDirections() const
150 {
151  return {};
152 }
153 
154 bool KBlockLayout::hasHeightForWidth() const
155 {
156  return true;
157 }
158 
159 int KBlockLayout::heightForWidth( int width ) const
160 {
161  int height = doLayout(QRect(0, 0, width, 0), true);
162  return height;
163 }
164 
165 void KBlockLayout::setGeometry( const QRect& rect )
166 {
167  QLayout::setGeometry(rect);
168  doLayout(rect, false);
169 }
170 
171 QSize KBlockLayout::sizeHint() const
172 {
173  // TODO: try to get the items into a square
174  QSize size;
175  for (QLayoutItem* item : qAsConst(d->itemList)) {
176  const QSize itemSize = item->minimumSize();
177  size.rwidth() += itemSize.width();
178  if (itemSize.height() > size.height()) {
179  size.setHeight(itemSize.height());
180  }
181  }
182 
183  size.rwidth() += horizontalSpacing() * d->itemList.count();
184  size += QSize(2*margin(), 2*margin());
185  return size;
186 }
187 
188 QSize KBlockLayout::minimumSize() const
189 {
190  QSize size;
191  for (QLayoutItem* item : qAsConst(d->itemList)) {
192  size = size.expandedTo(item->minimumSize());
193  }
194 
195  size += QSize(2*margin(), 2*margin());
196  return size;
197 }
198 
199 struct Row {
200  Row( const QList<QLayoutItem*>& i, int h, int w )
201  : items(i), height(h), width(w) {
202  }
203 
204  QList<QLayoutItem*> items;
205  int height;
206  int width;
207 };
208 
209 int KBlockLayout::doLayout( const QRect& rect, bool testOnly ) const
210 {
211  int x = rect.x();
212  int y = rect.y();
213  int lineHeight = 0;
214 
215  // 1. calculate lines
216  QList<Row> rows;
217  QList<QLayoutItem*> rowItems;
218  for( int i = 0; i < d->itemList.count(); ++i ) {
219  QLayoutItem* item = d->itemList[i];
220  int nextX = x + item->sizeHint().width() + horizontalSpacing();
221  if (nextX - horizontalSpacing() > rect.right() && lineHeight > 0) {
222  rows.append( Row( rowItems, lineHeight, x - horizontalSpacing() ) );
223  rowItems.clear();
224 
225  x = rect.x();
226  y = y + lineHeight + verticalSpacing();
227  nextX = x + item->sizeHint().width() + horizontalSpacing();
228  lineHeight = 0;
229  }
230 
231  rowItems.append( item );
232 
233  x = nextX;
234  lineHeight = qMax(lineHeight, item->sizeHint().height());
235  }
236  // append the last row
237  rows.append( Row( rowItems, lineHeight, x-horizontalSpacing() ) );
238 
239  int finalHeight = y + lineHeight - rect.y();
240  if( testOnly )
241  return finalHeight;
242 
243  // 2. place the items
244  y = rect.y();
245  for (const Row& row : qAsConst(rows)) {
246  x = rect.x();
247  if( alignment() & Qt::AlignRight )
248  x += (rect.width() - row.width);
249  else if( alignment() & Qt::AlignHCenter )
250  x += (rect.width() - row.width)/2;
251 
252  for (QLayoutItem* item : qAsConst(row.items)) {
253  int yy = y;
254  if( alignment() & Qt::AlignBottom )
255  yy += (row.height - item->sizeHint().height());
256  else if( alignment() & Qt::AlignVCenter )
257  yy += (row.height - item->sizeHint().height())/2;
258  item->setGeometry(QRect(QPoint(x, yy), item->sizeHint()));
259 
260  x += item->sizeHint().width() + horizontalSpacing();
261 
262  if( alignment() & Qt::AlignJustify )
263  x += (rect.width() - row.width)/qMax(row.items.count()-1,1);
264  }
265 
266  y = y + row.height + verticalSpacing();
267  }
268 
269  return finalHeight;
270 }
void setAlignment(Qt::Alignment)
Set the alignment to use.
void clear()
void setHeight(int height)
int width() const const
int right() const const
virtual void setGeometry(const QRect &r)=0
QStyle * style() const const
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const =0
int & rwidth()
int x() const const
int y() const const
AlignLeft
void append(const T &value)
virtual QSize minimumSize() const const =0
The KBlockLayout arranges widget in rows and columns like a text editor does.
Definition: kblocklayout.h:36
int width() const const
QSize expandedTo(const QSize &otherSize) const const
int height() const const
int spacing() const const
typedef Orientations
bool isWidgetType() const const
QObject * parent() const const
virtual void setGeometry(const QRect &r) override
int margin() const const
virtual QSize sizeHint() const const =0
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 18 2021 23:07:21 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.