Warning, file /office/calligra/libs/widgets/KoToolBoxLayout_p.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * Copyright (c) 2005-2009 Thomas Zander <zander@kde.org> 0003 * Copyright (c) 2009 Peter Simonsson <peter.simonsson@gmail.com> 0004 * Copyright (c) 2010 Cyrille Berger <cberger@cberger.net> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public License 0017 * along with this library; see the file COPYING.LIB. If not, write to 0018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 #ifndef _KO_TOOLBOX_LAYOUT_H_ 0022 #define _KO_TOOLBOX_LAYOUT_H_ 0023 0024 #include <WidgetsDebug.h> 0025 #include <QLayout> 0026 #include <QMap> 0027 #include <QRect> 0028 #include <QAbstractButton> 0029 #include <QDesktopWidget> 0030 #include <QApplication> 0031 #include <QMouseEvent> 0032 0033 class SectionLayout : public QLayout 0034 { 0035 Q_OBJECT 0036 public: 0037 explicit SectionLayout(QWidget *parent) 0038 : QLayout(parent), m_orientation(Qt::Vertical) 0039 { 0040 } 0041 0042 ~SectionLayout() override 0043 { 0044 qDeleteAll( m_items ); 0045 m_items.clear(); 0046 } 0047 0048 void addButton(QAbstractButton *button, int priority) 0049 { 0050 addChildWidget(button); 0051 0052 m_priorities.insert(button, priority); 0053 int index = 1; 0054 foreach (QWidgetItem *item, m_items) { 0055 if (m_priorities.value(static_cast<QAbstractButton*>(item->widget())) > priority) 0056 break; 0057 index++; 0058 } 0059 m_items.insert(index-1, new QWidgetItem(button)); 0060 } 0061 0062 QSize sizeHint() const override 0063 { 0064 Q_ASSERT(0); 0065 return QSize(); 0066 } 0067 0068 void addItem(QLayoutItem*) override { Q_ASSERT(0); } 0069 0070 QLayoutItem* itemAt(int i) const override 0071 { 0072 if (m_items.count() <= i) 0073 return nullptr; 0074 return m_items.at(i); 0075 } 0076 0077 QLayoutItem* takeAt(int i) override { return m_items.takeAt(i); } 0078 0079 int count() const override { return m_items.count(); } 0080 0081 void setGeometry (const QRect &rect) override 0082 { 0083 int x = 0; 0084 int y = 0; 0085 const QSize &size = buttonSize(); 0086 if (m_orientation == Qt::Vertical) { 0087 foreach (QWidgetItem* w, m_items) { 0088 if (w->isEmpty()) 0089 continue; 0090 w->widget()->setGeometry(QRect(x, y, size.width(), size.height())); 0091 x += size.width(); 0092 if (x + size.width() > rect.width()) { 0093 x = 0; 0094 y += size.height(); 0095 } 0096 } 0097 } else { 0098 foreach (QWidgetItem* w, m_items) { 0099 if (w->isEmpty()) 0100 continue; 0101 w->widget()->setGeometry(QRect(x, y, size.width(), size.height())); 0102 y += size.height(); 0103 if (y + size.height() > rect.height()) { 0104 x += size.width(); 0105 y = 0; 0106 } 0107 } 0108 } 0109 } 0110 0111 void setButtonSize(const QSize size) 0112 { 0113 m_buttonSize = size; 0114 } 0115 0116 const QSize &buttonSize() const 0117 { 0118 return m_buttonSize; 0119 } 0120 0121 void setOrientation (Qt::Orientation orientation) 0122 { 0123 m_orientation = orientation; 0124 } 0125 0126 private: 0127 QSize m_buttonSize; 0128 QMap<QAbstractButton*, int> m_priorities; 0129 QList<QWidgetItem*> m_items; 0130 Qt::Orientation m_orientation; 0131 }; 0132 0133 class Section : public QWidget 0134 { 0135 Q_OBJECT 0136 public: 0137 enum SeparatorFlag { 0138 SeparatorTop = 0x0001,/* SeparatorBottom = 0x0002, SeparatorRight = 0x0004,*/ SeparatorLeft = 0x0008 0139 }; 0140 Q_DECLARE_FLAGS(Separators, SeparatorFlag) 0141 explicit Section(QWidget *parent = 0) 0142 : QWidget(parent), 0143 m_layout(new SectionLayout(this)) 0144 { 0145 setLayout(m_layout); 0146 } 0147 0148 void addButton(QAbstractButton *button, int priority) 0149 { 0150 m_layout->addButton(button, priority); 0151 } 0152 0153 void setName(const QString &name) 0154 { 0155 m_name = name; 0156 } 0157 0158 QString name() const 0159 { 0160 return m_name; 0161 } 0162 0163 void setButtonSize(const QSize& size) 0164 { 0165 m_layout->setButtonSize(size); 0166 } 0167 0168 QSize iconSize() const 0169 { 0170 return m_layout->buttonSize(); 0171 } 0172 0173 int visibleButtonCount() const 0174 { 0175 int count = 0; 0176 for(int i = m_layout->count()-1; i >= 0; --i) { 0177 if (! static_cast<QWidgetItem*> (m_layout->itemAt(i))->isEmpty()) 0178 ++count; 0179 } 0180 return count; 0181 } 0182 0183 void setSeparator(Separators separators) 0184 { 0185 m_separators = separators; 0186 } 0187 0188 Separators separators() const 0189 { 0190 return m_separators; 0191 } 0192 0193 void setOrientation (Qt::Orientation orientation) 0194 { 0195 m_layout->setOrientation(orientation); 0196 } 0197 0198 private: 0199 SectionLayout *m_layout; 0200 QString m_name; 0201 Separators m_separators; 0202 }; 0203 0204 Q_DECLARE_OPERATORS_FOR_FLAGS(Section::Separators) 0205 0206 class KoToolBoxLayout : public QLayout 0207 { 0208 Q_OBJECT 0209 public: 0210 explicit KoToolBoxLayout(QWidget *parent) 0211 : QLayout(parent) 0212 , m_orientation(Qt::Vertical) 0213 { 0214 setSpacing(6); 0215 } 0216 0217 ~KoToolBoxLayout() override; 0218 0219 QSize sizeHint() const override 0220 { 0221 // Prefer showing one row/column by default 0222 const QSize minSize = minimumSize(); 0223 if (!minSize.isValid()) { 0224 return minSize; 0225 } 0226 if (m_orientation == Qt::Vertical) { 0227 return QSize(minSize.width(), minSize.height() + spacing()); 0228 } else { 0229 return QSize(minSize.height() + spacing(), minSize.width()); 0230 } 0231 } 0232 0233 QSize minimumSize() const override 0234 { 0235 if (m_sections.isEmpty()) 0236 return QSize(); 0237 QSize oneIcon = static_cast<Section*> (m_sections[0]->widget())->iconSize(); 0238 return oneIcon; 0239 } 0240 0241 void addSection(Section *section) 0242 { 0243 addChildWidget(section); 0244 0245 QList<QWidgetItem*>::iterator iterator = m_sections.begin(); 0246 int defaults = 2; // skip the first two as they are the 'main' and 'dynamic' sections. 0247 while (iterator != m_sections.end()) { 0248 if (--defaults < 0 && static_cast<Section*> ((*iterator)->widget())->name() > section->name()) 0249 break; 0250 ++iterator; 0251 } 0252 m_sections.insert(iterator, new QWidgetItem(section)); 0253 } 0254 0255 void addItem(QLayoutItem*) override 0256 { 0257 Q_ASSERT(0); // don't let anything else be added. (code depends on this!) 0258 } 0259 0260 QLayoutItem* itemAt(int i) const override 0261 { 0262 return m_sections.value(i); 0263 } 0264 QLayoutItem* takeAt(int i) override { return m_sections.takeAt(i); } 0265 int count() const override { return m_sections.count(); } 0266 0267 void setGeometry (const QRect &rect) override 0268 { 0269 QLayout::setGeometry(rect); 0270 doLayout(rect.size(), true); 0271 } 0272 0273 bool hasHeightForWidth() const override 0274 { 0275 return m_orientation == Qt::Vertical; 0276 } 0277 0278 int heightForWidth(int width) const override 0279 { 0280 if (m_orientation == Qt::Vertical) { 0281 const int height = doLayout(QSize(width, 0), false); 0282 return height; 0283 } else { 0284 return -1; 0285 } 0286 } 0287 0288 /** 0289 * For calculating the width from height by KoToolBoxScrollArea. 0290 * QWidget doesn't actually support trading width for height, so it needs to 0291 * be handled specifically. 0292 */ 0293 int widthForHeight(int height) const 0294 { 0295 if (m_orientation == Qt::Horizontal) { 0296 const int width = doLayout(QSize(0, height), false); 0297 return width; 0298 } else { 0299 return -1; 0300 } 0301 } 0302 0303 void setOrientation (Qt::Orientation orientation) 0304 { 0305 m_orientation = orientation; 0306 invalidate(); 0307 } 0308 0309 private: 0310 int doLayout(const QSize &size, bool applyGeometry) const 0311 { 0312 // nothing to do? 0313 if (m_sections.isEmpty()) { 0314 return 0; 0315 } 0316 0317 // the names of the variables assume a vertical orientation, 0318 // but all calculations are done based on the real orientation 0319 const bool isVertical = m_orientation == Qt::Vertical; 0320 0321 const QSize iconSize = static_cast<Section*> (m_sections.first()->widget())->iconSize(); 0322 0323 const int maxWidth = isVertical ? size.width() : size.height(); 0324 // using min 1 as width to e.g. protect against div by 0 below 0325 const int iconWidth = qMax(1, isVertical ? iconSize.width() : iconSize.height()); 0326 const int iconHeight = qMax(1, isVertical ? iconSize.height() : iconSize.width()); 0327 0328 const int maxColumns = qMax(1, (maxWidth / iconWidth)); 0329 0330 int x = 0; 0331 int y = 0; 0332 bool firstSection = true; 0333 if (!applyGeometry) { 0334 foreach (QWidgetItem *wi, m_sections) { 0335 Section *section = static_cast<Section*> (wi->widget()); 0336 const int buttonCount = section->visibleButtonCount(); 0337 if (buttonCount == 0) { 0338 continue; 0339 } 0340 0341 // rows needed for the buttons (calculation gets the ceiling value of the plain div) 0342 const int neededRowCount = ((buttonCount-1) / maxColumns) + 1; 0343 0344 if (firstSection) { 0345 firstSection = false; 0346 } else { 0347 // start on a new row, set separator 0348 x = 0; 0349 y += iconHeight + spacing(); 0350 } 0351 0352 // advance by the icons in the last row 0353 const int lastRowColumnCount = buttonCount - ((neededRowCount-1) * maxColumns); 0354 x += (lastRowColumnCount * iconWidth) + spacing(); 0355 // advance by all but the last used row 0356 y += (neededRowCount - 1) * iconHeight; 0357 } 0358 } else { 0359 foreach (QWidgetItem *wi, m_sections) { 0360 Section *section = static_cast<Section*> (wi->widget()); 0361 const int buttonCount = section->visibleButtonCount(); 0362 if (buttonCount == 0) { 0363 section->hide(); 0364 continue; 0365 } 0366 0367 // rows needed for the buttons (calculation gets the ceiling value of the plain div) 0368 const int neededRowCount = ((buttonCount-1) / maxColumns) + 1; 0369 0370 if (firstSection) { 0371 firstSection = false; 0372 } else { 0373 // start on a new row, set separator 0374 x = 0; 0375 y += iconHeight + spacing(); 0376 const Section::Separators separator = 0377 isVertical ? Section::SeparatorTop : Section::SeparatorLeft; 0378 section->setSeparator( separator ); 0379 } 0380 0381 const int usedColumns = qMin(buttonCount, maxColumns); 0382 if (isVertical) { 0383 section->setGeometry(x, y, 0384 usedColumns * iconWidth, neededRowCount * iconHeight); 0385 } else { 0386 section->setGeometry(y, x, 0387 neededRowCount * iconHeight, usedColumns * iconWidth); 0388 } 0389 0390 // advance by the icons in the last row 0391 const int lastRowColumnCount = buttonCount - ((neededRowCount-1) * maxColumns); 0392 x += (lastRowColumnCount * iconWidth) + spacing(); 0393 // advance by all but the last used row 0394 y += (neededRowCount - 1) * iconHeight; 0395 } 0396 } 0397 0398 return y + iconHeight; 0399 } 0400 0401 QList <QWidgetItem*> m_sections; 0402 Qt::Orientation m_orientation; 0403 }; 0404 0405 #endif