| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the demonstration applications of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:BSD$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** BSD License Usage |
| 18 | ** Alternatively, you may use this file under the terms of the BSD license |
| 19 | ** as follows: |
| 20 | ** |
| 21 | ** "Redistribution and use in source and binary forms, with or without |
| 22 | ** modification, are permitted provided that the following conditions are |
| 23 | ** met: |
| 24 | ** * Redistributions of source code must retain the above copyright |
| 25 | ** notice, this list of conditions and the following disclaimer. |
| 26 | ** * Redistributions in binary form must reproduce the above copyright |
| 27 | ** notice, this list of conditions and the following disclaimer in |
| 28 | ** the documentation and/or other materials provided with the |
| 29 | ** distribution. |
| 30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
| 31 | ** contributors may be used to endorse or promote products derived |
| 32 | ** from this software without specific prior written permission. |
| 33 | ** |
| 34 | ** |
| 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
| 46 | ** |
| 47 | ** $QT_END_LICENSE$ |
| 48 | ** |
| 49 | ****************************************************************************/ |
| 50 | |
| 51 | #include "toolbar.h" |
| 52 | |
| 53 | #include <QRandomGenerator> |
| 54 | |
| 55 | #include <QActionGroup> |
| 56 | #include <QMainWindow> |
| 57 | #include <QMenu> |
| 58 | #include <QPainter> |
| 59 | #include <QPainterPath> |
| 60 | #include <QSpinBox> |
| 61 | #include <QLabel> |
| 62 | #include <QToolTip> |
| 63 | |
| 64 | #include <stdlib.h> |
| 65 | |
| 66 | static QPixmap genIcon(const QSize &iconSize, const QString &, const QColor &color, qreal pixelRatio) |
| 67 | { |
| 68 | int w = qRound(iconSize.width() * pixelRatio); |
| 69 | int h = qRound(iconSize.height() * pixelRatio); |
| 70 | |
| 71 | QImage image(w, h, QImage::Format_ARGB32_Premultiplied); |
| 72 | image.fill(0); |
| 73 | |
| 74 | QPainter p(&image); |
| 75 | |
| 76 | extern void render_qt_text(QPainter *, int, int, const QColor &); |
| 77 | render_qt_text(&p, w, h, color); |
| 78 | |
| 79 | QPixmap pm = QPixmap::fromImage(image, Qt::DiffuseDither | Qt::DiffuseAlphaDither); |
| 80 | pm.setDevicePixelRatio(pixelRatio); |
| 81 | return pm; |
| 82 | } |
| 83 | |
| 84 | static QPixmap genIcon(const QSize &iconSize, int number, const QColor &color, qreal pixelRatio) |
| 85 | { return genIcon(iconSize, QString::number(number), color, pixelRatio); } |
| 86 | |
| 87 | ToolBar::ToolBar(const QString &title, QWidget *parent) |
| 88 | : QToolBar(parent) |
| 89 | , spinbox(nullptr) |
| 90 | , spinboxAction(nullptr) |
| 91 | { |
| 92 | setWindowTitle(title); |
| 93 | setObjectName(title); |
| 94 | |
| 95 | setIconSize(QSize(32, 32)); |
| 96 | |
| 97 | qreal dpr = devicePixelRatio(); |
| 98 | menu = new QMenu("One" , this); |
| 99 | menu->setIcon(genIcon(iconSize(), 1, Qt::black, dpr)); |
| 100 | menu->addAction(genIcon(iconSize(), "A" , Qt::blue, dpr), "A" ); |
| 101 | menu->addAction(genIcon(iconSize(), "B" , Qt::blue, dpr), "B" ); |
| 102 | menu->addAction(genIcon(iconSize(), "C" , Qt::blue, dpr), "C" ); |
| 103 | addAction(menu->menuAction()); |
| 104 | |
| 105 | QAction *two = addAction(genIcon(iconSize(), 2, Qt::white, dpr), "Two" ); |
| 106 | QFont boldFont; |
| 107 | boldFont.setBold(true); |
| 108 | two->setFont(boldFont); |
| 109 | |
| 110 | addAction(genIcon(iconSize(), 3, Qt::red, dpr), "Three" ); |
| 111 | addAction(genIcon(iconSize(), 4, Qt::green, dpr), "Four" ); |
| 112 | addAction(genIcon(iconSize(), 5, Qt::blue, dpr), "Five" ); |
| 113 | addAction(genIcon(iconSize(), 6, Qt::yellow, dpr), "Six" ); |
| 114 | orderAction = new QAction(this); |
| 115 | orderAction->setText(tr("Order Items in Tool Bar" )); |
| 116 | connect(orderAction, &QAction::triggered, this, &ToolBar::order); |
| 117 | |
| 118 | randomizeAction = new QAction(this); |
| 119 | randomizeAction->setText(tr("Randomize Items in Tool Bar" )); |
| 120 | connect(randomizeAction, &QAction::triggered, this, &ToolBar::randomize); |
| 121 | |
| 122 | addSpinBoxAction = new QAction(this); |
| 123 | addSpinBoxAction->setText(tr("Add Spin Box" )); |
| 124 | connect(addSpinBoxAction, &QAction::triggered, this, &ToolBar::addSpinBox); |
| 125 | |
| 126 | removeSpinBoxAction = new QAction(this); |
| 127 | removeSpinBoxAction->setText(tr("Remove Spin Box" )); |
| 128 | removeSpinBoxAction->setEnabled(false); |
| 129 | connect(removeSpinBoxAction, &QAction::triggered, this, &ToolBar::removeSpinBox); |
| 130 | |
| 131 | movableAction = new QAction(tr("Movable" ), this); |
| 132 | movableAction->setCheckable(true); |
| 133 | connect(movableAction, &QAction::triggered, this, &ToolBar::changeMovable); |
| 134 | |
| 135 | allowedAreasActions = new QActionGroup(this); |
| 136 | allowedAreasActions->setExclusive(false); |
| 137 | |
| 138 | allowLeftAction = new QAction(tr("Allow on Left" ), this); |
| 139 | allowLeftAction->setCheckable(true); |
| 140 | connect(allowLeftAction, &QAction::triggered, this, &ToolBar::allowLeft); |
| 141 | |
| 142 | allowRightAction = new QAction(tr("Allow on Right" ), this); |
| 143 | allowRightAction->setCheckable(true); |
| 144 | connect(allowRightAction, &QAction::triggered, this, &ToolBar::allowRight); |
| 145 | |
| 146 | allowTopAction = new QAction(tr("Allow on Top" ), this); |
| 147 | allowTopAction->setCheckable(true); |
| 148 | connect(allowTopAction, &QAction::triggered, this, &ToolBar::allowTop); |
| 149 | |
| 150 | allowBottomAction = new QAction(tr("Allow on Bottom" ), this); |
| 151 | allowBottomAction->setCheckable(true); |
| 152 | connect(allowBottomAction, &QAction::triggered, this, &ToolBar::allowBottom); |
| 153 | |
| 154 | allowedAreasActions->addAction(allowLeftAction); |
| 155 | allowedAreasActions->addAction(allowRightAction); |
| 156 | allowedAreasActions->addAction(allowTopAction); |
| 157 | allowedAreasActions->addAction(allowBottomAction); |
| 158 | |
| 159 | areaActions = new QActionGroup(this); |
| 160 | areaActions->setExclusive(true); |
| 161 | |
| 162 | leftAction = new QAction(tr("Place on Left" ) , this); |
| 163 | leftAction->setCheckable(true); |
| 164 | connect(leftAction, &QAction::triggered, this, &ToolBar::placeLeft); |
| 165 | |
| 166 | rightAction = new QAction(tr("Place on Right" ) , this); |
| 167 | rightAction->setCheckable(true); |
| 168 | connect(rightAction, &QAction::triggered, this, &ToolBar::placeRight); |
| 169 | |
| 170 | topAction = new QAction(tr("Place on Top" ) , this); |
| 171 | topAction->setCheckable(true); |
| 172 | connect(topAction, &QAction::triggered, this, &ToolBar::placeTop); |
| 173 | |
| 174 | bottomAction = new QAction(tr("Place on Bottom" ) , this); |
| 175 | bottomAction->setCheckable(true); |
| 176 | connect(bottomAction, &QAction::triggered, this, &ToolBar::placeBottom); |
| 177 | |
| 178 | areaActions->addAction(leftAction); |
| 179 | areaActions->addAction(rightAction); |
| 180 | areaActions->addAction(topAction); |
| 181 | areaActions->addAction(bottomAction); |
| 182 | |
| 183 | connect(movableAction, &QAction::triggered, areaActions, &QActionGroup::setEnabled); |
| 184 | |
| 185 | connect(movableAction, &QAction::triggered, allowedAreasActions, &QActionGroup::setEnabled); |
| 186 | |
| 187 | menu = new QMenu(title, this); |
| 188 | menu->addAction(toggleViewAction()); |
| 189 | menu->addSeparator(); |
| 190 | menu->addAction(orderAction); |
| 191 | menu->addAction(randomizeAction); |
| 192 | menu->addSeparator(); |
| 193 | menu->addAction(addSpinBoxAction); |
| 194 | menu->addAction(removeSpinBoxAction); |
| 195 | menu->addSeparator(); |
| 196 | menu->addAction(movableAction); |
| 197 | menu->addSeparator(); |
| 198 | menu->addActions(allowedAreasActions->actions()); |
| 199 | menu->addSeparator(); |
| 200 | menu->addActions(areaActions->actions()); |
| 201 | menu->addSeparator(); |
| 202 | menu->addAction(tr("Insert break" ), this, &ToolBar::insertToolBarBreak); |
| 203 | |
| 204 | connect(menu, &QMenu::aboutToShow, this, &ToolBar::updateMenu); |
| 205 | |
| 206 | randomize(); |
| 207 | } |
| 208 | |
| 209 | void ToolBar::() |
| 210 | { |
| 211 | QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget()); |
| 212 | Q_ASSERT(mainWindow); |
| 213 | |
| 214 | const Qt::ToolBarArea area = mainWindow->toolBarArea(this); |
| 215 | const Qt::ToolBarAreas areas = allowedAreas(); |
| 216 | |
| 217 | movableAction->setChecked(isMovable()); |
| 218 | |
| 219 | allowLeftAction->setChecked(isAreaAllowed(Qt::LeftToolBarArea)); |
| 220 | allowRightAction->setChecked(isAreaAllowed(Qt::RightToolBarArea)); |
| 221 | allowTopAction->setChecked(isAreaAllowed(Qt::TopToolBarArea)); |
| 222 | allowBottomAction->setChecked(isAreaAllowed(Qt::BottomToolBarArea)); |
| 223 | |
| 224 | if (allowedAreasActions->isEnabled()) { |
| 225 | allowLeftAction->setEnabled(area != Qt::LeftToolBarArea); |
| 226 | allowRightAction->setEnabled(area != Qt::RightToolBarArea); |
| 227 | allowTopAction->setEnabled(area != Qt::TopToolBarArea); |
| 228 | allowBottomAction->setEnabled(area != Qt::BottomToolBarArea); |
| 229 | } |
| 230 | |
| 231 | leftAction->setChecked(area == Qt::LeftToolBarArea); |
| 232 | rightAction->setChecked(area == Qt::RightToolBarArea); |
| 233 | topAction->setChecked(area == Qt::TopToolBarArea); |
| 234 | bottomAction->setChecked(area == Qt::BottomToolBarArea); |
| 235 | |
| 236 | if (areaActions->isEnabled()) { |
| 237 | leftAction->setEnabled(areas & Qt::LeftToolBarArea); |
| 238 | rightAction->setEnabled(areas & Qt::RightToolBarArea); |
| 239 | topAction->setEnabled(areas & Qt::TopToolBarArea); |
| 240 | bottomAction->setEnabled(areas & Qt::BottomToolBarArea); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | void ToolBar::order() |
| 245 | { |
| 246 | QList<QAction *> ordered; |
| 247 | QList<QAction *> actions1 = actions(); |
| 248 | const QList<QAction *> childActions = findChildren<QAction *>(); |
| 249 | for (QAction *action : childActions) { |
| 250 | if (!actions1.contains(action)) |
| 251 | continue; |
| 252 | actions1.removeAll(action); |
| 253 | ordered.append(action); |
| 254 | } |
| 255 | |
| 256 | clear(); |
| 257 | addActions(ordered); |
| 258 | |
| 259 | orderAction->setEnabled(false); |
| 260 | } |
| 261 | |
| 262 | void ToolBar::randomize() |
| 263 | { |
| 264 | QList<QAction *> randomized; |
| 265 | QList<QAction *> actions = this->actions(); |
| 266 | while (!actions.isEmpty()) { |
| 267 | QAction *action = actions.takeAt(QRandomGenerator::global()->bounded(int(actions.size()))); |
| 268 | randomized.append(action); |
| 269 | } |
| 270 | clear(); |
| 271 | addActions(randomized); |
| 272 | |
| 273 | orderAction->setEnabled(true); |
| 274 | } |
| 275 | |
| 276 | void ToolBar::addSpinBox() |
| 277 | { |
| 278 | if (!spinbox) |
| 279 | spinbox = new QSpinBox(this); |
| 280 | if (!spinboxAction) |
| 281 | spinboxAction = addWidget(spinbox); |
| 282 | else |
| 283 | addAction(spinboxAction); |
| 284 | |
| 285 | addSpinBoxAction->setEnabled(false); |
| 286 | removeSpinBoxAction->setEnabled(true); |
| 287 | } |
| 288 | |
| 289 | void ToolBar::removeSpinBox() |
| 290 | { |
| 291 | if (spinboxAction) |
| 292 | removeAction(spinboxAction); |
| 293 | |
| 294 | addSpinBoxAction->setEnabled(true); |
| 295 | removeSpinBoxAction->setEnabled(false); |
| 296 | } |
| 297 | |
| 298 | void ToolBar::allow(Qt::ToolBarArea area, bool a) |
| 299 | { |
| 300 | Qt::ToolBarAreas areas = allowedAreas(); |
| 301 | areas = a ? areas | area : areas & ~area; |
| 302 | setAllowedAreas(areas); |
| 303 | |
| 304 | if (areaActions->isEnabled()) { |
| 305 | leftAction->setEnabled(areas & Qt::LeftToolBarArea); |
| 306 | rightAction->setEnabled(areas & Qt::RightToolBarArea); |
| 307 | topAction->setEnabled(areas & Qt::TopToolBarArea); |
| 308 | bottomAction->setEnabled(areas & Qt::BottomToolBarArea); |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | void ToolBar::place(Qt::ToolBarArea area, bool p) |
| 313 | { |
| 314 | if (!p) |
| 315 | return; |
| 316 | |
| 317 | QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget()); |
| 318 | Q_ASSERT(mainWindow); |
| 319 | |
| 320 | mainWindow->addToolBar(area, this); |
| 321 | |
| 322 | if (allowedAreasActions->isEnabled()) { |
| 323 | allowLeftAction->setEnabled(area != Qt::LeftToolBarArea); |
| 324 | allowRightAction->setEnabled(area != Qt::RightToolBarArea); |
| 325 | allowTopAction->setEnabled(area != Qt::TopToolBarArea); |
| 326 | allowBottomAction->setEnabled(area != Qt::BottomToolBarArea); |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | void ToolBar::changeMovable(bool movable) |
| 331 | { setMovable(movable); } |
| 332 | |
| 333 | void ToolBar::allowLeft(bool a) |
| 334 | { allow(Qt::LeftToolBarArea, a); } |
| 335 | |
| 336 | void ToolBar::allowRight(bool a) |
| 337 | { allow(Qt::RightToolBarArea, a); } |
| 338 | |
| 339 | void ToolBar::allowTop(bool a) |
| 340 | { allow(Qt::TopToolBarArea, a); } |
| 341 | |
| 342 | void ToolBar::allowBottom(bool a) |
| 343 | { allow(Qt::BottomToolBarArea, a); } |
| 344 | |
| 345 | void ToolBar::placeLeft(bool p) |
| 346 | { place(Qt::LeftToolBarArea, p); } |
| 347 | |
| 348 | void ToolBar::placeRight(bool p) |
| 349 | { place(Qt::RightToolBarArea, p); } |
| 350 | |
| 351 | void ToolBar::placeTop(bool p) |
| 352 | { place(Qt::TopToolBarArea, p); } |
| 353 | |
| 354 | void ToolBar::placeBottom(bool p) |
| 355 | { place(Qt::BottomToolBarArea, p); } |
| 356 | |
| 357 | void ToolBar::insertToolBarBreak() |
| 358 | { |
| 359 | QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parentWidget()); |
| 360 | Q_ASSERT(mainWindow); |
| 361 | |
| 362 | mainWindow->insertToolBarBreak(this); |
| 363 | } |
| 364 | |