diff --git a/app/integrated_platform.pro b/app/integrated_platform.pro index a4949a2..dffe7f8 100644 --- a/app/integrated_platform.pro +++ b/app/integrated_platform.pro @@ -23,6 +23,7 @@ SOURCES += \ src/ui/plc_connection_dialog.cpp \ src/ui/free_monitor_widget.cpp \ src/ui/runtime_monitor_widget.cpp \ + src/ui/toolbar_icon_factory.cpp \ src/ui/project_workspace_controller.cpp \ src/ui/property_panel_controller.cpp \ src/ui/runtime_panel_controller.cpp \ @@ -63,6 +64,7 @@ HEADERS += \ src/ui/plc_connection_dialog.h \ src/ui/free_monitor_widget.h \ src/ui/runtime_monitor_widget.h \ + src/ui/toolbar_icon_factory.h \ src/ui/project_workspace_controller.h \ src/ui/property_panel_controller.h \ src/ui/runtime_panel_controller.h \ diff --git a/app/src/ui/free_monitor_widget.cpp b/app/src/ui/free_monitor_widget.cpp index 42d8a04..aa089ce 100644 --- a/app/src/ui/free_monitor_widget.cpp +++ b/app/src/ui/free_monitor_widget.cpp @@ -1,11 +1,11 @@ #include "free_monitor_widget.h" #include "services/register_monitor_service.h" +#include "toolbar_icon_factory.h" #include "ui_free_monitor_widget.h" #include #include -#include #include #include @@ -32,8 +32,8 @@ FreeMonitorWidget::FreeMonitorWidget( service_(service) { ui_->setupUi(this); - ui_->removeButton->setIcon(style()->standardIcon(QStyle::SP_TrashIcon)); - ui_->clearButton->setIcon(style()->standardIcon(QStyle::SP_DialogResetButton)); + ui_->removeButton->setIcon(makeUiIcon(UiIcon::Delete)); + ui_->clearButton->setIcon(makeUiIcon(UiIcon::ClearList)); ui_->monitorTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); ui_->monitorTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents); ui_->monitorTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); diff --git a/app/src/ui/main_window.cpp b/app/src/ui/main_window.cpp index cee1941..840abf3 100644 --- a/app/src/ui/main_window.cpp +++ b/app/src/ui/main_window.cpp @@ -7,6 +7,7 @@ #include "logic_instruction_dialog.h" #include "plc_connection_dialog.h" #include "runtime_monitor_widget.h" +#include "toolbar_icon_factory.h" #include "project_workspace_controller.h" #include "property_panel_controller.h" #include "runtime_panel_controller.h" @@ -26,12 +27,13 @@ #include #include #include +#include #include #include #include #include -#include #include +#include #include namespace { @@ -135,6 +137,27 @@ QString plcStatusText(const RuntimeModeService &service) } } +QToolButton *addToolbarMenu( + QToolBar *toolbar, + const QString &text, + const QString &object_name, + const QIcon &icon, + const QList &actions) +{ + auto *button = new QToolButton(toolbar); + button->setObjectName(object_name); + button->setText(text); + button->setIcon(icon); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + button->setPopupMode(QToolButton::InstantPopup); + + auto *menu = new QMenu(button); + menu->addActions(actions); + button->setMenu(menu); + toolbar->addWidget(button); + return button; +} + } // namespace MainWindow::MainWindow( @@ -289,6 +312,16 @@ void MainWindow::configureActions() [this] { addHmiControl(HmiControlType::AlarmList); }); connect(ui_->deleteControlAction, &QAction::triggered, this, &MainWindow::deleteSelectedControl); + addToolbarMenu( + ui_->hmiToolBar, + tr("更多控件"), + QStringLiteral("hmiMoreControlsButton"), + makeUiIcon(UiIcon::More), + QList{ + ui_->addProgressBarAction, + ui_->addPageJumpAction, + ui_->addAlarmListAction, + ui_->configureAlarmsAction}); connect(ui_->addRungAction, &QAction::triggered, this, &MainWindow::addLogicRung); @@ -525,6 +558,38 @@ void MainWindow::configureActions() this, &MainWindow::deleteSelectedLogicObject); connect(ui_->editRungCommentAction, &QAction::triggered, this, &MainWindow::editSelectedRungComment); + addToolbarMenu( + ui_->logicToolBar, + tr("更多触点"), + QStringLiteral("logicContactMenuButton"), + makeUiIcon(UiIcon::NormallyOpenContact), + QList{ + ui_->addRisingEdgeAction, + ui_->addFallingEdgeAction, + ui_->addTimerContactAction, + ui_->addCounterContactAction}); + addToolbarMenu( + ui_->logicToolBar, + tr("更多输出"), + QStringLiteral("logicOutputMenuButton"), + makeUiIcon(UiIcon::Coil), + QList{ui_->addSetCoilAction, ui_->addResetCoilAction}); + addToolbarMenu( + ui_->logicToolBar, + tr("定时/计数"), + QStringLiteral("logicTimerCounterMenuButton"), + makeUiIcon(UiIcon::Ton), + QList{ui_->addTonAction, ui_->addCtuAction, ui_->addCtdAction}); + addToolbarMenu( + ui_->logicToolBar, + tr("数据运算"), + QStringLiteral("logicDataMenuButton"), + makeUiIcon(UiIcon::Move), + QList{ + ui_->addMoveAction, + ui_->addAddAction, + ui_->addSubAction, + ui_->addCompareAction}); connect(ui_->editorTabWidget, &QTabWidget::currentChanged, this, @@ -564,54 +629,51 @@ void MainWindow::configureAppearance() setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - ui_->editingModeAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView)); - ui_->offlineModeAction->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); - ui_->onlineModeAction->setIcon(style()->standardIcon(QStyle::SP_DriveNetIcon)); - ui_->newProjectAction->setIcon(style()->standardIcon(QStyle::SP_FileIcon)); - ui_->saveProjectAction->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton)); - ui_->loadProjectAction->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); - ui_->configurePlcAction->setIcon(style()->standardIcon(QStyle::SP_ComputerIcon)); - ui_->disconnectPlcAction->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton)); - ui_->addButtonAction->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton)); - ui_->addIndicatorAction->setIcon(style()->standardIcon(QStyle::SP_DialogYesButton)); - ui_->addNumericDisplayAction->setIcon( - style()->standardIcon(QStyle::SP_FileDialogInfoView)); - ui_->addNumericInputAction->setIcon( - style()->standardIcon(QStyle::SP_FileDialogContentsView)); - ui_->addProgressBarAction->setIcon( - style()->standardIcon(QStyle::SP_MediaSeekForward)); - ui_->addLabelAction->setIcon( - style()->standardIcon(QStyle::SP_FileDialogInfoView)); - ui_->addPageJumpAction->setIcon( - style()->standardIcon(QStyle::SP_ArrowForward)); - ui_->addAlarmListAction->setIcon( - style()->standardIcon(QStyle::SP_MessageBoxWarning)); - ui_->configureAlarmsAction->setIcon( - style()->standardIcon(QStyle::SP_FileDialogDetailedView)); - ui_->deleteControlAction->setIcon(style()->standardIcon(QStyle::SP_TrashIcon)); - ui_->addRungAction->setIcon(style()->standardIcon(QStyle::SP_FileIcon)); - ui_->parallelInsertAction->setIcon(style()->standardIcon(QStyle::SP_ArrowDown)); - ui_->addNormallyOpenAction->setIcon(style()->standardIcon(QStyle::SP_ArrowRight)); - ui_->addNormallyClosedAction->setIcon(style()->standardIcon(QStyle::SP_ArrowRight)); - ui_->addRisingEdgeAction->setIcon(style()->standardIcon(QStyle::SP_ArrowRight)); - ui_->addFallingEdgeAction->setIcon(style()->standardIcon(QStyle::SP_ArrowRight)); - ui_->addTimerContactAction->setIcon(style()->standardIcon(QStyle::SP_ArrowRight)); - ui_->addCounterContactAction->setIcon(style()->standardIcon(QStyle::SP_ArrowRight)); - ui_->addNormalCoilAction->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton)); - ui_->addSetCoilAction->setIcon(style()->standardIcon(QStyle::SP_DialogYesButton)); - ui_->addResetCoilAction->setIcon(style()->standardIcon(QStyle::SP_DialogNoButton)); - ui_->addTonAction->setIcon(style()->standardIcon(QStyle::SP_BrowserReload)); - ui_->addCtuAction->setIcon(style()->standardIcon(QStyle::SP_ArrowUp)); - ui_->addCtdAction->setIcon(style()->standardIcon(QStyle::SP_ArrowDown)); - ui_->addMoveAction->setIcon(style()->standardIcon(QStyle::SP_ArrowForward)); - ui_->addAddAction->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton)); - ui_->addSubAction->setIcon(style()->standardIcon(QStyle::SP_DialogResetButton)); - ui_->addCompareAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogInfoView)); - ui_->editRungCommentAction->setIcon(style()->standardIcon(QStyle::SP_FileDialogDetailedView)); - ui_->deleteLogicAction->setIcon(style()->standardIcon(QStyle::SP_TrashIcon)); - ui_->editorTabWidget->setTabIcon(0, style()->standardIcon(QStyle::SP_DesktopIcon)); - ui_->editorTabWidget->setTabIcon(1, style()->standardIcon(QStyle::SP_FileDialogListView)); - ui_->editorTabWidget->setTabIcon(2, style()->standardIcon(QStyle::SP_ComputerIcon)); + ui_->editingModeAction->setIcon(makeUiIcon(UiIcon::Edit)); + ui_->offlineModeAction->setIcon(makeUiIcon(UiIcon::RunOffline)); + ui_->onlineModeAction->setIcon(makeUiIcon(UiIcon::RunOnline)); + ui_->newProjectAction->setIcon(makeUiIcon(UiIcon::NewDocument)); + ui_->saveProjectAction->setIcon(makeUiIcon(UiIcon::Save)); + ui_->saveAsProjectAction->setIcon(makeUiIcon(UiIcon::SaveAs)); + ui_->loadProjectAction->setIcon(makeUiIcon(UiIcon::Open)); + ui_->exitAction->setIcon(makeUiIcon(UiIcon::Exit)); + ui_->configurePlcAction->setIcon(makeUiIcon(UiIcon::PlcSettings)); + ui_->disconnectPlcAction->setIcon(makeUiIcon(UiIcon::Disconnect)); + ui_->configureRegisterCommentsAction->setIcon( + makeUiIcon(UiIcon::RegisterComments)); + ui_->addButtonAction->setIcon(makeUiIcon(UiIcon::HmiButton)); + ui_->addIndicatorAction->setIcon(makeUiIcon(UiIcon::Indicator)); + ui_->addNumericDisplayAction->setIcon(makeUiIcon(UiIcon::NumericDisplay)); + ui_->addNumericInputAction->setIcon(makeUiIcon(UiIcon::NumericInput)); + ui_->addProgressBarAction->setIcon(makeUiIcon(UiIcon::ProgressBar)); + ui_->addLabelAction->setIcon(makeUiIcon(UiIcon::Text)); + ui_->addPageJumpAction->setIcon(makeUiIcon(UiIcon::PageJump)); + ui_->addAlarmListAction->setIcon(makeUiIcon(UiIcon::AlarmList)); + ui_->configureAlarmsAction->setIcon(makeUiIcon(UiIcon::AlarmSettings)); + ui_->deleteControlAction->setIcon(makeUiIcon(UiIcon::Delete)); + ui_->addRungAction->setIcon(makeUiIcon(UiIcon::AddRung)); + ui_->parallelInsertAction->setIcon(makeUiIcon(UiIcon::ParallelBranch)); + ui_->addNormallyOpenAction->setIcon(makeUiIcon(UiIcon::NormallyOpenContact)); + ui_->addNormallyClosedAction->setIcon(makeUiIcon(UiIcon::NormallyClosedContact)); + ui_->addRisingEdgeAction->setIcon(makeUiIcon(UiIcon::RisingEdgeContact)); + ui_->addFallingEdgeAction->setIcon(makeUiIcon(UiIcon::FallingEdgeContact)); + ui_->addTimerContactAction->setIcon(makeUiIcon(UiIcon::TimerContact)); + ui_->addCounterContactAction->setIcon(makeUiIcon(UiIcon::CounterContact)); + ui_->addNormalCoilAction->setIcon(makeUiIcon(UiIcon::Coil)); + ui_->addSetCoilAction->setIcon(makeUiIcon(UiIcon::SetCoil)); + ui_->addResetCoilAction->setIcon(makeUiIcon(UiIcon::ResetCoil)); + ui_->addTonAction->setIcon(makeUiIcon(UiIcon::Ton)); + ui_->addCtuAction->setIcon(makeUiIcon(UiIcon::Ctu)); + ui_->addCtdAction->setIcon(makeUiIcon(UiIcon::Ctd)); + ui_->addMoveAction->setIcon(makeUiIcon(UiIcon::Move)); + ui_->addAddAction->setIcon(makeUiIcon(UiIcon::Add)); + ui_->addSubAction->setIcon(makeUiIcon(UiIcon::Subtract)); + ui_->addCompareAction->setIcon(makeUiIcon(UiIcon::Compare)); + ui_->editRungCommentAction->setIcon(makeUiIcon(UiIcon::Comment)); + ui_->deleteLogicAction->setIcon(makeUiIcon(UiIcon::Delete)); + ui_->editorTabWidget->setTabIcon(0, makeUiIcon(UiIcon::HmiPage)); + ui_->editorTabWidget->setTabIcon(1, makeUiIcon(UiIcon::Logic)); + ui_->editorTabWidget->setTabIcon(2, makeUiIcon(UiIcon::Runtime)); ui_->outputDock->setMaximumHeight(220); mode_status_label_ = new QLabel(this); diff --git a/app/src/ui/main_window.ui b/app/src/ui/main_window.ui index 34994dc..4741035 100644 --- a/app/src/ui/main_window.ui +++ b/app/src/ui/main_window.ui @@ -303,11 +303,7 @@ - - - - @@ -329,20 +325,7 @@ - - - - - - - - - - - - - diff --git a/app/src/ui/toolbar_icon_factory.cpp b/app/src/ui/toolbar_icon_factory.cpp new file mode 100644 index 0000000..071416c --- /dev/null +++ b/app/src/ui/toolbar_icon_factory.cpp @@ -0,0 +1,508 @@ +#include "toolbar_icon_factory.h" + +#include +#include +#include +#include + +#include + +namespace { + +const QColor kInk(QStringLiteral("#263842")); +const QColor kAccent(QStringLiteral("#2f7d4a")); +const QColor kAccentFill(QStringLiteral("#dcece3")); +const QColor kWarning(QStringLiteral("#b87808")); +const QColor kDanger(QStringLiteral("#a84545")); +const QColor kPaper(QStringLiteral("#ffffff")); + +QPen iconPen(const QColor &color = kInk, qreal width = 1.7) +{ + QPen pen(color, width); + pen.setCapStyle(Qt::RoundCap); + pen.setJoinStyle(Qt::RoundJoin); + return pen; +} + +void drawCenteredText( + QPainter &painter, + const QRectF &bounds, + const QString &text, + qreal point_size, + const QColor &color = kInk) +{ + QFont font = painter.font(); + font.setFamily(QStringLiteral("Arial")); + font.setPointSizeF(point_size); + font.setBold(true); + painter.setFont(font); + painter.setPen(color); + painter.drawText(bounds, Qt::AlignCenter, text); +} + +void drawPlc(QPainter &painter) +{ + painter.setPen(iconPen()); + painter.setBrush(kPaper); + painter.drawRoundedRect(QRectF(3, 4, 18, 16), 1.5, 1.5); + painter.drawLine(QPointF(8, 4), QPointF(8, 20)); + painter.setBrush(kAccent); + painter.setPen(Qt::NoPen); + painter.drawEllipse(QPointF(5.5, 8), 1.1, 1.1); + painter.drawEllipse(QPointF(5.5, 12), 1.1, 1.1); + painter.setPen(iconPen()); + painter.drawLine(QPointF(11, 8), QPointF(18, 8)); + painter.drawLine(QPointF(11, 12), QPointF(18, 12)); + painter.drawLine(QPointF(11, 16), QPointF(16, 16)); +} + +void drawSave(QPainter &painter) +{ + painter.setPen(iconPen()); + painter.setBrush(kPaper); + painter.drawRoundedRect(QRectF(4, 3, 16, 18), 1.2, 1.2); + painter.drawRect(QRectF(7, 3, 9, 6)); + painter.drawRect(QRectF(7, 13, 10, 8)); +} + +void drawContact(QPainter &painter, const QString &label, bool closed) +{ + painter.setPen(iconPen()); + painter.drawLine(QPointF(2, 12), QPointF(7, 12)); + painter.drawLine(QPointF(17, 12), QPointF(22, 12)); + painter.drawLine(QPointF(8, 7), QPointF(8, 17)); + painter.drawLine(QPointF(16, 7), QPointF(16, 17)); + if (closed) + { + painter.drawLine(QPointF(7, 17), QPointF(17, 7)); + } + if (!label.isEmpty()) + { + drawCenteredText(painter, QRectF(8, 7, 8, 10), label, 5.5); + } +} + +void drawCoil(QPainter &painter, const QString &label) +{ + painter.setPen(iconPen()); + painter.drawLine(QPointF(2, 12), QPointF(6, 12)); + painter.drawLine(QPointF(18, 12), QPointF(22, 12)); + QPainterPath left; + left.moveTo(11, 5); + left.cubicTo(5, 6, 5, 18, 11, 19); + painter.drawPath(left); + QPainterPath right; + right.moveTo(13, 5); + right.cubicTo(19, 6, 19, 18, 13, 19); + painter.drawPath(right); + if (!label.isEmpty()) + { + drawCenteredText(painter, QRectF(8, 7, 8, 10), label, 6.0); + } +} + +void drawInstructionBlock(QPainter &painter, const QString &label) +{ + painter.setPen(iconPen()); + painter.setBrush(kPaper); + painter.drawRoundedRect(QRectF(2.5, 5, 19, 14), 1.5, 1.5); + drawCenteredText(painter, QRectF(3, 5.5, 18, 13), label, 5.5); +} + +QPixmap renderIcon(UiIcon icon, int size) +{ + QPixmap pixmap(size, size); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.scale(static_cast(size) / 24.0, static_cast(size) / 24.0); + painter.setPen(iconPen()); + painter.setBrush(Qt::NoBrush); + + switch (icon) + { + case UiIcon::Edit: + { + painter.drawLine(QPointF(5, 19), QPointF(16.5, 7.5)); + painter.drawLine(QPointF(8, 20), QPointF(19.5, 8.5)); + painter.drawLine(QPointF(16.5, 7.5), QPointF(19.5, 8.5)); + painter.drawLine(QPointF(5, 19), QPointF(4, 21)); + break; + } + case UiIcon::RunOffline: + { + QPainterPath path; + path.moveTo(7, 4); + path.lineTo(20, 12); + path.lineTo(7, 20); + path.closeSubpath(); + painter.setPen(iconPen(kAccent)); + painter.setBrush(kAccentFill); + painter.drawPath(path); + break; + } + case UiIcon::RunOnline: + { + drawPlc(painter); + painter.setPen(Qt::NoPen); + painter.setBrush(kAccent); + QPainterPath path; + path.moveTo(14, 10); + path.lineTo(19, 13); + path.lineTo(14, 16); + path.closeSubpath(); + painter.drawPath(path); + break; + } + case UiIcon::NewDocument: + { + QPainterPath page; + page.moveTo(5, 2); + page.lineTo(15, 2); + page.lineTo(20, 7); + page.lineTo(20, 22); + page.lineTo(5, 22); + page.closeSubpath(); + painter.setBrush(kPaper); + painter.drawPath(page); + painter.drawLine(QPointF(15, 2), QPointF(15, 7)); + painter.drawLine(QPointF(15, 7), QPointF(20, 7)); + painter.drawLine(QPointF(8, 15), QPointF(16, 15)); + painter.drawLine(QPointF(12, 11), QPointF(12, 19)); + break; + } + case UiIcon::Save: + { + drawSave(painter); + break; + } + case UiIcon::SaveAs: + { + drawSave(painter); + painter.setPen(iconPen(kAccent, 2.0)); + painter.drawLine(QPointF(13, 19), QPointF(21, 11)); + break; + } + case UiIcon::Open: + { + painter.setBrush(kPaper); + QPainterPath folder; + folder.moveTo(2, 7); + folder.lineTo(9, 7); + folder.lineTo(11, 10); + folder.lineTo(22, 10); + folder.lineTo(19, 20); + folder.lineTo(3, 20); + folder.closeSubpath(); + painter.setBrush(kAccentFill); + painter.drawPath(folder); + break; + } + case UiIcon::Exit: + { + painter.drawRect(QRectF(4, 3, 10, 18)); + painter.drawLine(QPointF(10, 12), QPointF(22, 12)); + painter.drawLine(QPointF(18, 8), QPointF(22, 12)); + painter.drawLine(QPointF(18, 16), QPointF(22, 12)); + break; + } + case UiIcon::PlcSettings: + { + drawPlc(painter); + painter.setPen(iconPen(kAccent)); + painter.drawEllipse(QPointF(17.5, 16.5), 3.0, 3.0); + painter.drawLine(QPointF(17.5, 12), QPointF(17.5, 14)); + painter.drawLine(QPointF(17.5, 19), QPointF(17.5, 21)); + break; + } + case UiIcon::Disconnect: + { + painter.drawLine(QPointF(3, 12), QPointF(8, 12)); + painter.drawRect(QRectF(8, 8, 4, 8)); + painter.drawLine(QPointF(12, 10), QPointF(15, 10)); + painter.drawLine(QPointF(12, 14), QPointF(15, 14)); + painter.drawRect(QRectF(16, 8, 4, 8)); + painter.drawLine(QPointF(20, 12), QPointF(23, 12)); + painter.setPen(iconPen(kDanger, 2.0)); + painter.drawLine(QPointF(6, 20), QPointF(19, 4)); + break; + } + case UiIcon::RegisterComments: + { + painter.drawRoundedRect(QRectF(3, 3, 18, 18), 1.5, 1.5); + drawCenteredText(painter, QRectF(4, 4, 8, 7), QStringLiteral("M"), 5.0); + drawCenteredText(painter, QRectF(4, 12, 8, 7), QStringLiteral("D"), 5.0); + painter.drawLine(QPointF(13, 8), QPointF(19, 8)); + painter.drawLine(QPointF(13, 16), QPointF(19, 16)); + break; + } + case UiIcon::HmiButton: + { + painter.setBrush(kAccentFill); + painter.drawRoundedRect(QRectF(3, 5, 18, 14), 3, 3); + painter.setBrush(kPaper); + painter.drawEllipse(QPointF(12, 12), 4, 4); + break; + } + case UiIcon::Indicator: + { + painter.setBrush(kAccentFill); + painter.drawEllipse(QPointF(12, 12), 8.5, 8.5); + painter.setBrush(kAccent); + painter.setPen(Qt::NoPen); + painter.drawEllipse(QPointF(12, 12), 4.5, 4.5); + break; + } + case UiIcon::NumericDisplay: + { + painter.drawRoundedRect(QRectF(2, 5, 20, 14), 2, 2); + drawCenteredText(painter, QRectF(3, 6, 18, 12), QStringLiteral("123"), 6.0); + break; + } + case UiIcon::NumericInput: + { + painter.drawRoundedRect(QRectF(2, 5, 20, 14), 2, 2); + drawCenteredText(painter, QRectF(3, 6, 13, 12), QStringLiteral("12"), 6.0); + painter.drawLine(QPointF(18, 7), QPointF(18, 17)); + break; + } + case UiIcon::ProgressBar: + { + painter.drawRoundedRect(QRectF(2, 8, 20, 8), 2, 2); + painter.setPen(Qt::NoPen); + painter.setBrush(kAccent); + painter.drawRoundedRect(QRectF(4, 10, 11, 4), 1, 1); + break; + } + case UiIcon::Text: + { + painter.drawLine(QPointF(5, 5), QPointF(19, 5)); + painter.drawLine(QPointF(12, 5), QPointF(12, 20)); + drawCenteredText(painter, QRectF(7, 6, 10, 14), QStringLiteral("T"), 9.0); + break; + } + case UiIcon::PageJump: + { + painter.drawRect(QRectF(3, 3, 14, 18)); + painter.drawLine(QPointF(9, 12), QPointF(22, 12)); + painter.drawLine(QPointF(18, 8), QPointF(22, 12)); + painter.drawLine(QPointF(18, 16), QPointF(22, 12)); + break; + } + case UiIcon::AlarmList: + { + QPainterPath triangle; + triangle.moveTo(12, 3); + triangle.lineTo(22, 21); + triangle.lineTo(2, 21); + triangle.closeSubpath(); + painter.setPen(iconPen(kWarning)); + painter.setBrush(QColor(QStringLiteral("#fff0d2"))); + painter.drawPath(triangle); + painter.drawLine(QPointF(12, 8), QPointF(12, 14)); + painter.drawPoint(QPointF(12, 17)); + break; + } + case UiIcon::AlarmSettings: + { + painter.setPen(iconPen(kWarning)); + painter.drawArc(QRectF(4, 4, 12, 13), 0, 180 * 16); + painter.drawLine(QPointF(4, 10), QPointF(4, 17)); + painter.drawLine(QPointF(16, 10), QPointF(16, 17)); + painter.drawLine(QPointF(3, 17), QPointF(17, 17)); + painter.drawEllipse(QPointF(18, 17), 3.0, 3.0); + painter.drawLine(QPointF(18, 12), QPointF(18, 14)); + break; + } + case UiIcon::Delete: + { + painter.setPen(iconPen(kDanger)); + painter.drawLine(QPointF(5, 7), QPointF(19, 7)); + painter.drawLine(QPointF(9, 4), QPointF(15, 4)); + painter.drawRoundedRect(QRectF(7, 7, 10, 14), 1, 1); + painter.drawLine(QPointF(10, 10), QPointF(10, 18)); + painter.drawLine(QPointF(14, 10), QPointF(14, 18)); + break; + } + case UiIcon::AddRung: + { + painter.drawLine(QPointF(4, 3), QPointF(4, 21)); + painter.drawLine(QPointF(20, 3), QPointF(20, 21)); + painter.drawLine(QPointF(4, 12), QPointF(20, 12)); + painter.setPen(iconPen(kAccent, 2.0)); + painter.drawLine(QPointF(12, 7), QPointF(12, 17)); + painter.drawLine(QPointF(7, 12), QPointF(17, 12)); + break; + } + case UiIcon::ParallelBranch: + { + painter.drawLine(QPointF(2, 12), QPointF(6, 12)); + painter.drawLine(QPointF(18, 12), QPointF(22, 12)); + painter.drawLine(QPointF(6, 7), QPointF(6, 17)); + painter.drawLine(QPointF(18, 7), QPointF(18, 17)); + painter.drawLine(QPointF(6, 7), QPointF(18, 7)); + painter.drawLine(QPointF(6, 17), QPointF(18, 17)); + painter.setPen(iconPen(kAccent)); + painter.drawLine(QPointF(12, 9), QPointF(12, 15)); + painter.drawLine(QPointF(9, 12), QPointF(15, 12)); + break; + } + case UiIcon::NormallyOpenContact: + { + drawContact(painter, {}, false); + break; + } + case UiIcon::NormallyClosedContact: + { + drawContact(painter, {}, true); + break; + } + case UiIcon::RisingEdgeContact: + { + drawContact(painter, QStringLiteral("P"), false); + break; + } + case UiIcon::FallingEdgeContact: + { + drawContact(painter, QStringLiteral("N"), false); + break; + } + case UiIcon::TimerContact: + { + drawContact(painter, QStringLiteral("T"), false); + break; + } + case UiIcon::CounterContact: + { + drawContact(painter, QStringLiteral("C"), false); + break; + } + case UiIcon::Coil: + { + drawCoil(painter, {}); + break; + } + case UiIcon::SetCoil: + { + drawCoil(painter, QStringLiteral("S")); + break; + } + case UiIcon::ResetCoil: + { + drawCoil(painter, QStringLiteral("R")); + break; + } + case UiIcon::Ton: + { + drawInstructionBlock(painter, QStringLiteral("TON")); + break; + } + case UiIcon::Ctu: + { + drawInstructionBlock(painter, QStringLiteral("CTU")); + break; + } + case UiIcon::Ctd: + { + drawInstructionBlock(painter, QStringLiteral("CTD")); + break; + } + case UiIcon::Move: + { + painter.drawRect(QRectF(2, 6, 6, 12)); + painter.drawRect(QRectF(16, 6, 6, 12)); + painter.drawLine(QPointF(8, 12), QPointF(16, 12)); + painter.drawLine(QPointF(13, 9), QPointF(16, 12)); + painter.drawLine(QPointF(13, 15), QPointF(16, 12)); + break; + } + case UiIcon::Add: + { + drawInstructionBlock(painter, QStringLiteral("+")); + break; + } + case UiIcon::Subtract: + { + drawInstructionBlock(painter, QStringLiteral("-")); + break; + } + case UiIcon::Compare: + { + drawInstructionBlock(painter, QStringLiteral("<>")); + break; + } + case UiIcon::Comment: + { + painter.drawRoundedRect(QRectF(3, 3, 18, 18), 1.5, 1.5); + painter.drawLine(QPointF(7, 8), QPointF(17, 8)); + painter.drawLine(QPointF(7, 12), QPointF(17, 12)); + painter.drawLine(QPointF(7, 16), QPointF(13, 16)); + painter.setPen(iconPen(kAccent, 2.0)); + painter.drawLine(QPointF(14, 19), QPointF(21, 12)); + break; + } + case UiIcon::More: + { + painter.setPen(Qt::NoPen); + painter.setBrush(kInk); + painter.drawEllipse(QPointF(6, 12), 1.7, 1.7); + painter.drawEllipse(QPointF(12, 12), 1.7, 1.7); + painter.drawEllipse(QPointF(18, 12), 1.7, 1.7); + break; + } + case UiIcon::HmiPage: + { + painter.drawRoundedRect(QRectF(2, 4, 20, 14), 1.5, 1.5); + painter.drawLine(QPointF(8, 21), QPointF(16, 21)); + painter.drawLine(QPointF(12, 18), QPointF(12, 21)); + painter.setBrush(kAccentFill); + painter.drawRoundedRect(QRectF(6, 8, 12, 6), 1, 1); + break; + } + case UiIcon::Logic: + { + painter.drawLine(QPointF(3, 3), QPointF(3, 21)); + painter.drawLine(QPointF(21, 3), QPointF(21, 21)); + drawContact(painter, {}, false); + break; + } + case UiIcon::Runtime: + { + painter.drawRoundedRect(QRectF(2, 4, 20, 16), 1.5, 1.5); + QPainterPath pulse; + pulse.moveTo(4, 13); + pulse.lineTo(8, 13); + pulse.lineTo(10, 8); + pulse.lineTo(13, 17); + pulse.lineTo(16, 11); + pulse.lineTo(20, 11); + painter.setPen(iconPen(kAccent)); + painter.drawPath(pulse); + break; + } + case UiIcon::ClearList: + { + painter.drawLine(QPointF(4, 6), QPointF(16, 6)); + painter.drawLine(QPointF(4, 11), QPointF(13, 11)); + painter.drawLine(QPointF(4, 16), QPointF(10, 16)); + painter.setPen(iconPen(kDanger)); + painter.drawLine(QPointF(14, 13), QPointF(21, 20)); + painter.drawLine(QPointF(21, 13), QPointF(14, 20)); + break; + } + } + return pixmap; +} + +} // namespace + +QIcon makeUiIcon(UiIcon icon) +{ + QIcon result; + constexpr std::array sizes{16, 24, 32}; + for (int size : sizes) + { + result.addPixmap(renderIcon(icon, size)); + } + return result; +} diff --git a/app/src/ui/toolbar_icon_factory.h b/app/src/ui/toolbar_icon_factory.h new file mode 100644 index 0000000..e68693d --- /dev/null +++ b/app/src/ui/toolbar_icon_factory.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +enum class UiIcon +{ + Edit, + RunOffline, + RunOnline, + NewDocument, + Save, + SaveAs, + Open, + Exit, + PlcSettings, + Disconnect, + RegisterComments, + HmiButton, + Indicator, + NumericDisplay, + NumericInput, + ProgressBar, + Text, + PageJump, + AlarmList, + AlarmSettings, + Delete, + AddRung, + ParallelBranch, + NormallyOpenContact, + NormallyClosedContact, + RisingEdgeContact, + FallingEdgeContact, + TimerContact, + CounterContact, + Coil, + SetCoil, + ResetCoil, + Ton, + Ctu, + Ctd, + Move, + Add, + Subtract, + Compare, + Comment, + More, + HmiPage, + Logic, + Runtime, + ClearList +}; + +QIcon makeUiIcon(UiIcon icon); diff --git a/app/tests/main_window_tests.cpp b/app/tests/main_window_tests.cpp index 447c8a7..60426a4 100644 --- a/app/tests/main_window_tests.cpp +++ b/app/tests/main_window_tests.cpp @@ -37,8 +37,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -601,6 +603,16 @@ void testModeActionsControlEditingAvailability() QAction *add_progress_bar_action = requiredChild( window, "addProgressBarAction"); QAction *delete_control_action = requiredChild(window, "deleteControlAction"); + QToolButton *hmi_more_controls = requiredChild( + window, "hmiMoreControlsButton"); + QToolButton *logic_contact_menu = requiredChild( + window, "logicContactMenuButton"); + QToolButton *logic_output_menu = requiredChild( + window, "logicOutputMenuButton"); + QToolButton *logic_timer_counter_menu = requiredChild( + window, "logicTimerCounterMenuButton"); + QToolButton *logic_data_menu = requiredChild( + window, "logicDataMenuButton"); QAction *add_normally_open_action = requiredChild( window, "addNormallyOpenAction"); QAction *add_normal_coil_action = requiredChild( @@ -632,8 +644,93 @@ void testModeActionsControlEditingAvailability() QWidget *runtime_hmi = requiredChild(window, "runtimeHmiView"); QWidget *runtime_logic = requiredChild(window, "runtimeLogicView"); QWidget *free_monitor = requiredChild(window, "freeMonitorWidget"); + QTabWidget *editor_tabs = requiredChild(window, "editorTabWidget"); require(!runtime_tab->isVisible(), "runtime monitor workspace must be hidden while editing"); + for (const char *action_name : { + "exitAction", + "newProjectAction", + "saveProjectAction", + "saveAsProjectAction", + "loadProjectAction", + "configurePlcAction", + "configureRegisterCommentsAction", + "disconnectPlcAction", + "addButtonAction", + "addIndicatorAction", + "addNumericDisplayAction", + "addNumericInputAction", + "addProgressBarAction", + "addLabelAction", + "addPageJumpAction", + "addAlarmListAction", + "configureAlarmsAction", + "deleteControlAction", + "addRungAction", + "parallelInsertAction", + "addNormallyOpenAction", + "addNormallyClosedAction", + "addRisingEdgeAction", + "addFallingEdgeAction", + "addTimerContactAction", + "addCounterContactAction", + "addNormalCoilAction", + "addSetCoilAction", + "addResetCoilAction", + "addTonAction", + "addCtuAction", + "addCtdAction", + "addMoveAction", + "addAddAction", + "addSubAction", + "addCompareAction", + "editRungCommentAction", + "deleteLogicAction", + "editingModeAction", + "offlineModeAction", + "onlineModeAction"}) + { + require(!requiredChild(window, action_name)->icon().isNull(), + std::string("UI action must have a semantic icon: ") + action_name); + } + require(!hmi_more_controls->icon().isNull() + && !logic_contact_menu->icon().isNull() + && !logic_output_menu->icon().isNull() + && !logic_timer_counter_menu->icon().isNull() + && !logic_data_menu->icon().isNull(), + "every grouped toolbar menu must have an icon"); + require(editor_tabs->count() == 3 + && !editor_tabs->tabIcon(0).isNull() + && !editor_tabs->tabIcon(1).isNull() + && !editor_tabs->tabIcon(2).isNull(), + "every editor workspace tab must have an icon"); + QToolButton *monitor_remove = free_monitor->findChild( + QStringLiteral("removeButton")); + QToolButton *monitor_clear = free_monitor->findChild( + QStringLiteral("clearButton")); + require(monitor_remove != nullptr && monitor_clear != nullptr + && !monitor_remove->icon().isNull() + && !monitor_clear->icon().isNull(), + "free-monitor delete and clear commands must have icons"); + require(hmi_more_controls->menu() != nullptr + && hmi_more_controls->menu()->actions().contains(add_progress_bar_action), + "advanced HMI controls must remain reachable from the more-controls menu"); + require(logic_contact_menu->menu() != nullptr + && logic_contact_menu->menu()->actions().contains( + requiredChild(window, "addRisingEdgeAction")), + "edge and resource contacts must remain reachable from the contact menu"); + require(logic_output_menu->menu() != nullptr + && logic_output_menu->menu()->actions().contains( + requiredChild(window, "addResetCoilAction")), + "set/reset coils must remain reachable from the output menu"); + require(logic_timer_counter_menu->menu() != nullptr + && logic_timer_counter_menu->menu()->actions().contains( + requiredChild(window, "addCtdAction")), + "timer and counter instructions must remain reachable from their menu"); + require(logic_data_menu->menu() != nullptr + && logic_data_menu->menu()->actions().contains( + requiredChild(window, "addSubAction")), + "data instructions must remain reachable from the data menu"); const qreal compact_scale = hmi_editor->transform().m11(); window.resize(1600, 900); diff --git a/app/tests/main_window_tests.pro b/app/tests/main_window_tests.pro index cd3444f..cf489d4 100644 --- a/app/tests/main_window_tests.pro +++ b/app/tests/main_window_tests.pro @@ -16,6 +16,7 @@ SOURCES += \ ../src/ui/plc_connection_dialog.cpp \ ../src/ui/free_monitor_widget.cpp \ ../src/ui/runtime_monitor_widget.cpp \ + ../src/ui/toolbar_icon_factory.cpp \ ../src/ui/project_workspace_controller.cpp \ ../src/ui/property_panel_controller.cpp \ ../src/ui/runtime_panel_controller.cpp \ @@ -52,6 +53,7 @@ HEADERS += \ ../src/ui/plc_connection_dialog.h \ ../src/ui/free_monitor_widget.h \ ../src/ui/runtime_monitor_widget.h \ + ../src/ui/toolbar_icon_factory.h \ ../src/ui/project_workspace_controller.h \ ../src/ui/property_panel_controller.h \ ../src/ui/runtime_panel_controller.h \