| 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 <QMainWindow> |
| 56 | #include <QMenu> |
| 57 | #include <QPainter> |
| 58 | #include <QPainterPath> |
| 59 | #include <QSpinBox> |
| 60 | #include <QLabel> |
| 61 | #include <QToolTip> |
| 62 | |
| 63 | #include <stdlib.h> |
| 64 | |
| 65 | static QPixmap genIcon(const QSize &iconSize, const QString &, const QColor &color, qreal pixelRatio) |
| 66 | { |
| 67 | int w = qRound(d: iconSize.width() * pixelRatio); |
| 68 | int h = qRound(d: iconSize.height() * pixelRatio); |
| 69 | |
| 70 | QImage image(w, h, QImage::Format_ARGB32_Premultiplied); |
| 71 | image.fill(pixel: 0); |
| 72 | |
| 73 | QPainter p(&image); |
| 74 | |
| 75 | extern void render_qt_text(QPainter *, int, int, const QColor &); |
| 76 | render_qt_text(&p, w, h, color); |
| 77 | |
| 78 | QPixmap pm = QPixmap::fromImage(image, flags: Qt::DiffuseDither | Qt::DiffuseAlphaDither); |
| 79 | pm.setDevicePixelRatio(pixelRatio); |
| 80 | return pm; |
| 81 | } |
| 82 | |
| 83 | static QPixmap genIcon(const QSize &iconSize, int number, const QColor &color, qreal pixelRatio) |
| 84 | { return genIcon(iconSize, QString::number(number), color, pixelRatio); } |
| 85 | |
| 86 | ToolBar::ToolBar(const QString &title, QWidget *parent) |
| 87 | : QToolBar(parent) |
| 88 | , spinbox(nullptr) |
| 89 | , spinboxAction(nullptr) |
| 90 | { |
| 91 | setWindowTitle(title); |
| 92 | setObjectName(title); |
| 93 | |
| 94 | setIconSize(QSize(32, 32)); |
| 95 | |
| 96 | qreal dpr = devicePixelRatioF(); |
| 97 | menu = new QMenu("One" , this); |
| 98 | menu->setIcon(genIcon(iconSize: iconSize(), number: 1, color: Qt::black, pixelRatio: dpr)); |
| 99 | menu->addAction(icon: genIcon(iconSize: iconSize(), "A" , color: Qt::blue, pixelRatio: dpr), text: "A" ); |
| 100 | menu->addAction(icon: genIcon(iconSize: iconSize(), "B" , color: Qt::blue, pixelRatio: dpr), text: "B" ); |
| 101 | menu->addAction(icon: genIcon(iconSize: iconSize(), "C" , color: Qt::blue, pixelRatio: dpr), text: "C" ); |
| 102 | addAction(action: menu->menuAction()); |
| 103 | |
| 104 | QAction *two = addAction(icon: genIcon(iconSize: iconSize(), number: 2, color: Qt::white, pixelRatio: dpr), text: "Two" ); |
| 105 | QFont boldFont; |
| 106 | boldFont.setBold(true); |
| 107 | two->setFont(boldFont); |
| 108 | |
| 109 | addAction(icon: genIcon(iconSize: iconSize(), number: 3, color: Qt::red, pixelRatio: dpr), text: "Three" ); |
| 110 | addAction(icon: genIcon(iconSize: iconSize(), number: 4, color: Qt::green, pixelRatio: dpr), text: "Four" ); |
| 111 | addAction(icon: genIcon(iconSize: iconSize(), number: 5, color: Qt::blue, pixelRatio: dpr), text: "Five" ); |
| 112 | addAction(icon: genIcon(iconSize: iconSize(), number: 6, color: Qt::yellow, pixelRatio: dpr), text: "Six" ); |
| 113 | orderAction = new QAction(this); |
| 114 | orderAction->setText(tr(s: "Order Items in Tool Bar" )); |
| 115 | connect(sender: orderAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::order); |
| 116 | |
| 117 | randomizeAction = new QAction(this); |
| 118 | randomizeAction->setText(tr(s: "Randomize Items in Tool Bar" )); |
| 119 | connect(sender: randomizeAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::randomize); |
| 120 | |
| 121 | addSpinBoxAction = new QAction(this); |
| 122 | addSpinBoxAction->setText(tr(s: "Add Spin Box" )); |
| 123 | connect(sender: addSpinBoxAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::addSpinBox); |
| 124 | |
| 125 | removeSpinBoxAction = new QAction(this); |
| 126 | removeSpinBoxAction->setText(tr(s: "Remove Spin Box" )); |
| 127 | removeSpinBoxAction->setEnabled(false); |
| 128 | connect(sender: removeSpinBoxAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::removeSpinBox); |
| 129 | |
| 130 | movableAction = new QAction(tr(s: "Movable" ), this); |
| 131 | movableAction->setCheckable(true); |
| 132 | connect(sender: movableAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::changeMovable); |
| 133 | |
| 134 | allowedAreasActions = new QActionGroup(this); |
| 135 | allowedAreasActions->setExclusive(false); |
| 136 | |
| 137 | allowLeftAction = new QAction(tr(s: "Allow on Left" ), this); |
| 138 | allowLeftAction->setCheckable(true); |
| 139 | connect(sender: allowLeftAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::allowLeft); |
| 140 | |
| 141 | allowRightAction = new QAction(tr(s: "Allow on Right" ), this); |
| 142 | allowRightAction->setCheckable(true); |
| 143 | connect(sender: allowRightAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::allowRight); |
| 144 | |
| 145 | allowTopAction = new QAction(tr(s: "Allow on Top" ), this); |
| 146 | allowTopAction->setCheckable(true); |
| 147 | connect(sender: allowTopAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::allowTop); |
| 148 | |
| 149 | allowBottomAction = new QAction(tr(s: "Allow on Bottom" ), this); |
| 150 | allowBottomAction->setCheckable(true); |
| 151 | connect(sender: allowBottomAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::allowBottom); |
| 152 | |
| 153 | allowedAreasActions->addAction(a: allowLeftAction); |
| 154 | allowedAreasActions->addAction(a: allowRightAction); |
| 155 | allowedAreasActions->addAction(a: allowTopAction); |
| 156 | allowedAreasActions->addAction(a: allowBottomAction); |
| 157 | |
| 158 | areaActions = new QActionGroup(this); |
| 159 | areaActions->setExclusive(true); |
| 160 | |
| 161 | leftAction = new QAction(tr(s: "Place on Left" ) , this); |
| 162 | leftAction->setCheckable(true); |
| 163 | connect(sender: leftAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::placeLeft); |
| 164 | |
| 165 | rightAction = new QAction(tr(s: "Place on Right" ) , this); |
| 166 | rightAction->setCheckable(true); |
| 167 | connect(sender: rightAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::placeRight); |
| 168 | |
| 169 | topAction = new QAction(tr(s: "Place on Top" ) , this); |
| 170 | topAction->setCheckable(true); |
| 171 | connect(sender: topAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::placeTop); |
| 172 | |
| 173 | bottomAction = new QAction(tr(s: "Place on Bottom" ) , this); |
| 174 | bottomAction->setCheckable(true); |
| 175 | connect(sender: bottomAction, signal: &QAction::triggered, receiver: this, slot: &ToolBar::placeBottom); |
| 176 | |
| 177 | areaActions->addAction(a: leftAction); |
| 178 | areaActions->addAction(a: rightAction); |
| 179 | areaActions->addAction(a: topAction); |
| 180 | areaActions->addAction(a: bottomAction); |
| 181 | |
| 182 | connect(sender: movableAction, signal: &QAction::triggered, receiver: areaActions, slot: &QActionGroup::setEnabled); |
| 183 | |
| 184 | connect(sender: movableAction, signal: &QAction::triggered, receiver: allowedAreasActions, slot: &QActionGroup::setEnabled); |
| 185 | |
| 186 | menu = new QMenu(title, this); |
| 187 | menu->addAction(action: toggleViewAction()); |
| 188 | menu->addSeparator(); |
| 189 | menu->addAction(action: orderAction); |
| 190 | menu->addAction(action: randomizeAction); |
| 191 | menu->addSeparator(); |
| 192 | menu->addAction(action: addSpinBoxAction); |
| 193 | menu->addAction(action: removeSpinBoxAction); |
| 194 | menu->addSeparator(); |
| 195 | menu->addAction(action: movableAction); |
| 196 | menu->addSeparator(); |
| 197 | menu->addActions(actions: allowedAreasActions->actions()); |
| 198 | menu->addSeparator(); |
| 199 | menu->addActions(actions: areaActions->actions()); |
| 200 | menu->addSeparator(); |
| 201 | menu->addAction(text: tr(s: "Insert break" ), object: this, slot: &ToolBar::insertToolBarBreak); |
| 202 | |
| 203 | connect(sender: menu, signal: &QMenu::aboutToShow, receiver: this, slot: &ToolBar::updateMenu); |
| 204 | |
| 205 | randomize(); |
| 206 | } |
| 207 | |
| 208 | void ToolBar::() |
| 209 | { |
| 210 | QMainWindow *mainWindow = qobject_cast<QMainWindow *>(object: parentWidget()); |
| 211 | Q_ASSERT(mainWindow); |
| 212 | |
| 213 | const Qt::ToolBarArea area = mainWindow->toolBarArea(toolbar: this); |
| 214 | const Qt::ToolBarAreas areas = allowedAreas(); |
| 215 | |
| 216 | movableAction->setChecked(isMovable()); |
| 217 | |
| 218 | allowLeftAction->setChecked(isAreaAllowed(area: Qt::LeftToolBarArea)); |
| 219 | allowRightAction->setChecked(isAreaAllowed(area: Qt::RightToolBarArea)); |
| 220 | allowTopAction->setChecked(isAreaAllowed(area: Qt::TopToolBarArea)); |
| 221 | allowBottomAction->setChecked(isAreaAllowed(area: Qt::BottomToolBarArea)); |
| 222 | |
| 223 | if (allowedAreasActions->isEnabled()) { |
| 224 | allowLeftAction->setEnabled(area != Qt::LeftToolBarArea); |
| 225 | allowRightAction->setEnabled(area != Qt::RightToolBarArea); |
| 226 | allowTopAction->setEnabled(area != Qt::TopToolBarArea); |
| 227 | allowBottomAction->setEnabled(area != Qt::BottomToolBarArea); |
| 228 | } |
| 229 | |
| 230 | leftAction->setChecked(area == Qt::LeftToolBarArea); |
| 231 | rightAction->setChecked(area == Qt::RightToolBarArea); |
| 232 | topAction->setChecked(area == Qt::TopToolBarArea); |
| 233 | bottomAction->setChecked(area == Qt::BottomToolBarArea); |
| 234 | |
| 235 | if (areaActions->isEnabled()) { |
| 236 | leftAction->setEnabled(areas & Qt::LeftToolBarArea); |
| 237 | rightAction->setEnabled(areas & Qt::RightToolBarArea); |
| 238 | topAction->setEnabled(areas & Qt::TopToolBarArea); |
| 239 | bottomAction->setEnabled(areas & Qt::BottomToolBarArea); |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | void ToolBar::order() |
| 244 | { |
| 245 | QList<QAction *> ordered; |
| 246 | QList<QAction *> actions1 = actions(); |
| 247 | const QList<QAction *> childActions = findChildren<QAction *>(); |
| 248 | for (QAction *action : childActions) { |
| 249 | if (!actions1.contains(t: action)) |
| 250 | continue; |
| 251 | actions1.removeAll(t: action); |
| 252 | ordered.append(t: action); |
| 253 | } |
| 254 | |
| 255 | clear(); |
| 256 | addActions(actions: ordered); |
| 257 | |
| 258 | orderAction->setEnabled(false); |
| 259 | } |
| 260 | |
| 261 | void ToolBar::randomize() |
| 262 | { |
| 263 | QList<QAction *> randomized; |
| 264 | QList<QAction *> actions = this->actions(); |
| 265 | while (!actions.isEmpty()) { |
| 266 | QAction *action = actions.takeAt(i: QRandomGenerator::global()->bounded(highest: actions.size())); |
| 267 | randomized.append(t: action); |
| 268 | } |
| 269 | clear(); |
| 270 | addActions(actions: randomized); |
| 271 | |
| 272 | orderAction->setEnabled(true); |
| 273 | } |
| 274 | |
| 275 | void ToolBar::addSpinBox() |
| 276 | { |
| 277 | if (!spinbox) |
| 278 | spinbox = new QSpinBox(this); |
| 279 | if (!spinboxAction) |
| 280 | spinboxAction = addWidget(widget: spinbox); |
| 281 | else |
| 282 | addAction(action: spinboxAction); |
| 283 | |
| 284 | addSpinBoxAction->setEnabled(false); |
| 285 | removeSpinBoxAction->setEnabled(true); |
| 286 | } |
| 287 | |
| 288 | void ToolBar::removeSpinBox() |
| 289 | { |
| 290 | if (spinboxAction) |
| 291 | removeAction(action: spinboxAction); |
| 292 | |
| 293 | addSpinBoxAction->setEnabled(true); |
| 294 | removeSpinBoxAction->setEnabled(false); |
| 295 | } |
| 296 | |
| 297 | void ToolBar::allow(Qt::ToolBarArea area, bool a) |
| 298 | { |
| 299 | Qt::ToolBarAreas areas = allowedAreas(); |
| 300 | areas = a ? areas | area : areas & ~area; |
| 301 | setAllowedAreas(areas); |
| 302 | |
| 303 | if (areaActions->isEnabled()) { |
| 304 | leftAction->setEnabled(areas & Qt::LeftToolBarArea); |
| 305 | rightAction->setEnabled(areas & Qt::RightToolBarArea); |
| 306 | topAction->setEnabled(areas & Qt::TopToolBarArea); |
| 307 | bottomAction->setEnabled(areas & Qt::BottomToolBarArea); |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | void ToolBar::place(Qt::ToolBarArea area, bool p) |
| 312 | { |
| 313 | if (!p) |
| 314 | return; |
| 315 | |
| 316 | QMainWindow *mainWindow = qobject_cast<QMainWindow *>(object: parentWidget()); |
| 317 | Q_ASSERT(mainWindow); |
| 318 | |
| 319 | mainWindow->addToolBar(area, toolbar: this); |
| 320 | |
| 321 | if (allowedAreasActions->isEnabled()) { |
| 322 | allowLeftAction->setEnabled(area != Qt::LeftToolBarArea); |
| 323 | allowRightAction->setEnabled(area != Qt::RightToolBarArea); |
| 324 | allowTopAction->setEnabled(area != Qt::TopToolBarArea); |
| 325 | allowBottomAction->setEnabled(area != Qt::BottomToolBarArea); |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | void ToolBar::changeMovable(bool movable) |
| 330 | { setMovable(movable); } |
| 331 | |
| 332 | void ToolBar::allowLeft(bool a) |
| 333 | { allow(area: Qt::LeftToolBarArea, a); } |
| 334 | |
| 335 | void ToolBar::allowRight(bool a) |
| 336 | { allow(area: Qt::RightToolBarArea, a); } |
| 337 | |
| 338 | void ToolBar::allowTop(bool a) |
| 339 | { allow(area: Qt::TopToolBarArea, a); } |
| 340 | |
| 341 | void ToolBar::allowBottom(bool a) |
| 342 | { allow(area: Qt::BottomToolBarArea, a); } |
| 343 | |
| 344 | void ToolBar::placeLeft(bool p) |
| 345 | { place(area: Qt::LeftToolBarArea, p); } |
| 346 | |
| 347 | void ToolBar::placeRight(bool p) |
| 348 | { place(area: Qt::RightToolBarArea, p); } |
| 349 | |
| 350 | void ToolBar::placeTop(bool p) |
| 351 | { place(area: Qt::TopToolBarArea, p); } |
| 352 | |
| 353 | void ToolBar::placeBottom(bool p) |
| 354 | { place(area: Qt::BottomToolBarArea, p); } |
| 355 | |
| 356 | void ToolBar::insertToolBarBreak() |
| 357 | { |
| 358 | QMainWindow *mainWindow = qobject_cast<QMainWindow *>(object: parentWidget()); |
| 359 | Q_ASSERT(mainWindow); |
| 360 | |
| 361 | mainWindow->insertToolBarBreak(before: this); |
| 362 | } |
| 363 | |