Browse Source

refactor: 统一工具栏图标与分组

main
suyu 1 month ago
parent
commit
7c3a232f77
8 changed files with 777 additions and 69 deletions
  1. +2
    -0
      app/integrated_platform.pro
  2. +3
    -3
      app/src/ui/free_monitor_widget.cpp
  3. +111
    -49
      app/src/ui/main_window.cpp
  4. +0
    -17
      app/src/ui/main_window.ui
  5. +508
    -0
      app/src/ui/toolbar_icon_factory.cpp
  6. +54
    -0
      app/src/ui/toolbar_icon_factory.h
  7. +97
    -0
      app/tests/main_window_tests.cpp
  8. +2
    -0
      app/tests/main_window_tests.pro

+ 2
- 0
app/integrated_platform.pro View File

@@ -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 \


+ 3
- 3
app/src/ui/free_monitor_widget.cpp View File

@@ -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 <QHeaderView>
#include <QMessageBox>
#include <QStyle>
#include <QTableWidgetItem>

#include <set>
@@ -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);


+ 111
- 49
app/src/ui/main_window.cpp View File

@@ -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 <QApplication>
#include <QFileDialog>
#include <QInputDialog>
#include <QIcon>
#include <QLabel>
#include <QMessageBox>
#include <QMenu>
#include <QStatusBar>
#include <QStyle>
#include <QTabWidget>
#include <QToolBar>
#include <QToolButton>

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<QAction *> &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<QAction *>{
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<QAction *>{
ui_->addRisingEdgeAction,
ui_->addFallingEdgeAction,
ui_->addTimerContactAction,
ui_->addCounterContactAction});
addToolbarMenu(
ui_->logicToolBar,
tr("更多输出"),
QStringLiteral("logicOutputMenuButton"),
makeUiIcon(UiIcon::Coil),
QList<QAction *>{ui_->addSetCoilAction, ui_->addResetCoilAction});
addToolbarMenu(
ui_->logicToolBar,
tr("定时/计数"),
QStringLiteral("logicTimerCounterMenuButton"),
makeUiIcon(UiIcon::Ton),
QList<QAction *>{ui_->addTonAction, ui_->addCtuAction, ui_->addCtdAction});
addToolbarMenu(
ui_->logicToolBar,
tr("数据运算"),
QStringLiteral("logicDataMenuButton"),
makeUiIcon(UiIcon::Move),
QList<QAction *>{
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);


+ 0
- 17
app/src/ui/main_window.ui View File

@@ -303,11 +303,7 @@
<addaction name="addIndicatorAction"/>
<addaction name="addNumericDisplayAction"/>
<addaction name="addNumericInputAction"/>
<addaction name="addProgressBarAction"/>
<addaction name="addLabelAction"/>
<addaction name="addPageJumpAction"/>
<addaction name="addAlarmListAction"/>
<addaction name="configureAlarmsAction"/>
<addaction name="deleteControlAction"/>
</widget>
<widget class="QToolBar" name="logicToolBar">
@@ -329,20 +325,7 @@
<addaction name="separator"/>
<addaction name="addNormallyOpenAction"/>
<addaction name="addNormallyClosedAction"/>
<addaction name="addRisingEdgeAction"/>
<addaction name="addFallingEdgeAction"/>
<addaction name="addTimerContactAction"/>
<addaction name="addCounterContactAction"/>
<addaction name="addNormalCoilAction"/>
<addaction name="addSetCoilAction"/>
<addaction name="addResetCoilAction"/>
<addaction name="addTonAction"/>
<addaction name="addCtuAction"/>
<addaction name="addCtdAction"/>
<addaction name="addMoveAction"/>
<addaction name="addAddAction"/>
<addaction name="addSubAction"/>
<addaction name="addCompareAction"/>
<addaction name="editRungCommentAction"/>
</widget>
<widget class="QDockWidget" name="projectDock">


+ 508
- 0
app/src/ui/toolbar_icon_factory.cpp View File

@@ -0,0 +1,508 @@
#include "toolbar_icon_factory.h"

#include <QFont>
#include <QPainter>
#include <QPainterPath>
#include <QPixmap>

#include <array>

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<qreal>(size) / 24.0, static_cast<qreal>(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<int, 3> sizes{16, 24, 32};
for (int size : sizes)
{
result.addPixmap(renderIcon(icon, size));
}
return result;
}

+ 54
- 0
app/src/ui/toolbar_icon_factory.h View File

@@ -0,0 +1,54 @@
#pragma once

#include <QIcon>

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);

+ 97
- 0
app/tests/main_window_tests.cpp View File

@@ -37,8 +37,10 @@
#include <QPushButton>
#include <QStringList>
#include <QTableWidget>
#include <QTabWidget>
#include <QTimer>
#include <QTest>
#include <QToolButton>
#include <QTreeWidget>

#include <iostream>
@@ -601,6 +603,16 @@ void testModeActionsControlEditingAvailability()
QAction *add_progress_bar_action = requiredChild<QAction>(
window, "addProgressBarAction");
QAction *delete_control_action = requiredChild<QAction>(window, "deleteControlAction");
QToolButton *hmi_more_controls = requiredChild<QToolButton>(
window, "hmiMoreControlsButton");
QToolButton *logic_contact_menu = requiredChild<QToolButton>(
window, "logicContactMenuButton");
QToolButton *logic_output_menu = requiredChild<QToolButton>(
window, "logicOutputMenuButton");
QToolButton *logic_timer_counter_menu = requiredChild<QToolButton>(
window, "logicTimerCounterMenuButton");
QToolButton *logic_data_menu = requiredChild<QToolButton>(
window, "logicDataMenuButton");
QAction *add_normally_open_action = requiredChild<QAction>(
window, "addNormallyOpenAction");
QAction *add_normal_coil_action = requiredChild<QAction>(
@@ -632,8 +644,93 @@ void testModeActionsControlEditingAvailability()
QWidget *runtime_hmi = requiredChild<QWidget>(window, "runtimeHmiView");
QWidget *runtime_logic = requiredChild<QWidget>(window, "runtimeLogicView");
QWidget *free_monitor = requiredChild<QWidget>(window, "freeMonitorWidget");
QTabWidget *editor_tabs = requiredChild<QTabWidget>(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<QAction>(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<QToolButton *>(
QStringLiteral("removeButton"));
QToolButton *monitor_clear = free_monitor->findChild<QToolButton *>(
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<QAction>(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<QAction>(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<QAction>(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<QAction>(window, "addSubAction")),
"data instructions must remain reachable from the data menu");

const qreal compact_scale = hmi_editor->transform().m11();
window.resize(1600, 900);


+ 2
- 0
app/tests/main_window_tests.pro View File

@@ -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 \


Loading…
Cancel
Save