| 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 examples 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 "arrow.h" | 
| 52 | #include "diagramitem.h" | 
| 53 | #include "diagramscene.h" | 
| 54 | #include "diagramtextitem.h" | 
| 55 | #include "mainwindow.h" | 
| 56 |  | 
| 57 | #include <QtWidgets> | 
| 58 |  | 
| 59 | const int InsertTextButton = 10; | 
| 60 |  | 
| 61 | //! [0] | 
| 62 | MainWindow::MainWindow() | 
| 63 | { | 
| 64 |     createActions(); | 
| 65 |     createToolBox(); | 
| 66 |     createMenus(); | 
| 67 |  | 
| 68 |     scene = new DiagramScene(itemMenu, this); | 
| 69 |     scene->setSceneRect(QRectF(0, 0, 5000, 5000)); | 
| 70 |     connect(sender: scene, signal: &DiagramScene::itemInserted, | 
| 71 |             receiver: this, slot: &MainWindow::itemInserted); | 
| 72 |     connect(sender: scene, signal: &DiagramScene::textInserted, | 
| 73 |             receiver: this, slot: &MainWindow::textInserted); | 
| 74 |     connect(sender: scene, signal: &DiagramScene::itemSelected, | 
| 75 |             receiver: this, slot: &MainWindow::itemSelected); | 
| 76 |     createToolbars(); | 
| 77 |  | 
| 78 |     QHBoxLayout *layout = new QHBoxLayout; | 
| 79 |     layout->addWidget(toolBox); | 
| 80 |     view = new QGraphicsView(scene); | 
| 81 |     layout->addWidget(view); | 
| 82 |  | 
| 83 |     QWidget *widget = new QWidget; | 
| 84 |     widget->setLayout(layout); | 
| 85 |  | 
| 86 |     setCentralWidget(widget); | 
| 87 |     setWindowTitle(tr(s: "Diagramscene" )); | 
| 88 |     setUnifiedTitleAndToolBarOnMac(true); | 
| 89 | } | 
| 90 | //! [0] | 
| 91 |  | 
| 92 | //! [1] | 
| 93 | void MainWindow::backgroundButtonGroupClicked(QAbstractButton *button) | 
| 94 | { | 
| 95 |     const QList<QAbstractButton *> buttons = backgroundButtonGroup->buttons(); | 
| 96 |     for (QAbstractButton *myButton : buttons) { | 
| 97 |         if (myButton != button) | 
| 98 |             button->setChecked(false); | 
| 99 |     } | 
| 100 |     QString text = button->text(); | 
| 101 |     if (text == tr(s: "Blue Grid" )) | 
| 102 |         scene->setBackgroundBrush(QPixmap(":/images/background1.png" )); | 
| 103 |     else if (text == tr(s: "White Grid" )) | 
| 104 |         scene->setBackgroundBrush(QPixmap(":/images/background2.png" )); | 
| 105 |     else if (text == tr(s: "Gray Grid" )) | 
| 106 |         scene->setBackgroundBrush(QPixmap(":/images/background3.png" )); | 
| 107 |     else | 
| 108 |         scene->setBackgroundBrush(QPixmap(":/images/background4.png" )); | 
| 109 |  | 
| 110 |     scene->update(); | 
| 111 |     view->update(); | 
| 112 | } | 
| 113 | //! [1] | 
| 114 |  | 
| 115 | //! [2] | 
| 116 | void MainWindow::buttonGroupClicked(QAbstractButton *button) | 
| 117 | { | 
| 118 |     const QList<QAbstractButton *> buttons = buttonGroup->buttons(); | 
| 119 |     for (QAbstractButton *myButton : buttons) { | 
| 120 |         if (myButton != button) | 
| 121 |             button->setChecked(false); | 
| 122 |     } | 
| 123 |     const int id = buttonGroup->id(button); | 
| 124 |     if (id == InsertTextButton) { | 
| 125 |         scene->setMode(DiagramScene::InsertText); | 
| 126 |     } else { | 
| 127 |         scene->setItemType(DiagramItem::DiagramType(id)); | 
| 128 |         scene->setMode(DiagramScene::InsertItem); | 
| 129 |     } | 
| 130 | } | 
| 131 | //! [2] | 
| 132 |  | 
| 133 | //! [3] | 
| 134 | void MainWindow::deleteItem() | 
| 135 | { | 
| 136 |     QList<QGraphicsItem *> selectedItems = scene->selectedItems(); | 
| 137 |     for (QGraphicsItem *item : qAsConst(t&: selectedItems)) { | 
| 138 |         if (item->type() == Arrow::Type) { | 
| 139 |             scene->removeItem(item); | 
| 140 |             Arrow *arrow = qgraphicsitem_cast<Arrow *>(item); | 
| 141 |             arrow->startItem()->removeArrow(arrow); | 
| 142 |             arrow->endItem()->removeArrow(arrow); | 
| 143 |             delete item; | 
| 144 |         } | 
| 145 |     } | 
| 146 |  | 
| 147 |     selectedItems = scene->selectedItems(); | 
| 148 |     for (QGraphicsItem *item : qAsConst(t&: selectedItems)) { | 
| 149 |          if (item->type() == DiagramItem::Type) | 
| 150 |              qgraphicsitem_cast<DiagramItem *>(item)->removeArrows(); | 
| 151 |          scene->removeItem(item); | 
| 152 |          delete item; | 
| 153 |      } | 
| 154 | } | 
| 155 | //! [3] | 
| 156 |  | 
| 157 | //! [4] | 
| 158 | void MainWindow::pointerGroupClicked() | 
| 159 | { | 
| 160 |     scene->setMode(DiagramScene::Mode(pointerTypeGroup->checkedId())); | 
| 161 | } | 
| 162 | //! [4] | 
| 163 |  | 
| 164 | //! [5] | 
| 165 | void MainWindow::bringToFront() | 
| 166 | { | 
| 167 |     if (scene->selectedItems().isEmpty()) | 
| 168 |         return; | 
| 169 |  | 
| 170 |     QGraphicsItem *selectedItem = scene->selectedItems().first(); | 
| 171 |     const QList<QGraphicsItem *> overlapItems = selectedItem->collidingItems(); | 
| 172 |  | 
| 173 |     qreal zValue = 0; | 
| 174 |     for (const QGraphicsItem *item : overlapItems) { | 
| 175 |         if (item->zValue() >= zValue && item->type() == DiagramItem::Type) | 
| 176 |             zValue = item->zValue() + 0.1; | 
| 177 |     } | 
| 178 |     selectedItem->setZValue(zValue); | 
| 179 | } | 
| 180 | //! [5] | 
| 181 |  | 
| 182 | //! [6] | 
| 183 | void MainWindow::sendToBack() | 
| 184 | { | 
| 185 |     if (scene->selectedItems().isEmpty()) | 
| 186 |         return; | 
| 187 |  | 
| 188 |     QGraphicsItem *selectedItem = scene->selectedItems().first(); | 
| 189 |     const QList<QGraphicsItem *> overlapItems = selectedItem->collidingItems(); | 
| 190 |  | 
| 191 |     qreal zValue = 0; | 
| 192 |     for (const QGraphicsItem *item : overlapItems) { | 
| 193 |         if (item->zValue() <= zValue && item->type() == DiagramItem::Type) | 
| 194 |             zValue = item->zValue() - 0.1; | 
| 195 |     } | 
| 196 |     selectedItem->setZValue(zValue); | 
| 197 | } | 
| 198 | //! [6] | 
| 199 |  | 
| 200 | //! [7] | 
| 201 | void MainWindow::itemInserted(DiagramItem *item) | 
| 202 | { | 
| 203 |     pointerTypeGroup->button(id: int(DiagramScene::MoveItem))->setChecked(true); | 
| 204 |     scene->setMode(DiagramScene::Mode(pointerTypeGroup->checkedId())); | 
| 205 |     buttonGroup->button(id: int(item->diagramType()))->setChecked(false); | 
| 206 | } | 
| 207 | //! [7] | 
| 208 |  | 
| 209 | //! [8] | 
| 210 | void MainWindow::textInserted(QGraphicsTextItem *) | 
| 211 | { | 
| 212 |     buttonGroup->button(id: InsertTextButton)->setChecked(false); | 
| 213 |     scene->setMode(DiagramScene::Mode(pointerTypeGroup->checkedId())); | 
| 214 | } | 
| 215 | //! [8] | 
| 216 |  | 
| 217 | //! [9] | 
| 218 | void MainWindow::currentFontChanged(const QFont &) | 
| 219 | { | 
| 220 |     handleFontChange(); | 
| 221 | } | 
| 222 | //! [9] | 
| 223 |  | 
| 224 | //! [10] | 
| 225 | void MainWindow::fontSizeChanged(const QString &) | 
| 226 | { | 
| 227 |     handleFontChange(); | 
| 228 | } | 
| 229 | //! [10] | 
| 230 |  | 
| 231 | //! [11] | 
| 232 | void MainWindow::sceneScaleChanged(const QString &scale) | 
| 233 | { | 
| 234 |     double newScale = scale.left(n: scale.indexOf(s: tr(s: "%" ))).toDouble() / 100.0; | 
| 235 |     QTransform oldMatrix = view->transform(); | 
| 236 |     view->resetTransform(); | 
| 237 |     view->translate(dx: oldMatrix.dx(), dy: oldMatrix.dy()); | 
| 238 |     view->scale(sx: newScale, sy: newScale); | 
| 239 | } | 
| 240 | //! [11] | 
| 241 |  | 
| 242 | //! [12] | 
| 243 | void MainWindow::textColorChanged() | 
| 244 | { | 
| 245 |     textAction = qobject_cast<QAction *>(object: sender()); | 
| 246 |     fontColorToolButton->setIcon(createColorToolButtonIcon( | 
| 247 |                                      image: ":/images/textpointer.png" , | 
| 248 |                                      color: qvariant_cast<QColor>(v: textAction->data()))); | 
| 249 |     textButtonTriggered(); | 
| 250 | } | 
| 251 | //! [12] | 
| 252 |  | 
| 253 | //! [13] | 
| 254 | void MainWindow::itemColorChanged() | 
| 255 | { | 
| 256 |     fillAction = qobject_cast<QAction *>(object: sender()); | 
| 257 |     fillColorToolButton->setIcon(createColorToolButtonIcon( | 
| 258 |                                      image: ":/images/floodfill.png" , | 
| 259 |                                      color: qvariant_cast<QColor>(v: fillAction->data()))); | 
| 260 |     fillButtonTriggered(); | 
| 261 | } | 
| 262 | //! [13] | 
| 263 |  | 
| 264 | //! [14] | 
| 265 | void MainWindow::lineColorChanged() | 
| 266 | { | 
| 267 |     lineAction = qobject_cast<QAction *>(object: sender()); | 
| 268 |     lineColorToolButton->setIcon(createColorToolButtonIcon( | 
| 269 |                                      image: ":/images/linecolor.png" , | 
| 270 |                                      color: qvariant_cast<QColor>(v: lineAction->data()))); | 
| 271 |     lineButtonTriggered(); | 
| 272 | } | 
| 273 | //! [14] | 
| 274 |  | 
| 275 | //! [15] | 
| 276 | void MainWindow::textButtonTriggered() | 
| 277 | { | 
| 278 |     scene->setTextColor(qvariant_cast<QColor>(v: textAction->data())); | 
| 279 | } | 
| 280 | //! [15] | 
| 281 |  | 
| 282 | //! [16] | 
| 283 | void MainWindow::fillButtonTriggered() | 
| 284 | { | 
| 285 |     scene->setItemColor(qvariant_cast<QColor>(v: fillAction->data())); | 
| 286 | } | 
| 287 | //! [16] | 
| 288 |  | 
| 289 | //! [17] | 
| 290 | void MainWindow::lineButtonTriggered() | 
| 291 | { | 
| 292 |     scene->setLineColor(qvariant_cast<QColor>(v: lineAction->data())); | 
| 293 | } | 
| 294 | //! [17] | 
| 295 |  | 
| 296 | //! [18] | 
| 297 | void MainWindow::handleFontChange() | 
| 298 | { | 
| 299 |     QFont font = fontCombo->currentFont(); | 
| 300 |     font.setPointSize(fontSizeCombo->currentText().toInt()); | 
| 301 |     font.setWeight(boldAction->isChecked() ? QFont::Bold : QFont::Normal); | 
| 302 |     font.setItalic(italicAction->isChecked()); | 
| 303 |     font.setUnderline(underlineAction->isChecked()); | 
| 304 |  | 
| 305 |     scene->setFont(font); | 
| 306 | } | 
| 307 | //! [18] | 
| 308 |  | 
| 309 | //! [19] | 
| 310 | void MainWindow::itemSelected(QGraphicsItem *item) | 
| 311 | { | 
| 312 |     DiagramTextItem *textItem = | 
| 313 |     qgraphicsitem_cast<DiagramTextItem *>(item); | 
| 314 |  | 
| 315 |     QFont font = textItem->font(); | 
| 316 |     fontCombo->setCurrentFont(font); | 
| 317 |     fontSizeCombo->setEditText(QString().setNum(n: font.pointSize())); | 
| 318 |     boldAction->setChecked(font.weight() == QFont::Bold); | 
| 319 |     italicAction->setChecked(font.italic()); | 
| 320 |     underlineAction->setChecked(font.underline()); | 
| 321 | } | 
| 322 | //! [19] | 
| 323 |  | 
| 324 | //! [20] | 
| 325 | void MainWindow::about() | 
| 326 | { | 
| 327 |     QMessageBox::about(parent: this, title: tr(s: "About Diagram Scene" ), | 
| 328 |                        text: tr(s: "The <b>Diagram Scene</b> example shows "  | 
| 329 |                           "use of the graphics framework." )); | 
| 330 | } | 
| 331 | //! [20] | 
| 332 |  | 
| 333 | //! [21] | 
| 334 | void MainWindow::createToolBox() | 
| 335 | { | 
| 336 |     buttonGroup = new QButtonGroup(this); | 
| 337 |     buttonGroup->setExclusive(false); | 
| 338 |     connect(sender: buttonGroup, signal: QOverload<QAbstractButton *>::of(ptr: &QButtonGroup::buttonClicked), | 
| 339 |             receiver: this, slot: &MainWindow::buttonGroupClicked); | 
| 340 |     QGridLayout *layout = new QGridLayout; | 
| 341 |     layout->addWidget(createCellWidget(text: tr(s: "Conditional" ), type: DiagramItem::Conditional), row: 0, column: 0); | 
| 342 |     layout->addWidget(createCellWidget(text: tr(s: "Process" ), type: DiagramItem::Step),row: 0, column: 1); | 
| 343 |     layout->addWidget(createCellWidget(text: tr(s: "Input/Output" ), type: DiagramItem::Io), row: 1, column: 0); | 
| 344 | //! [21] | 
| 345 |  | 
| 346 |     QToolButton *textButton = new QToolButton; | 
| 347 |     textButton->setCheckable(true); | 
| 348 |     buttonGroup->addButton(textButton, id: InsertTextButton); | 
| 349 |     textButton->setIcon(QIcon(QPixmap(":/images/textpointer.png" ))); | 
| 350 |     textButton->setIconSize(QSize(50, 50)); | 
| 351 |     QGridLayout *textLayout = new QGridLayout; | 
| 352 |     textLayout->addWidget(textButton, row: 0, column: 0, Qt::AlignHCenter); | 
| 353 |     textLayout->addWidget(new QLabel(tr(s: "Text" )), row: 1, column: 0, Qt::AlignCenter); | 
| 354 |     QWidget *textWidget = new QWidget; | 
| 355 |     textWidget->setLayout(textLayout); | 
| 356 |     layout->addWidget(textWidget, row: 1, column: 1); | 
| 357 |  | 
| 358 |     layout->setRowStretch(row: 3, stretch: 10); | 
| 359 |     layout->setColumnStretch(column: 2, stretch: 10); | 
| 360 |  | 
| 361 |     QWidget *itemWidget = new QWidget; | 
| 362 |     itemWidget->setLayout(layout); | 
| 363 |  | 
| 364 |     backgroundButtonGroup = new QButtonGroup(this); | 
| 365 |     connect(sender: backgroundButtonGroup, signal: QOverload<QAbstractButton *>::of(ptr: &QButtonGroup::buttonClicked), | 
| 366 |             receiver: this, slot: &MainWindow::backgroundButtonGroupClicked); | 
| 367 |  | 
| 368 |     QGridLayout *backgroundLayout = new QGridLayout; | 
| 369 |     backgroundLayout->addWidget(createBackgroundCellWidget(text: tr(s: "Blue Grid" ), | 
| 370 |                                                            image: ":/images/background1.png" ), row: 0, column: 0); | 
| 371 |     backgroundLayout->addWidget(createBackgroundCellWidget(text: tr(s: "White Grid" ), | 
| 372 |                                                            image: ":/images/background2.png" ), row: 0, column: 1); | 
| 373 |     backgroundLayout->addWidget(createBackgroundCellWidget(text: tr(s: "Gray Grid" ), | 
| 374 |                                                            image: ":/images/background3.png" ), row: 1, column: 0); | 
| 375 |     backgroundLayout->addWidget(createBackgroundCellWidget(text: tr(s: "No Grid" ), | 
| 376 |                                                            image: ":/images/background4.png" ), row: 1, column: 1); | 
| 377 |  | 
| 378 |     backgroundLayout->setRowStretch(row: 2, stretch: 10); | 
| 379 |     backgroundLayout->setColumnStretch(column: 2, stretch: 10); | 
| 380 |  | 
| 381 |     QWidget *backgroundWidget = new QWidget; | 
| 382 |     backgroundWidget->setLayout(backgroundLayout); | 
| 383 |  | 
| 384 |  | 
| 385 | //! [22] | 
| 386 |     toolBox = new QToolBox; | 
| 387 |     toolBox->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored)); | 
| 388 |     toolBox->setMinimumWidth(itemWidget->sizeHint().width()); | 
| 389 |     toolBox->addItem(item: itemWidget, text: tr(s: "Basic Flowchart Shapes" )); | 
| 390 |     toolBox->addItem(item: backgroundWidget, text: tr(s: "Backgrounds" )); | 
| 391 | } | 
| 392 | //! [22] | 
| 393 |  | 
| 394 | //! [23] | 
| 395 | void MainWindow::createActions() | 
| 396 | { | 
| 397 |     toFrontAction = new QAction(QIcon(":/images/bringtofront.png" ), | 
| 398 |                                 tr(s: "Bring to &Front" ), this); | 
| 399 |     toFrontAction->setShortcut(tr(s: "Ctrl+F" )); | 
| 400 |     toFrontAction->setStatusTip(tr(s: "Bring item to front" )); | 
| 401 |     connect(sender: toFrontAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::bringToFront); | 
| 402 | //! [23] | 
| 403 |  | 
| 404 |     sendBackAction = new QAction(QIcon(":/images/sendtoback.png" ), tr(s: "Send to &Back" ), this); | 
| 405 |     sendBackAction->setShortcut(tr(s: "Ctrl+T" )); | 
| 406 |     sendBackAction->setStatusTip(tr(s: "Send item to back" )); | 
| 407 |     connect(sender: sendBackAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::sendToBack); | 
| 408 |  | 
| 409 |     deleteAction = new QAction(QIcon(":/images/delete.png" ), tr(s: "&Delete" ), this); | 
| 410 |     deleteAction->setShortcut(tr(s: "Delete" )); | 
| 411 |     deleteAction->setStatusTip(tr(s: "Delete item from diagram" )); | 
| 412 |     connect(sender: deleteAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::deleteItem); | 
| 413 |  | 
| 414 |     exitAction = new QAction(tr(s: "E&xit" ), this); | 
| 415 |     exitAction->setShortcuts(QKeySequence::Quit); | 
| 416 |     exitAction->setStatusTip(tr(s: "Quit Scenediagram example" )); | 
| 417 |     connect(sender: exitAction, signal: &QAction::triggered, receiver: this, slot: &QWidget::close); | 
| 418 |  | 
| 419 |     boldAction = new QAction(tr(s: "Bold" ), this); | 
| 420 |     boldAction->setCheckable(true); | 
| 421 |     QPixmap pixmap(":/images/bold.png" ); | 
| 422 |     boldAction->setIcon(QIcon(pixmap)); | 
| 423 |     boldAction->setShortcut(tr(s: "Ctrl+B" )); | 
| 424 |     connect(sender: boldAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::handleFontChange); | 
| 425 |  | 
| 426 |     italicAction = new QAction(QIcon(":/images/italic.png" ), tr(s: "Italic" ), this); | 
| 427 |     italicAction->setCheckable(true); | 
| 428 |     italicAction->setShortcut(tr(s: "Ctrl+I" )); | 
| 429 |     connect(sender: italicAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::handleFontChange); | 
| 430 |  | 
| 431 |     underlineAction = new QAction(QIcon(":/images/underline.png" ), tr(s: "Underline" ), this); | 
| 432 |     underlineAction->setCheckable(true); | 
| 433 |     underlineAction->setShortcut(tr(s: "Ctrl+U" )); | 
| 434 |     connect(sender: underlineAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::handleFontChange); | 
| 435 |  | 
| 436 |     aboutAction = new QAction(tr(s: "A&bout" ), this); | 
| 437 |     aboutAction->setShortcut(tr(s: "F1" )); | 
| 438 |     connect(sender: aboutAction, signal: &QAction::triggered, receiver: this, slot: &MainWindow::about); | 
| 439 | } | 
| 440 |  | 
| 441 | //! [24] | 
| 442 | void MainWindow::createMenus() | 
| 443 | { | 
| 444 |     fileMenu = menuBar()->addMenu(title: tr(s: "&File" )); | 
| 445 |     fileMenu->addAction(action: exitAction); | 
| 446 |  | 
| 447 |     itemMenu = menuBar()->addMenu(title: tr(s: "&Item" )); | 
| 448 |     itemMenu->addAction(action: deleteAction); | 
| 449 |     itemMenu->addSeparator(); | 
| 450 |     itemMenu->addAction(action: toFrontAction); | 
| 451 |     itemMenu->addAction(action: sendBackAction); | 
| 452 |  | 
| 453 |     aboutMenu = menuBar()->addMenu(title: tr(s: "&Help" )); | 
| 454 |     aboutMenu->addAction(action: aboutAction); | 
| 455 | } | 
| 456 | //! [24] | 
| 457 |  | 
| 458 | //! [25] | 
| 459 | void MainWindow::createToolbars() | 
| 460 | { | 
| 461 | //! [25] | 
| 462 |     editToolBar = addToolBar(title: tr(s: "Edit" )); | 
| 463 |     editToolBar->addAction(action: deleteAction); | 
| 464 |     editToolBar->addAction(action: toFrontAction); | 
| 465 |     editToolBar->addAction(action: sendBackAction); | 
| 466 |  | 
| 467 |     fontCombo = new QFontComboBox(); | 
| 468 |     connect(sender: fontCombo, signal: &QFontComboBox::currentFontChanged, | 
| 469 |             receiver: this, slot: &MainWindow::currentFontChanged); | 
| 470 |  | 
| 471 |     fontSizeCombo = new QComboBox; | 
| 472 |     fontSizeCombo->setEditable(true); | 
| 473 |     for (int i = 8; i < 30; i = i + 2) | 
| 474 |         fontSizeCombo->addItem(atext: QString().setNum(n: i)); | 
| 475 |     QIntValidator *validator = new QIntValidator(2, 64, this); | 
| 476 |     fontSizeCombo->setValidator(validator); | 
| 477 |     connect(sender: fontSizeCombo, signal: &QComboBox::currentTextChanged, | 
| 478 |             receiver: this, slot: &MainWindow::fontSizeChanged); | 
| 479 |  | 
| 480 |     fontColorToolButton = new QToolButton; | 
| 481 |     fontColorToolButton->setPopupMode(QToolButton::MenuButtonPopup); | 
| 482 |     fontColorToolButton->setMenu(createColorMenu(SLOT(textColorChanged()), defaultColor: Qt::black)); | 
| 483 |     textAction = fontColorToolButton->menu()->defaultAction(); | 
| 484 |     fontColorToolButton->setIcon(createColorToolButtonIcon(image: ":/images/textpointer.png" , color: Qt::black)); | 
| 485 |     fontColorToolButton->setAutoFillBackground(true); | 
| 486 |     connect(sender: fontColorToolButton, signal: &QAbstractButton::clicked, | 
| 487 |             receiver: this, slot: &MainWindow::textButtonTriggered); | 
| 488 |  | 
| 489 | //! [26] | 
| 490 |     fillColorToolButton = new QToolButton; | 
| 491 |     fillColorToolButton->setPopupMode(QToolButton::MenuButtonPopup); | 
| 492 |     fillColorToolButton->setMenu(createColorMenu(SLOT(itemColorChanged()), defaultColor: Qt::white)); | 
| 493 |     fillAction = fillColorToolButton->menu()->defaultAction(); | 
| 494 |     fillColorToolButton->setIcon(createColorToolButtonIcon( | 
| 495 |                                      image: ":/images/floodfill.png" , color: Qt::white)); | 
| 496 |     connect(sender: fillColorToolButton, signal: &QAbstractButton::clicked, | 
| 497 |             receiver: this, slot: &MainWindow::fillButtonTriggered); | 
| 498 | //! [26] | 
| 499 |  | 
| 500 |     lineColorToolButton = new QToolButton; | 
| 501 |     lineColorToolButton->setPopupMode(QToolButton::MenuButtonPopup); | 
| 502 |     lineColorToolButton->setMenu(createColorMenu(SLOT(lineColorChanged()), defaultColor: Qt::black)); | 
| 503 |     lineAction = lineColorToolButton->menu()->defaultAction(); | 
| 504 |     lineColorToolButton->setIcon(createColorToolButtonIcon( | 
| 505 |                                      image: ":/images/linecolor.png" , color: Qt::black)); | 
| 506 |     connect(sender: lineColorToolButton, signal: &QAbstractButton::clicked, | 
| 507 |             receiver: this, slot: &MainWindow::lineButtonTriggered); | 
| 508 |  | 
| 509 |     textToolBar = addToolBar(title: tr(s: "Font" )); | 
| 510 |     textToolBar->addWidget(widget: fontCombo); | 
| 511 |     textToolBar->addWidget(widget: fontSizeCombo); | 
| 512 |     textToolBar->addAction(action: boldAction); | 
| 513 |     textToolBar->addAction(action: italicAction); | 
| 514 |     textToolBar->addAction(action: underlineAction); | 
| 515 |  | 
| 516 |     colorToolBar = addToolBar(title: tr(s: "Color" )); | 
| 517 |     colorToolBar->addWidget(widget: fontColorToolButton); | 
| 518 |     colorToolBar->addWidget(widget: fillColorToolButton); | 
| 519 |     colorToolBar->addWidget(widget: lineColorToolButton); | 
| 520 |  | 
| 521 |     QToolButton *pointerButton = new QToolButton; | 
| 522 |     pointerButton->setCheckable(true); | 
| 523 |     pointerButton->setChecked(true); | 
| 524 |     pointerButton->setIcon(QIcon(":/images/pointer.png" )); | 
| 525 |     QToolButton *linePointerButton = new QToolButton; | 
| 526 |     linePointerButton->setCheckable(true); | 
| 527 |     linePointerButton->setIcon(QIcon(":/images/linepointer.png" )); | 
| 528 |  | 
| 529 |     pointerTypeGroup = new QButtonGroup(this); | 
| 530 |     pointerTypeGroup->addButton(pointerButton, id: int(DiagramScene::MoveItem)); | 
| 531 |     pointerTypeGroup->addButton(linePointerButton, id: int(DiagramScene::InsertLine)); | 
| 532 |     connect(sender: pointerTypeGroup, signal: QOverload<QAbstractButton *>::of(ptr: &QButtonGroup::buttonClicked), | 
| 533 |             receiver: this, slot: &MainWindow::pointerGroupClicked); | 
| 534 |  | 
| 535 |     sceneScaleCombo = new QComboBox; | 
| 536 |     QStringList scales; | 
| 537 |     scales << tr(s: "50%" ) << tr(s: "75%" ) << tr(s: "100%" ) << tr(s: "125%" ) << tr(s: "150%" ); | 
| 538 |     sceneScaleCombo->addItems(texts: scales); | 
| 539 |     sceneScaleCombo->setCurrentIndex(2); | 
| 540 |     connect(sender: sceneScaleCombo, signal: &QComboBox::currentTextChanged, | 
| 541 |             receiver: this, slot: &MainWindow::sceneScaleChanged); | 
| 542 |  | 
| 543 |     pointerToolbar = addToolBar(title: tr(s: "Pointer type" )); | 
| 544 |     pointerToolbar->addWidget(widget: pointerButton); | 
| 545 |     pointerToolbar->addWidget(widget: linePointerButton); | 
| 546 |     pointerToolbar->addWidget(widget: sceneScaleCombo); | 
| 547 | //! [27] | 
| 548 | } | 
| 549 | //! [27] | 
| 550 |  | 
| 551 | //! [28] | 
| 552 | QWidget *MainWindow::createBackgroundCellWidget(const QString &text, const QString &image) | 
| 553 | { | 
| 554 |     QToolButton *button = new QToolButton; | 
| 555 |     button->setText(text); | 
| 556 |     button->setIcon(QIcon(image)); | 
| 557 |     button->setIconSize(QSize(50, 50)); | 
| 558 |     button->setCheckable(true); | 
| 559 |     backgroundButtonGroup->addButton(button); | 
| 560 |  | 
| 561 |     QGridLayout *layout = new QGridLayout; | 
| 562 |     layout->addWidget(button, row: 0, column: 0, Qt::AlignHCenter); | 
| 563 |     layout->addWidget(new QLabel(text), row: 1, column: 0, Qt::AlignCenter); | 
| 564 |  | 
| 565 |     QWidget *widget = new QWidget; | 
| 566 |     widget->setLayout(layout); | 
| 567 |  | 
| 568 |     return widget; | 
| 569 | } | 
| 570 | //! [28] | 
| 571 |  | 
| 572 | //! [29] | 
| 573 | QWidget *MainWindow::createCellWidget(const QString &text, DiagramItem::DiagramType type) | 
| 574 | { | 
| 575 |  | 
| 576 |     DiagramItem item(type, itemMenu); | 
| 577 |     QIcon icon(item.image()); | 
| 578 |  | 
| 579 |     QToolButton *button = new QToolButton; | 
| 580 |     button->setIcon(icon); | 
| 581 |     button->setIconSize(QSize(50, 50)); | 
| 582 |     button->setCheckable(true); | 
| 583 |     buttonGroup->addButton(button, id: int(type)); | 
| 584 |  | 
| 585 |     QGridLayout *layout = new QGridLayout; | 
| 586 |     layout->addWidget(button, row: 0, column: 0, Qt::AlignHCenter); | 
| 587 |     layout->addWidget(new QLabel(text), row: 1, column: 0, Qt::AlignCenter); | 
| 588 |  | 
| 589 |     QWidget *widget = new QWidget; | 
| 590 |     widget->setLayout(layout); | 
| 591 |  | 
| 592 |     return widget; | 
| 593 | } | 
| 594 | //! [29] | 
| 595 |  | 
| 596 | //! [30] | 
| 597 | QMenu *MainWindow::createColorMenu(const char *slot, QColor defaultColor) | 
| 598 | { | 
| 599 |     QList<QColor> colors; | 
| 600 |     colors << Qt::black << Qt::white << Qt::red << Qt::blue << Qt::yellow; | 
| 601 |     QStringList names; | 
| 602 |     names << tr(s: "black" ) << tr(s: "white" ) << tr(s: "red" ) << tr(s: "blue" ) | 
| 603 |           << tr(s: "yellow" ); | 
| 604 |  | 
| 605 |     QMenu * = new QMenu(this); | 
| 606 |     for (int i = 0; i < colors.count(); ++i) { | 
| 607 |         QAction *action = new QAction(names.at(i), this); | 
| 608 |         action->setData(colors.at(i)); | 
| 609 |         action->setIcon(createColorIcon(color: colors.at(i))); | 
| 610 |         connect(sender: action, SIGNAL(triggered()), receiver: this, member: slot); | 
| 611 |         colorMenu->addAction(action); | 
| 612 |         if (colors.at(i) == defaultColor) | 
| 613 |             colorMenu->setDefaultAction(action); | 
| 614 |     } | 
| 615 |     return colorMenu; | 
| 616 | } | 
| 617 | //! [30] | 
| 618 |  | 
| 619 | //! [31] | 
| 620 | QIcon MainWindow::createColorToolButtonIcon(const QString &imageFile, QColor color) | 
| 621 | { | 
| 622 |     QPixmap pixmap(50, 80); | 
| 623 |     pixmap.fill(fillColor: Qt::transparent); | 
| 624 |     QPainter painter(&pixmap); | 
| 625 |     QPixmap image(imageFile); | 
| 626 |     // Draw icon centred horizontally on button. | 
| 627 |     QRect target(4, 0, 42, 43); | 
| 628 |     QRect source(0, 0, 42, 43); | 
| 629 |     painter.fillRect(QRect(0, 60, 50, 80), color); | 
| 630 |     painter.drawPixmap(targetRect: target, pixmap: image, sourceRect: source); | 
| 631 |  | 
| 632 |     return QIcon(pixmap); | 
| 633 | } | 
| 634 | //! [31] | 
| 635 |  | 
| 636 | //! [32] | 
| 637 | QIcon MainWindow::createColorIcon(QColor color) | 
| 638 | { | 
| 639 |     QPixmap pixmap(20, 20); | 
| 640 |     QPainter painter(&pixmap); | 
| 641 |     painter.setPen(Qt::NoPen); | 
| 642 |     painter.fillRect(QRect(0, 0, 20, 20), color); | 
| 643 |  | 
| 644 |     return QIcon(pixmap); | 
| 645 | } | 
| 646 | //! [32] | 
| 647 |  |