Krita Source Code Documentation
Loading...
Searching...
No Matches
KoToolBoxLayout_p.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005-2009 Thomas Zander <zander@kde.org>
3 * SPDX-FileCopyrightText: 2009 Peter Simonsson <peter.simonsson@gmail.com>
4 * SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
5 *
6 * SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8#ifndef _KO_TOOLBOX_LAYOUT_H_
9#define _KO_TOOLBOX_LAYOUT_H_
10
11#include <WidgetsDebug.h>
12#include <QLayout>
13#include <QMap>
14#include <QRect>
15#include <QAbstractButton>
16#include <QApplication>
17#include <QMouseEvent>
18
19class SectionLayout : public QLayout
20{
21public:
22 explicit SectionLayout(QWidget *parent)
23 : QLayout(parent), m_orientation(Qt::Vertical)
24 {
25 }
26
27 ~SectionLayout() override
28 {
29 qDeleteAll( m_items );
30 m_items.clear();
31 }
32
33 void addButton(QAbstractButton *button, int priority)
34 {
35 addChildWidget(button);
36 if (m_priorities.values().contains(priority)) {
37 qWarning() << "Button" << button << "has a conflicting priority";
38 }
39
40 m_priorities.insert(button, priority);
41 int index = 1;
42 Q_FOREACH (QWidgetItem *item, m_items) {
43 if (m_priorities.value(static_cast<QAbstractButton*>(item->widget())) > priority)
44 break;
45 index++;
46 }
47 m_items.insert(index-1, new QWidgetItem(button));
48 }
49
50 QSize sizeHint() const override
51 {
52 // This is implemented just to not freak out GammaRay, in practice
53 // this doesn't have any effect on the layout.
54 if (m_orientation == Qt::Vertical) {
55 return QSize(m_buttonSize.width(), m_buttonSize.height() * count());
56 } else {
57 return QSize(m_buttonSize.width() * count(), m_buttonSize.height());
58 }
59 }
60
61 void addItem(QLayoutItem*) override { Q_ASSERT(0); }
62
63 QLayoutItem* itemAt(int i) const override
64 {
65 if (m_items.count() <= i)
66 return 0;
67 return m_items.at(i);
68 }
69
70 QLayoutItem* takeAt(int i) override { return m_items.takeAt(i); }
71
72 int count() const override { return m_items.count(); }
73
74 void setGeometry (const QRect &rect) override
75 {
76 int x = 0;
77 int y = 0; const QSize &size = buttonSize();
78 if (m_orientation == Qt::Vertical) {
79 foreach (QWidgetItem* w, m_items) {
80 if (w->isEmpty())
81 continue;
82 int realX;
83 if (parentWidget()->isLeftToRight()) {
84 realX = x;
85 } else {
86 realX = rect.width() - x - size.width();
87 }
88 w->widget()->setGeometry(QRect(realX, y, size.width(), size.height()));
89 x += size.width();
90 if (x + size.width() > rect.width()) {
91 x = 0;
92 y += size.height();
93 }
94 }
95 } else {
96 foreach (QWidgetItem* w, m_items) {
97 if (w->isEmpty())
98 continue;
99 int realX;
100 if (parentWidget()->isLeftToRight()) {
101 realX = x;
102 } else {
103 realX = rect.width() - x - size.width();
104 }
105 w->widget()->setGeometry(QRect(realX, y, size.width(), size.height()));
106 y += size.height();
107 if (y + size.height() > rect.height()) {
108 x += size.width();
109 y = 0;
110 }
111 }
112 }
113 }
114
115 void setButtonSize(const QSize size)
116 {
117 m_buttonSize = size;
118 }
119
120 const QSize &buttonSize() const
121 {
122 return m_buttonSize;
123 }
124
125 void setOrientation (Qt::Orientation orientation)
126 {
127 m_orientation = orientation;
128 }
129
130private:
132 QMap<QAbstractButton*, int> m_priorities;
134 Qt::Orientation m_orientation;
135};
136
137class Section : public QWidget
138{
139public:
141 SeparatorTop = 0x0001,/* SeparatorBottom = 0x0002, SeparatorRight = 0x0004,*/ SeparatorLeft = 0x0008
142 };
143 Q_DECLARE_FLAGS(Separators, SeparatorFlag)
144 explicit Section(QWidget *parent = 0)
145 : QWidget(parent),
146 m_layout(new SectionLayout(this))
147 {
148// Re-enable this when we need to debug the section layout again.
149// setAutoFillBackground(true);
150// static int i = 0;
151// switch(i) {
152// case 0:
153// setStyleSheet("background-color:red");
154// break;
155// case 1:
156// setStyleSheet("background-color:blue");
157// break;
158// case 2:
159// setStyleSheet("background-color:green");
160// break;
161// case 3:
162// setStyleSheet("background-color:yellow");
163// break;
164// case 4:
165// setStyleSheet("background-color:white");
166// break;
167// case 5:
168// setStyleSheet("background-color:gray");
169// break;
170// case 6:
171// setStyleSheet("background-color:lime");
172// break;
173// case 7:
174// setStyleSheet("background-color:silver");
175// break;
176// case 8:
177// setStyleSheet("background-color:purple");
178// break;
179// default:
180// setStyleSheet("background-color:maroon");
181// break;
182// }
183// i++;
184
185 }
186
187 void addButton(QAbstractButton *button, int priority)
188 {
189 m_layout->addButton(button, priority);
190 }
191
192 void setName(const QString &name)
193 {
194 setObjectName(name);
195 m_name = name;
196 }
197
198 QString name() const
199 {
200 return m_name;
201 }
202
203 void setButtonSize(QSize size)
204 {
205 m_layout->setButtonSize(size);
206 }
207
208 QSize iconSize() const
209 {
210 return m_layout->buttonSize();
211 }
212
214 {
215 int count = 0;
216 for(int i = m_layout->count()-1; i >= 0; --i) {
217 if (! static_cast<QWidgetItem*> (m_layout->itemAt(i))->isEmpty())
218 ++count;
219 }
220 return count;
221 }
222
223 void setSeparator(Separators separators)
224 {
226 }
227
228 Separators separators() const
229 {
230 return m_separators;
231 }
232
233 void setOrientation (Qt::Orientation orientation)
234 {
235 m_layout->setOrientation(orientation);
236 }
237
238
239protected:
240private:
242 QString m_name;
243 Separators m_separators;
244};
245
246Q_DECLARE_OPERATORS_FOR_FLAGS(Section::Separators)
247
248class KoToolBoxLayout : public QLayout
249{
250public:
251 explicit KoToolBoxLayout(QWidget *parent)
252 : QLayout(parent)
253 , m_orientation(Qt::Vertical)
254 {
255 setSpacing(6);
256 }
257
259 {
260 qDeleteAll( m_sections );
261 m_sections.clear();
262 }
263
264 QSize sizeHint() const override
265 {
266 // Prefer showing two rows/columns by default
267 QSize twoIcons = static_cast<Section*> (m_sections[0]->widget())->iconSize() * 2;
268 const int length = doLayout(QRect(QPoint(), twoIcons), false);
269 if (m_orientation == Qt::Vertical) {
270 return QSize(twoIcons.width(), length);
271 } else {
272 return QSize(length, twoIcons.height());
273 }
274 }
275
276 QSize minimumSize() const override
277 {
278 if (m_sections.isEmpty())
279 return QSize();
280 QSize oneIcon = static_cast<Section*> (m_sections[0]->widget())->iconSize();
281 return oneIcon;
282 }
283
284 void addSection(Section *section)
285 {
286 addChildWidget(section);
287
288 QList<QWidgetItem*>::iterator iterator = m_sections.begin();
289 int defaults = 2; // skip the first two as they are the 'main' and 'dynamic' sections.
290 while (iterator != m_sections.end()) {
291 if (--defaults < 0 && static_cast<Section*> ((*iterator)->widget())->name() > section->name())
292 break;
293 ++iterator;
294 }
295 m_sections.insert(iterator, new QWidgetItem(section));
296 }
297
298 void addItem(QLayoutItem*) override
299 {
300 Q_ASSERT(0); // don't let anything else be added. (code depends on this!)
301 }
302
303 QLayoutItem* itemAt(int i) const override
304 {
305 return m_sections.value(i);
306 }
307
308 QLayoutItem* takeAt(int i) override { return m_sections.takeAt(i); }
309
310 int count() const override { return m_sections.count(); }
311
312 void setGeometry (const QRect &rect) override
313 {
314 QLayout::setGeometry(rect);
315 doLayout(rect, true);
316 }
317
318 bool hasHeightForWidth() const override
319 {
320 // return true;
321 return m_orientation == Qt::Vertical;
322 }
323
324 int heightForWidth(int width) const override
325 {
326 if (m_orientation == Qt::Vertical) {
327 const int height = doLayout(QRect(0, 0, width, 0), false);
328 return height;
329 } else {
330 #if 0
331 const int iconHeight = static_cast<Section*> (m_sections[0]->widget())->iconSize().height();
332 for (int i = 1; i <= 10; i++) {
333 const int testWidth = doLayout(QRect(0, 0, 0, iconHeight * i), false);
334 if (testWidth <= width) {
335 return iconHeight * i;
336 }
337 }
338 // Return a huge height
339 return 65535;
340 #endif
341 return -1;
342 }
343 }
344
350 int widthForHeight(int height) const
351 {
352 if (m_orientation == Qt::Horizontal) {
353 const int width = doLayout(QRect(0, 0, 0, height), false);
354 return width;
355 } else {
356 return -1;
357 }
358 }
359
360 void setOrientation (Qt::Orientation orientation)
361 {
362 m_orientation = orientation;
363 invalidate();
364 }
365
366private:
367 int doLayout(const QRect &rect, bool notDryRun) const
368 {
369 // nothing to do?
370 if (m_sections.isEmpty()) {
371 return 0;
372 }
373
374 // the names of the variables assume a vertical orientation,
375 // but all calculations are done based on the real orientation
376 const bool isVertical = m_orientation == Qt::Vertical;
377
378 const QSize iconSize = static_cast<Section*> (m_sections.first()->widget())->iconSize();
379
380 const int maxWidth = isVertical ? rect.width() : rect.height();
381 // using min 1 as width to e.g. protect against div by 0 below
382 const int iconWidth = qMax(1, isVertical ? iconSize.width() : iconSize.height());
383 const int iconHeight = qMax(1, isVertical ? iconSize.height() : iconSize.width());
384
385 const int maxColumns = qMax(1, (maxWidth / iconWidth));
386
387 int x = 0;
388 int y = 0;
389 bool firstSection = true;
390 foreach (QWidgetItem *wi, m_sections) {
391 Section *section = static_cast<Section*> (wi->widget());
392 const int buttonCount = section->visibleButtonCount();
393 if (buttonCount == 0) {
394 // move out of view, not perfect TODO: better solution
395 if (notDryRun) {
396 section->setGeometry(1000, 1000, 0, 0);
397 }
398 continue;
399 }
400
401 // rows needed for the buttons (calculation gets the ceiling value of the plain div)
402 const int neededRowCount = ((buttonCount-1) / maxColumns) + 1;
403
404 if (firstSection) {
405 firstSection = false;
406 } else {
407 // start on a new row, set separator
408 x = 0;
409 y += iconHeight + spacing();
410 if (notDryRun){
411 const Section::Separators separator =
413 section->setSeparator( separator );
414 }
415 }
416
417 if (notDryRun) {
418 const int usedColumns = qMin(buttonCount, maxColumns);
419 int narrowSide = usedColumns * iconWidth;
420 int longSide = neededRowCount * iconHeight;
421 if (isVertical) {
422 int realX;
423 if (parentWidget()->isLeftToRight()) {
424 realX = x;
425 } else {
426 realX = rect.width() - x - narrowSide;
427 }
428 section->setGeometry(realX, y,
429 narrowSide, longSide);
430 } else {
431 int realX;
432 if (parentWidget()->isLeftToRight()) {
433 realX = y;
434 } else {
435 realX = rect.width() - y - longSide;
436 }
437 section->setGeometry(realX, x,
438 longSide, narrowSide);
439 }
440 }
441
442 // advance by the icons in the last row
443 const int lastRowColumnCount = buttonCount - ((neededRowCount-1) * maxColumns);
444 x += (lastRowColumnCount * iconWidth) + spacing();
445 // advance by all but the last used row
446 y += (neededRowCount - 1) * iconHeight;
447 }
448
449 // cache total height (or width), adding the iconHeight for the current row
450 return y + iconHeight;
451 }
452
453 QList <QWidgetItem*> m_sections;
454 Qt::Orientation m_orientation;
455};
456
457#endif
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
Q_DECLARE_FLAGS(KisUpdaterContextSnapshotEx, KisUpdaterContextSnapshotExTag)
int iconSize(qreal width, qreal height)
void addItem(QLayoutItem *) override
int count() const override
QSize sizeHint() const override
QList< QWidgetItem * > m_sections
bool hasHeightForWidth() const override
int doLayout(const QRect &rect, bool notDryRun) const
KoToolBoxLayout(QWidget *parent)
int heightForWidth(int width) const override
QLayoutItem * itemAt(int i) const override
void setOrientation(Qt::Orientation orientation)
void addSection(Section *section)
~KoToolBoxLayout() override
void setGeometry(const QRect &rect) override
QLayoutItem * takeAt(int i) override
Qt::Orientation m_orientation
int widthForHeight(int height) const
QSize minimumSize() const override
void setButtonSize(const QSize size)
QMap< QAbstractButton *, int > m_priorities
const QSize & buttonSize() const
SectionLayout(QWidget *parent)
QLayoutItem * itemAt(int i) const override
int count() const override
~SectionLayout() override
void addButton(QAbstractButton *button, int priority)
void setOrientation(Qt::Orientation orientation)
QList< QWidgetItem * > m_items
QSize sizeHint() const override
void setGeometry(const QRect &rect) override
QLayoutItem * takeAt(int i) override
Qt::Orientation m_orientation
void addItem(QLayoutItem *) override
SectionLayout * m_layout
void addButton(QAbstractButton *button, int priority)
void setButtonSize(QSize size)
Separators separators() const
QString name() const
Separators m_separators
void setSeparator(Separators separators)
void setOrientation(Qt::Orientation orientation)
int visibleButtonCount() const
void setName(const QString &name)
QSize iconSize() const
Q_DECLARE_OPERATORS_FOR_FLAGS(KisBaseRectsWalker::SubtreeVisitFlags)
QString button(const QWheelEvent &ev)