| @@ -17,6 +17,7 @@ INCLUDEPATH += src | |||
| SOURCES += \ | |||
| src/main.cpp \ | |||
| src/ui/main_window.cpp \ | |||
| src/ui/logic_instruction_dialog.cpp \ | |||
| src/ui/alarm_configuration_dialog.cpp \ | |||
| src/ui/register_comment_dialog.cpp \ | |||
| src/ui/plc_connection_dialog.cpp \ | |||
| @@ -52,6 +53,7 @@ SOURCES += \ | |||
| HEADERS += \ | |||
| src/ui/main_window.h \ | |||
| src/ui/logic_instruction_dialog.h \ | |||
| src/ui/alarm_configuration_dialog.h \ | |||
| src/ui/register_comment_dialog.h \ | |||
| src/ui/plc_connection_dialog.h \ | |||
| @@ -89,6 +91,7 @@ HEADERS += \ | |||
| FORMS += \ | |||
| src/ui/main_window.ui \ | |||
| src/ui/logic_instruction_dialog.ui \ | |||
| src/ui/alarm_configuration_dialog.ui \ | |||
| src/ui/register_comment_dialog.ui \ | |||
| src/ui/plc_connection_dialog.ui \ | |||
| @@ -717,7 +717,7 @@ LogicEditorResult LogicEditorService::setOutput( | |||
| { | |||
| return failure( | |||
| LogicEditorError::InvalidNode, | |||
| "梯形图输出必须使用有效线圈或 TON 指令"); | |||
| "梯形图输出必须使用有效的输出指令"); | |||
| } | |||
| const std::string node_id = existing_rung->output.has_value() | |||
| ? existing_rung->output->id : makeUniqueNodeId(*logic, nodePrefix(config)); | |||
| @@ -821,13 +821,17 @@ bool LogicEditorService::isConditionConfig(const LogicNodeConfig &config) | |||
| return std::holds_alternative<ContactNodeConfig>(config) | |||
| || std::holds_alternative<EdgeContactNodeConfig>(config) | |||
| || std::holds_alternative<TimerContactNodeConfig>(config) | |||
| || std::holds_alternative<CounterContactNodeConfig>(config) | |||
| || std::holds_alternative<CompareNodeConfig>(config); | |||
| } | |||
| bool LogicEditorService::isOutputConfig(const LogicNodeConfig &config) | |||
| { | |||
| return std::holds_alternative<CoilNodeConfig>(config) | |||
| || std::holds_alternative<TonNodeConfig>(config); | |||
| || std::holds_alternative<TonNodeConfig>(config) | |||
| || std::holds_alternative<CounterNodeConfig>(config) | |||
| || std::holds_alternative<MoveNodeConfig>(config) | |||
| || std::holds_alternative<ArithmeticNodeConfig>(config); | |||
| } | |||
| std::string LogicEditorService::nodePrefix(const LogicNodeConfig &config) | |||
| @@ -848,6 +852,10 @@ std::string LogicEditorService::nodePrefix(const LogicNodeConfig &config) | |||
| { | |||
| return "timer-contact"; | |||
| } | |||
| else if constexpr (std::is_same_v<Config, CounterContactNodeConfig>) | |||
| { | |||
| return "counter-contact"; | |||
| } | |||
| else if constexpr (std::is_same_v<Config, CoilNodeConfig>) | |||
| { | |||
| return "coil"; | |||
| @@ -856,7 +864,22 @@ std::string LogicEditorService::nodePrefix(const LogicNodeConfig &config) | |||
| { | |||
| return "ton"; | |||
| } | |||
| return "compare"; | |||
| else if constexpr (std::is_same_v<Config, CounterNodeConfig>) | |||
| { | |||
| return "counter"; | |||
| } | |||
| else if constexpr (std::is_same_v<Config, MoveNodeConfig>) | |||
| { | |||
| return "move"; | |||
| } | |||
| else if constexpr (std::is_same_v<Config, ArithmeticNodeConfig>) | |||
| { | |||
| return "arithmetic"; | |||
| } | |||
| else | |||
| { | |||
| return "compare"; | |||
| } | |||
| }, | |||
| config); | |||
| } | |||
| @@ -53,6 +53,18 @@ QString timerAddressText(const TimerAddress &address) | |||
| return QString::fromStdString(address.toString()); | |||
| } | |||
| QString counterAddressText(const CounterAddress &address) | |||
| { | |||
| return QString::fromStdString(address.toString()); | |||
| } | |||
| QString wordOperandText(const WordOperand &operand) | |||
| { | |||
| return operand.kind == WordOperandKind::Register | |||
| ? registerAddressText(operand.address) | |||
| : QString::number(operand.constant); | |||
| } | |||
| void drawRegisterComment( | |||
| QPainter *painter, const QString &comment, qreal top = 22.0) | |||
| { | |||
| @@ -112,6 +124,11 @@ QString nodeToolTip(const LogicNodeConfig &config) | |||
| return LogicEditorWidget::tr("T 触点:%1") | |||
| .arg(timerAddressText(value.address)); | |||
| } | |||
| else if constexpr (std::is_same_v<Config, CounterContactNodeConfig>) | |||
| { | |||
| return LogicEditorWidget::tr("C 触点:%1") | |||
| .arg(counterAddressText(value.address)); | |||
| } | |||
| else if constexpr (std::is_same_v<Config, CoilNodeConfig>) | |||
| { | |||
| return LogicEditorWidget::tr("输出线圈:%1") | |||
| @@ -124,12 +141,37 @@ QString nodeToolTip(const LogicNodeConfig &config) | |||
| .arg(comparisonText(value.comparison)) | |||
| .arg(value.value); | |||
| } | |||
| else | |||
| else if constexpr (std::is_same_v<Config, TonNodeConfig>) | |||
| { | |||
| return LogicEditorWidget::tr("TON:%1,预设 %2 ms") | |||
| .arg(timerAddressText(value.address)) | |||
| .arg(value.presetMs); | |||
| } | |||
| else if constexpr (std::is_same_v<Config, CounterNodeConfig>) | |||
| { | |||
| return LogicEditorWidget::tr("%1:%2,CV %3,PV %4,复位 %5") | |||
| .arg(value.mode == CounterMode::Up | |||
| ? QStringLiteral("CTU") : QStringLiteral("CTD")) | |||
| .arg(counterAddressText(value.address)) | |||
| .arg(registerAddressText(value.currentValueAddress)) | |||
| .arg(wordOperandText(value.preset)) | |||
| .arg(registerAddressText(value.resetAddress)); | |||
| } | |||
| else if constexpr (std::is_same_v<Config, MoveNodeConfig>) | |||
| { | |||
| return LogicEditorWidget::tr("MOVE:%1 -> %2") | |||
| .arg(wordOperandText(value.source)) | |||
| .arg(registerAddressText(value.destination)); | |||
| } | |||
| else | |||
| { | |||
| return LogicEditorWidget::tr("%1:%2,%3 -> %4") | |||
| .arg(value.operation == ArithmeticOperation::Add | |||
| ? QStringLiteral("ADD") : QStringLiteral("SUB")) | |||
| .arg(wordOperandText(value.left)) | |||
| .arg(wordOperandText(value.right)) | |||
| .arg(registerAddressText(value.destination)); | |||
| } | |||
| }, | |||
| config); | |||
| } | |||
| @@ -327,6 +369,24 @@ public: | |||
| Qt::AlignCenter, | |||
| configured_ ? timerAddressText(timer_contact->address) : tr("< T 地址 >")); | |||
| } | |||
| else if (const auto *counter_contact = | |||
| std::get_if<CounterContactNodeConfig>(&config_)) | |||
| { | |||
| painter->fillRect(QRectF(-25, -22, 50, 44), Qt::white); | |||
| painter->drawLine(QPointF(-kNodeTerminalX, 0), QPointF(-18, 0)); | |||
| painter->drawLine(QPointF(18, 0), QPointF(kNodeTerminalX, 0)); | |||
| painter->drawLine(QPointF(-18, -15), QPointF(-18, 15)); | |||
| painter->drawLine(QPointF(18, -15), QPointF(18, 15)); | |||
| if (counter_contact->mode == ContactMode::NormallyClosed) | |||
| { | |||
| painter->drawLine(QPointF(-23, 18), QPointF(23, -18)); | |||
| } | |||
| painter->drawText( | |||
| QRectF(-kCellWidth / 2.0, -40, kCellWidth, 18), | |||
| Qt::AlignCenter, | |||
| configured_ ? counterAddressText(counter_contact->address) | |||
| : tr("< C 地址 >")); | |||
| } | |||
| else if (const auto *coil = std::get_if<CoilNodeConfig>(&config_)) | |||
| { | |||
| painter->fillRect(QRectF(-35, -23, 70, 46), Qt::white); | |||
| @@ -391,6 +451,69 @@ public: | |||
| configured_ ? QStringLiteral("PT %1 ms").arg(ton->presetMs) | |||
| : tr("< 预设时间 >")); | |||
| } | |||
| else if (const auto *counter = std::get_if<CounterNodeConfig>(&config_)) | |||
| { | |||
| const QRectF box(-47, -18, 94, 36); | |||
| painter->fillRect(box.adjusted(-1, -1, 1, 1), Qt::white); | |||
| painter->drawLine(QPointF(-kNodeTerminalX, 0), QPointF(-47, 0)); | |||
| painter->drawLine(QPointF(47, 0), QPointF(kNodeTerminalX, 0)); | |||
| painter->drawRect(box); | |||
| painter->drawText( | |||
| box, | |||
| Qt::AlignCenter, | |||
| counter->mode == CounterMode::Up | |||
| ? QStringLiteral("CTU") : QStringLiteral("CTD")); | |||
| painter->drawText( | |||
| QRectF(-kCellWidth / 2.0, -40, kCellWidth, 18), | |||
| Qt::AlignCenter, | |||
| configured_ ? counterAddressText(counter->address) | |||
| : tr("< C 地址 >")); | |||
| painter->drawText( | |||
| QRectF(-kCellWidth / 2.0, 22, kCellWidth, 18), | |||
| Qt::AlignCenter, | |||
| configured_ ? QStringLiteral("CV %1 / PV %2") | |||
| .arg(registerAddressText(counter->currentValueAddress)) | |||
| .arg(wordOperandText(counter->preset)) | |||
| : tr("< CV / PV >")); | |||
| } | |||
| else if (const auto *move = std::get_if<MoveNodeConfig>(&config_)) | |||
| { | |||
| const QRectF box(-47, -18, 94, 36); | |||
| painter->fillRect(box.adjusted(-1, -1, 1, 1), Qt::white); | |||
| painter->drawLine(QPointF(-kNodeTerminalX, 0), QPointF(-47, 0)); | |||
| painter->drawLine(QPointF(47, 0), QPointF(kNodeTerminalX, 0)); | |||
| painter->drawRect(box); | |||
| painter->drawText(box, Qt::AlignCenter, QStringLiteral("MOVE")); | |||
| painter->drawText( | |||
| QRectF(-kCellWidth / 2.0, -40, kCellWidth, 18), | |||
| Qt::AlignCenter, | |||
| configured_ ? QStringLiteral("%1 -> %2") | |||
| .arg(wordOperandText(move->source)) | |||
| .arg(registerAddressText(move->destination)) | |||
| : tr("< 源 -> 目标 >")); | |||
| } | |||
| else if (const auto *arithmetic = | |||
| std::get_if<ArithmeticNodeConfig>(&config_)) | |||
| { | |||
| const QRectF box(-47, -18, 94, 36); | |||
| painter->fillRect(box.adjusted(-1, -1, 1, 1), Qt::white); | |||
| painter->drawLine(QPointF(-kNodeTerminalX, 0), QPointF(-47, 0)); | |||
| painter->drawLine(QPointF(47, 0), QPointF(kNodeTerminalX, 0)); | |||
| painter->drawRect(box); | |||
| painter->drawText( | |||
| box, | |||
| Qt::AlignCenter, | |||
| arithmetic->operation == ArithmeticOperation::Add | |||
| ? QStringLiteral("ADD") : QStringLiteral("SUB")); | |||
| painter->drawText( | |||
| QRectF(-kCellWidth / 2.0, -40, kCellWidth, 18), | |||
| Qt::AlignCenter, | |||
| configured_ ? QStringLiteral("%1,%2 -> %3") | |||
| .arg(wordOperandText(arithmetic->left)) | |||
| .arg(wordOperandText(arithmetic->right)) | |||
| .arg(registerAddressText(arithmetic->destination)) | |||
| : tr("< 操作数 -> 目标 >")); | |||
| } | |||
| } | |||
| const std::string &nodeId() const { return node_id_; } | |||
| @@ -766,7 +889,9 @@ void LogicEditorWidget::reloadLogic() | |||
| }(), | |||
| [&rung, this, rung_active] | |||
| { | |||
| return std::holds_alternative<TonNodeConfig>(rung.output->config) | |||
| return (std::holds_alternative<TonNodeConfig>(rung.output->config) | |||
| || std::holds_alternative<CounterNodeConfig>( | |||
| rung.output->config)) | |||
| ? traceValue( | |||
| trace_, | |||
| &LogicTraceSnapshot::nodeValues, | |||
| @@ -0,0 +1,206 @@ | |||
| #include "logic_instruction_dialog.h" | |||
| #include "ui_logic_instruction_dialog.h" | |||
| #include <QComboBox> | |||
| #include <QDialogButtonBox> | |||
| #include <QLabel> | |||
| #include <QSpinBox> | |||
| #include <limits> | |||
| namespace { | |||
| constexpr int kConstantOperandData = 0; | |||
| constexpr int kRegisterOperandData = 1; | |||
| void configureOperandCombo(QComboBox *combo) | |||
| { | |||
| combo->clear(); | |||
| combo->addItem(LogicInstructionDialog::tr("常量"), kConstantOperandData); | |||
| combo->addItem(LogicInstructionDialog::tr("D 寄存器"), kRegisterOperandData); | |||
| } | |||
| } // namespace | |||
| LogicInstructionDialog::LogicInstructionDialog( | |||
| const LogicNodeConfig &config, | |||
| QWidget *parent) | |||
| : QDialog(parent), | |||
| ui_(std::make_unique<Ui::LogicInstructionDialog>()), | |||
| original_config_(config) | |||
| { | |||
| ui_->setupUi(this); | |||
| configureOperandCombo(ui_->counterPresetKindComboBox); | |||
| configureOperandCombo(ui_->leftOperandKindComboBox); | |||
| configureOperandCombo(ui_->rightOperandKindComboBox); | |||
| connect(ui_->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); | |||
| connect(ui_->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); | |||
| for (QComboBox *combo : { | |||
| ui_->counterPresetKindComboBox, | |||
| ui_->leftOperandKindComboBox, | |||
| ui_->rightOperandKindComboBox}) | |||
| { | |||
| connect( | |||
| combo, | |||
| qOverload<int>(&QComboBox::currentIndexChanged), | |||
| this, | |||
| &LogicInstructionDialog::updateOperandRanges); | |||
| } | |||
| if (const auto *counter = std::get_if<CounterNodeConfig>(&config)) | |||
| { | |||
| configureCounter(*counter); | |||
| } | |||
| else if (const auto *move = std::get_if<MoveNodeConfig>(&config)) | |||
| { | |||
| configureMove(*move); | |||
| } | |||
| else if (const auto *arithmetic = std::get_if<ArithmeticNodeConfig>(&config)) | |||
| { | |||
| configureArithmetic(*arithmetic); | |||
| } | |||
| updateOperandRanges(); | |||
| } | |||
| LogicInstructionDialog::~LogicInstructionDialog() = default; | |||
| LogicNodeConfig LogicInstructionDialog::config() const | |||
| { | |||
| if (std::holds_alternative<CounterNodeConfig>(original_config_)) | |||
| { | |||
| return CounterNodeConfig{ | |||
| CounterAddress{ui_->counterAddressSpinBox->value()}, | |||
| static_cast<CounterMode>(ui_->counterModeComboBox->currentData().toInt()), | |||
| RegisterAddress{ | |||
| RegisterArea::D, | |||
| ui_->counterCurrentAddressSpinBox->value()}, | |||
| operandFrom( | |||
| ui_->counterPresetKindComboBox, | |||
| ui_->counterPresetValueSpinBox), | |||
| RegisterAddress{ | |||
| RegisterArea::M, | |||
| ui_->counterResetAddressSpinBox->value()}}; | |||
| } | |||
| if (std::holds_alternative<MoveNodeConfig>(original_config_)) | |||
| { | |||
| return MoveNodeConfig{ | |||
| operandFrom(ui_->leftOperandKindComboBox, ui_->leftOperandValueSpinBox), | |||
| RegisterAddress{ | |||
| RegisterArea::D, | |||
| ui_->destinationAddressSpinBox->value()}}; | |||
| } | |||
| const auto *arithmetic = std::get_if<ArithmeticNodeConfig>(&original_config_); | |||
| return ArithmeticNodeConfig{ | |||
| arithmetic->operation, | |||
| operandFrom(ui_->leftOperandKindComboBox, ui_->leftOperandValueSpinBox), | |||
| operandFrom(ui_->rightOperandKindComboBox, ui_->rightOperandValueSpinBox), | |||
| RegisterAddress{ | |||
| RegisterArea::D, | |||
| ui_->destinationAddressSpinBox->value()}}; | |||
| } | |||
| void LogicInstructionDialog::configureCounter(const CounterNodeConfig &config) | |||
| { | |||
| setWindowTitle(tr("配置计数器")); | |||
| ui_->instructionStackedWidget->setCurrentWidget(ui_->counterPage); | |||
| ui_->counterModeComboBox->clear(); | |||
| ui_->counterModeComboBox->addItem(tr("CTU 加计数"), static_cast<int>(CounterMode::Up)); | |||
| ui_->counterModeComboBox->addItem( | |||
| tr("CTD 减计数"), static_cast<int>(CounterMode::Down)); | |||
| ui_->counterModeComboBox->setCurrentIndex( | |||
| ui_->counterModeComboBox->findData(static_cast<int>(config.mode))); | |||
| ui_->counterAddressSpinBox->setValue(config.address.index()); | |||
| ui_->counterCurrentAddressSpinBox->setValue(config.currentValueAddress.index()); | |||
| ui_->counterResetAddressSpinBox->setValue(config.resetAddress.index()); | |||
| setOperand( | |||
| ui_->counterPresetKindComboBox, | |||
| ui_->counterPresetValueSpinBox, | |||
| config.preset); | |||
| } | |||
| void LogicInstructionDialog::configureMove(const MoveNodeConfig &config) | |||
| { | |||
| setWindowTitle(tr("配置 MOVE")); | |||
| ui_->instructionStackedWidget->setCurrentWidget(ui_->dataInstructionPage); | |||
| ui_->instructionNameLabel->setText(QStringLiteral("MOVE")); | |||
| ui_->leftOperandLabel->setText(tr("源操作数")); | |||
| ui_->rightOperandLabel->setVisible(false); | |||
| ui_->rightOperandEditor->setVisible(false); | |||
| setOperand( | |||
| ui_->leftOperandKindComboBox, | |||
| ui_->leftOperandValueSpinBox, | |||
| config.source); | |||
| ui_->destinationAddressSpinBox->setValue(config.destination.index()); | |||
| } | |||
| void LogicInstructionDialog::configureArithmetic(const ArithmeticNodeConfig &config) | |||
| { | |||
| const bool is_add = config.operation == ArithmeticOperation::Add; | |||
| setWindowTitle(is_add ? tr("配置 ADD") : tr("配置 SUB")); | |||
| ui_->instructionStackedWidget->setCurrentWidget(ui_->dataInstructionPage); | |||
| ui_->instructionNameLabel->setText(is_add | |||
| ? QStringLiteral("ADD") : QStringLiteral("SUB")); | |||
| ui_->leftOperandLabel->setText(tr("左操作数")); | |||
| ui_->rightOperandLabel->setVisible(true); | |||
| ui_->rightOperandEditor->setVisible(true); | |||
| setOperand( | |||
| ui_->leftOperandKindComboBox, | |||
| ui_->leftOperandValueSpinBox, | |||
| config.left); | |||
| setOperand( | |||
| ui_->rightOperandKindComboBox, | |||
| ui_->rightOperandValueSpinBox, | |||
| config.right); | |||
| ui_->destinationAddressSpinBox->setValue(config.destination.index()); | |||
| } | |||
| void LogicInstructionDialog::updateOperandRanges() | |||
| { | |||
| const auto update = [](const QComboBox *combo, QSpinBox *spin) | |||
| { | |||
| const bool register_operand = combo->currentData().toInt() | |||
| == kRegisterOperandData; | |||
| spin->setPrefix(register_operand ? QStringLiteral("D") : QString{}); | |||
| spin->setMinimum(register_operand | |||
| ? RegisterAddress::kMinimumIndex | |||
| : std::numeric_limits<std::int16_t>::min()); | |||
| spin->setMaximum(register_operand | |||
| ? RegisterAddress::kMaximumIndex | |||
| : std::numeric_limits<std::int16_t>::max()); | |||
| }; | |||
| update(ui_->counterPresetKindComboBox, ui_->counterPresetValueSpinBox); | |||
| update(ui_->leftOperandKindComboBox, ui_->leftOperandValueSpinBox); | |||
| update(ui_->rightOperandKindComboBox, ui_->rightOperandValueSpinBox); | |||
| } | |||
| void LogicInstructionDialog::setOperand( | |||
| QComboBox *kind_combo, | |||
| QSpinBox *value_spin, | |||
| const WordOperand &operand) | |||
| { | |||
| kind_combo->setCurrentIndex(kind_combo->findData( | |||
| operand.kind == WordOperandKind::Register | |||
| ? kRegisterOperandData : kConstantOperandData)); | |||
| value_spin->setValue( | |||
| operand.kind == WordOperandKind::Register | |||
| ? operand.address.index() : operand.constant); | |||
| } | |||
| WordOperand LogicInstructionDialog::operandFrom( | |||
| const QComboBox *kind_combo, | |||
| const QSpinBox *value_spin) | |||
| { | |||
| if (kind_combo->currentData().toInt() == kRegisterOperandData) | |||
| { | |||
| return WordOperand{ | |||
| WordOperandKind::Register, | |||
| RegisterAddress{RegisterArea::D, value_spin->value()}, | |||
| 0}; | |||
| } | |||
| return WordOperand{ | |||
| WordOperandKind::Constant, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| static_cast<std::int16_t>(value_spin->value())}; | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| #pragma once | |||
| #include "domain/control_logic_model.h" | |||
| #include <QDialog> | |||
| #include <memory> | |||
| class QComboBox; | |||
| class QSpinBox; | |||
| namespace Ui { | |||
| class LogicInstructionDialog; | |||
| } | |||
| class LogicInstructionDialog final : public QDialog | |||
| { | |||
| Q_OBJECT | |||
| public: | |||
| explicit LogicInstructionDialog( | |||
| const LogicNodeConfig &config, | |||
| QWidget *parent = nullptr); | |||
| ~LogicInstructionDialog() override; | |||
| LogicNodeConfig config() const; | |||
| private: | |||
| void configureCounter(const CounterNodeConfig &config); | |||
| void configureMove(const MoveNodeConfig &config); | |||
| void configureArithmetic(const ArithmeticNodeConfig &config); | |||
| void updateOperandRanges(); | |||
| static void setOperand( | |||
| QComboBox *kind_combo, | |||
| QSpinBox *value_spin, | |||
| const WordOperand &operand); | |||
| static WordOperand operandFrom( | |||
| const QComboBox *kind_combo, | |||
| const QSpinBox *value_spin); | |||
| std::unique_ptr<Ui::LogicInstructionDialog> ui_; | |||
| LogicNodeConfig original_config_; | |||
| }; | |||
| @@ -0,0 +1,66 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <ui version="4.0"> | |||
| <class>LogicInstructionDialog</class> | |||
| <widget class="QDialog" name="LogicInstructionDialog"> | |||
| <property name="geometry"> | |||
| <rect><x>0</x><y>0</y><width>420</width><height>310</height></rect> | |||
| </property> | |||
| <property name="windowTitle"><string>配置逻辑指令</string></property> | |||
| <layout class="QVBoxLayout" name="verticalLayout"> | |||
| <item> | |||
| <widget class="QStackedWidget" name="instructionStackedWidget"> | |||
| <widget class="QWidget" name="counterPage"> | |||
| <layout class="QFormLayout" name="counterFormLayout"> | |||
| <item row="0" column="0"><widget class="QLabel" name="counterModeLabel"><property name="text"><string>计数方式</string></property></widget></item> | |||
| <item row="0" column="1"><widget class="QComboBox" name="counterModeComboBox"/></item> | |||
| <item row="1" column="0"><widget class="QLabel" name="counterAddressLabel"><property name="text"><string>计数器资源</string></property></widget></item> | |||
| <item row="1" column="1"><widget class="QSpinBox" name="counterAddressSpinBox"><property name="prefix"><string>C</string></property><property name="maximum"><number>4000</number></property></widget></item> | |||
| <item row="2" column="0"><widget class="QLabel" name="counterCurrentAddressLabel"><property name="text"><string>当前值 CV</string></property></widget></item> | |||
| <item row="2" column="1"><widget class="QSpinBox" name="counterCurrentAddressSpinBox"><property name="prefix"><string>D</string></property><property name="maximum"><number>4000</number></property></widget></item> | |||
| <item row="3" column="0"><widget class="QLabel" name="counterPresetLabel"><property name="text"><string>预设值 PV</string></property></widget></item> | |||
| <item row="3" column="1"> | |||
| <widget class="QWidget" name="counterPresetEditor" native="true"> | |||
| <layout class="QHBoxLayout" name="counterPresetLayout"><property name="leftMargin"><number>0</number></property><property name="topMargin"><number>0</number></property><property name="rightMargin"><number>0</number></property><property name="bottomMargin"><number>0</number></property> | |||
| <item><widget class="QComboBox" name="counterPresetKindComboBox"/></item> | |||
| <item><widget class="QSpinBox" name="counterPresetValueSpinBox"><property name="maximum"><number>32767</number></property><property name="value"><number>10</number></property></widget></item> | |||
| </layout> | |||
| </widget> | |||
| </item> | |||
| <item row="4" column="0"><widget class="QLabel" name="counterResetAddressLabel"><property name="text"><string>复位输入</string></property></widget></item> | |||
| <item row="4" column="1"><widget class="QSpinBox" name="counterResetAddressSpinBox"><property name="prefix"><string>M</string></property><property name="maximum"><number>4000</number></property></widget></item> | |||
| </layout> | |||
| </widget> | |||
| <widget class="QWidget" name="dataInstructionPage"> | |||
| <layout class="QFormLayout" name="dataInstructionFormLayout"> | |||
| <item row="0" column="0"><widget class="QLabel" name="instructionCaptionLabel"><property name="text"><string>指令</string></property></widget></item> | |||
| <item row="0" column="1"><widget class="QLabel" name="instructionNameLabel"><property name="text"><string>MOVE</string></property></widget></item> | |||
| <item row="1" column="0"><widget class="QLabel" name="leftOperandLabel"><property name="text"><string>源操作数</string></property></widget></item> | |||
| <item row="1" column="1"> | |||
| <widget class="QWidget" name="leftOperandEditor" native="true"> | |||
| <layout class="QHBoxLayout" name="leftOperandLayout"><property name="leftMargin"><number>0</number></property><property name="topMargin"><number>0</number></property><property name="rightMargin"><number>0</number></property><property name="bottomMargin"><number>0</number></property> | |||
| <item><widget class="QComboBox" name="leftOperandKindComboBox"/></item> | |||
| <item><widget class="QSpinBox" name="leftOperandValueSpinBox"><property name="minimum"><number>-32768</number></property><property name="maximum"><number>32767</number></property></widget></item> | |||
| </layout> | |||
| </widget> | |||
| </item> | |||
| <item row="2" column="0"><widget class="QLabel" name="rightOperandLabel"><property name="text"><string>右操作数</string></property></widget></item> | |||
| <item row="2" column="1"> | |||
| <widget class="QWidget" name="rightOperandEditor" native="true"> | |||
| <layout class="QHBoxLayout" name="rightOperandLayout"><property name="leftMargin"><number>0</number></property><property name="topMargin"><number>0</number></property><property name="rightMargin"><number>0</number></property><property name="bottomMargin"><number>0</number></property> | |||
| <item><widget class="QComboBox" name="rightOperandKindComboBox"/></item> | |||
| <item><widget class="QSpinBox" name="rightOperandValueSpinBox"><property name="minimum"><number>-32768</number></property><property name="maximum"><number>32767</number></property></widget></item> | |||
| </layout> | |||
| </widget> | |||
| </item> | |||
| <item row="3" column="0"><widget class="QLabel" name="destinationAddressLabel"><property name="text"><string>目标地址</string></property></widget></item> | |||
| <item row="3" column="1"><widget class="QSpinBox" name="destinationAddressSpinBox"><property name="prefix"><string>D</string></property><property name="maximum"><number>4000</number></property></widget></item> | |||
| </layout> | |||
| </widget> | |||
| </widget> | |||
| </item> | |||
| <item><widget class="QDialogButtonBox" name="buttonBox"><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item> | |||
| </layout> | |||
| </widget> | |||
| <resources/> | |||
| <connections/> | |||
| </ui> | |||
| @@ -4,6 +4,7 @@ | |||
| #include "alarm_configuration_dialog.h" | |||
| #include "register_comment_dialog.h" | |||
| #include "logic_editor_widget.h" | |||
| #include "logic_instruction_dialog.h" | |||
| #include "plc_connection_dialog.h" | |||
| #include "runtime_monitor_widget.h" | |||
| #include "free_monitor_widget.h" | |||
| @@ -342,6 +343,7 @@ void MainWindow::configureActions() | |||
| QAction *parallel_rising = parallel_menu->addAction(tr("并联上升沿触点")); | |||
| QAction *parallel_falling = parallel_menu->addAction(tr("并联下降沿触点")); | |||
| QAction *parallel_timer = parallel_menu->addAction(tr("并联 T 触点")); | |||
| QAction *parallel_counter = parallel_menu->addAction(tr("并联 C 触点")); | |||
| QAction *parallel_compare = parallel_menu->addAction(tr("并联比较条件")); | |||
| connect(parallel_open, &QAction::triggered, | |||
| this, | |||
| @@ -380,6 +382,13 @@ void MainWindow::configureActions() | |||
| addLogicParallelBranch(TimerContactNodeConfig{ | |||
| TimerAddress{0}, ContactMode::NormallyOpen}); | |||
| }); | |||
| connect(parallel_counter, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| addLogicParallelBranch(CounterContactNodeConfig{ | |||
| CounterAddress{0}, ContactMode::NormallyOpen}); | |||
| }); | |||
| connect(parallel_compare, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| @@ -432,6 +441,13 @@ void MainWindow::configureActions() | |||
| addLogicCondition(TimerContactNodeConfig{ | |||
| TimerAddress{0}, ContactMode::NormallyOpen}); | |||
| }); | |||
| connect(ui_->addCounterContactAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| addLogicCondition(CounterContactNodeConfig{ | |||
| CounterAddress{0}, ContactMode::NormallyOpen}); | |||
| }); | |||
| connect(ui_->addNormalCoilAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| @@ -462,6 +478,77 @@ void MainWindow::configureActions() | |||
| { | |||
| setLogicOutput(TonNodeConfig{TimerAddress{0}, 1000}); | |||
| }); | |||
| connect(ui_->addCtuAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| configureAndSetLogicOutput(CounterNodeConfig{ | |||
| CounterAddress{0}, | |||
| CounterMode::Up, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| WordOperand{ | |||
| WordOperandKind::Constant, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 10}, | |||
| RegisterAddress{RegisterArea::M, 0}}); | |||
| }); | |||
| connect(ui_->addCtdAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| configureAndSetLogicOutput(CounterNodeConfig{ | |||
| CounterAddress{0}, | |||
| CounterMode::Down, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| WordOperand{ | |||
| WordOperandKind::Constant, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 10}, | |||
| RegisterAddress{RegisterArea::M, 0}}); | |||
| }); | |||
| connect(ui_->addMoveAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| configureAndSetLogicOutput(MoveNodeConfig{ | |||
| WordOperand{ | |||
| WordOperandKind::Constant, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 0}, | |||
| RegisterAddress{RegisterArea::D, 0}}); | |||
| }); | |||
| connect(ui_->addAddAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| configureAndSetLogicOutput(ArithmeticNodeConfig{ | |||
| ArithmeticOperation::Add, | |||
| WordOperand{ | |||
| WordOperandKind::Register, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 0}, | |||
| WordOperand{ | |||
| WordOperandKind::Constant, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 1}, | |||
| RegisterAddress{RegisterArea::D, 0}}); | |||
| }); | |||
| connect(ui_->addSubAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| { | |||
| configureAndSetLogicOutput(ArithmeticNodeConfig{ | |||
| ArithmeticOperation::Subtract, | |||
| WordOperand{ | |||
| WordOperandKind::Register, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 0}, | |||
| WordOperand{ | |||
| WordOperandKind::Constant, | |||
| RegisterAddress{RegisterArea::D, 0}, | |||
| 1}, | |||
| RegisterAddress{RegisterArea::D, 0}}); | |||
| }); | |||
| connect(ui_->addCompareAction, &QAction::triggered, | |||
| this, | |||
| [this] | |||
| @@ -544,10 +631,16 @@ void MainWindow::configureAppearance() | |||
| 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)); | |||
| @@ -1443,6 +1536,21 @@ void MainWindow::showLogicNodeProperties(const std::string &node_id) | |||
| static_cast<int>(timer_contact->mode))); | |||
| ui_->logicModeComboBox->setEnabled(true); | |||
| } | |||
| else if (const auto *counter_contact = | |||
| std::get_if<CounterContactNodeConfig>(&node->config)) | |||
| { | |||
| ui_->logicNodeTypeLabel->setText(tr("C 触点")); | |||
| ui_->logicAddressAreaLabel->setText(QStringLiteral("C")); | |||
| ui_->logicAddressSpinBox->setValue(counter_contact->address.index()); | |||
| ui_->logicModeComboBox->addItem( | |||
| tr("常开"), static_cast<int>(ContactMode::NormallyOpen)); | |||
| ui_->logicModeComboBox->addItem( | |||
| tr("常闭"), static_cast<int>(ContactMode::NormallyClosed)); | |||
| ui_->logicModeComboBox->setCurrentIndex( | |||
| ui_->logicModeComboBox->findData( | |||
| static_cast<int>(counter_contact->mode))); | |||
| ui_->logicModeComboBox->setEnabled(true); | |||
| } | |||
| else if (const auto *coil = std::get_if<CoilNodeConfig>(&node->config)) | |||
| { | |||
| ui_->logicNodeTypeLabel->setText(tr("线圈")); | |||
| @@ -1472,16 +1580,47 @@ void MainWindow::showLogicNodeProperties(const std::string &node_id) | |||
| ui_->logicValueSpinBox->setEnabled(true); | |||
| ui_->logicValueSpinBox->setValue(compare->value); | |||
| } | |||
| else | |||
| else if (const auto *ton = std::get_if<TonNodeConfig>(&node->config)) | |||
| { | |||
| const auto &ton = std::get<TonNodeConfig>(node->config); | |||
| ui_->logicNodeTypeLabel->setText(tr("TON")); | |||
| ui_->logicAddressAreaLabel->setText(QStringLiteral("T")); | |||
| ui_->logicAddressSpinBox->setValue(ton.address.index()); | |||
| ui_->logicAddressSpinBox->setValue(ton->address.index()); | |||
| ui_->logicModeComboBox->addItem(tr("非保持接通延时")); | |||
| ui_->logicModeComboBox->setEnabled(false); | |||
| ui_->logicPresetSpinBox->setEnabled(true); | |||
| ui_->logicPresetSpinBox->setValue(ton.presetMs); | |||
| ui_->logicPresetSpinBox->setValue(ton->presetMs); | |||
| } | |||
| else if (const auto *counter = std::get_if<CounterNodeConfig>(&node->config)) | |||
| { | |||
| ui_->logicNodeTypeLabel->setText( | |||
| counter->mode == CounterMode::Up ? QStringLiteral("CTU") | |||
| : QStringLiteral("CTD")); | |||
| ui_->logicAddressAreaLabel->setText(QStringLiteral("C")); | |||
| ui_->logicAddressSpinBox->setValue(counter->address.index()); | |||
| ui_->logicAddressSpinBox->setEnabled(false); | |||
| ui_->logicModeComboBox->addItem(tr("使用配置对话框编辑")); | |||
| ui_->logicModeComboBox->setEnabled(false); | |||
| } | |||
| else if (const auto *move = std::get_if<MoveNodeConfig>(&node->config)) | |||
| { | |||
| ui_->logicNodeTypeLabel->setText(QStringLiteral("MOVE")); | |||
| ui_->logicAddressAreaLabel->setText(QStringLiteral("D")); | |||
| ui_->logicAddressSpinBox->setValue(move->destination.index()); | |||
| ui_->logicAddressSpinBox->setEnabled(false); | |||
| ui_->logicModeComboBox->addItem(tr("使用配置对话框编辑")); | |||
| ui_->logicModeComboBox->setEnabled(false); | |||
| } | |||
| else | |||
| { | |||
| const auto &arithmetic = std::get<ArithmeticNodeConfig>(node->config); | |||
| ui_->logicNodeTypeLabel->setText( | |||
| arithmetic.operation == ArithmeticOperation::Add | |||
| ? QStringLiteral("ADD") : QStringLiteral("SUB")); | |||
| ui_->logicAddressAreaLabel->setText(QStringLiteral("D")); | |||
| ui_->logicAddressSpinBox->setValue(arithmetic.destination.index()); | |||
| ui_->logicAddressSpinBox->setEnabled(false); | |||
| ui_->logicModeComboBox->addItem(tr("使用配置对话框编辑")); | |||
| ui_->logicModeComboBox->setEnabled(false); | |||
| } | |||
| if (!node->configured) | |||
| { | |||
| @@ -1628,6 +1767,36 @@ void MainWindow::setLogicOutput(const LogicNodeConfig &config) | |||
| statusBar()->showMessage(tr("逻辑输出已设置"), 3000); | |||
| } | |||
| void MainWindow::configureAndSetLogicOutput(const LogicNodeConfig &config) | |||
| { | |||
| LogicInstructionDialog dialog(config, this); | |||
| if (dialog.exec() != QDialog::Accepted) | |||
| { | |||
| return; | |||
| } | |||
| const LogicNodeConfig configured = dialog.config(); | |||
| LogicEditorResult result = logic_editor_widget_->setOutput(configured); | |||
| if (!result.succeeded) | |||
| { | |||
| showProjectResult(tr("设置逻辑输出"), fromUtf8(result.message), false); | |||
| return; | |||
| } | |||
| const std::string node_id = result.id; | |||
| result = logic_editor_service_.updateNodeConfig( | |||
| current_logic_id_, node_id, configured); | |||
| if (!result.succeeded) | |||
| { | |||
| showProjectResult(tr("配置逻辑输出"), fromUtf8(result.message), false); | |||
| return; | |||
| } | |||
| selected_logic_node_id_ = node_id; | |||
| logic_editor_widget_->reloadLogic(); | |||
| logic_editor_widget_->selectNode(node_id); | |||
| showLogicNodeProperties(node_id); | |||
| refreshProjectUi(); | |||
| statusBar()->showMessage(tr("逻辑输出已配置"), 3000); | |||
| } | |||
| void MainWindow::addLogicRung() | |||
| { | |||
| const LogicEditorResult result = logic_editor_widget_->addRung(); | |||
| @@ -1719,6 +1888,12 @@ void MainWindow::applySelectedLogicNodeProperties() | |||
| TimerAddress{ui_->logicAddressSpinBox->value()}, | |||
| static_cast<ContactMode>(ui_->logicModeComboBox->currentData().toInt())}; | |||
| } | |||
| else if (std::holds_alternative<CounterContactNodeConfig>(config)) | |||
| { | |||
| config = CounterContactNodeConfig{ | |||
| CounterAddress{ui_->logicAddressSpinBox->value()}, | |||
| static_cast<ContactMode>(ui_->logicModeComboBox->currentData().toInt())}; | |||
| } | |||
| else if (std::holds_alternative<CoilNodeConfig>(config)) | |||
| { | |||
| config = CoilNodeConfig{ | |||
| @@ -1733,12 +1908,21 @@ void MainWindow::applySelectedLogicNodeProperties() | |||
| ui_->logicComparisonComboBox->currentData().toInt()), | |||
| static_cast<std::int16_t>(ui_->logicValueSpinBox->value())}; | |||
| } | |||
| else | |||
| else if (std::holds_alternative<TonNodeConfig>(config)) | |||
| { | |||
| config = TonNodeConfig{ | |||
| TimerAddress{ui_->logicAddressSpinBox->value()}, | |||
| ui_->logicPresetSpinBox->value()}; | |||
| } | |||
| else | |||
| { | |||
| LogicInstructionDialog dialog(config, this); | |||
| if (dialog.exec() != QDialog::Accepted) | |||
| { | |||
| return; | |||
| } | |||
| config = dialog.config(); | |||
| } | |||
| const LogicEditorResult result = logic_editor_service_.updateNodeConfig( | |||
| current_logic_id_, selected_logic_node_id_, config); | |||
| @@ -1956,10 +2140,16 @@ void MainWindow::updateModeUi(const QString &message) | |||
| ui_->addRisingEdgeAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addFallingEdgeAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addTimerContactAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addCounterContactAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addNormalCoilAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addSetCoilAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addResetCoilAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addTonAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addCtuAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addCtdAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addMoveAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addAddAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addSubAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->addCompareAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->editRungCommentAction->setEnabled(policy.allowsProjectEditing); | |||
| ui_->deleteLogicAction->setEnabled(policy.allowsProjectEditing); | |||
| @@ -132,6 +132,7 @@ private: | |||
| void addLogicParallelBranch(const LogicNodeConfig &config); | |||
| // 设置当前网络右侧的输出线圈 | |||
| void setLogicOutput(const LogicNodeConfig &config); | |||
| void configureAndSetLogicOutput(const LogicNodeConfig &config); | |||
| // 新增一个梯形图网络 | |||
| void addLogicRung(); | |||
| void editSelectedRungComment(); | |||
| @@ -330,10 +330,16 @@ | |||
| <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"/> | |||
| <addaction name="deleteLogicAction"/> | |||
| @@ -1018,6 +1024,10 @@ | |||
| <string>添加离线仿真定时器触点</string> | |||
| </property> | |||
| </action> | |||
| <action name="addCounterContactAction"> | |||
| <property name="text"><string>C 触点</string></property> | |||
| <property name="toolTip"><string>添加离线仿真计数器完成触点</string></property> | |||
| </action> | |||
| <action name="addNormalCoilAction"> | |||
| <property name="text"> | |||
| <string>线圈</string> | |||
| @@ -1050,6 +1060,26 @@ | |||
| <string>设置非保持接通延时定时器输出</string> | |||
| </property> | |||
| </action> | |||
| <action name="addCtuAction"> | |||
| <property name="text"><string>CTU</string></property> | |||
| <property name="toolTip"><string>设置按上升沿执行的加计数器</string></property> | |||
| </action> | |||
| <action name="addCtdAction"> | |||
| <property name="text"><string>CTD</string></property> | |||
| <property name="toolTip"><string>设置按上升沿执行的减计数器</string></property> | |||
| </action> | |||
| <action name="addMoveAction"> | |||
| <property name="text"><string>MOVE</string></property> | |||
| <property name="toolTip"><string>设置 D 数据传送指令</string></property> | |||
| </action> | |||
| <action name="addAddAction"> | |||
| <property name="text"><string>ADD</string></property> | |||
| <property name="toolTip"><string>设置带饱和处理的加法指令</string></property> | |||
| </action> | |||
| <action name="addSubAction"> | |||
| <property name="text"><string>SUB</string></property> | |||
| <property name="toolTip"><string>设置带饱和处理的减法指令</string></property> | |||
| </action> | |||
| <action name="addCompareAction"> | |||
| <property name="text"> | |||
| <string>D 比较</string> | |||
| @@ -18,6 +18,7 @@ SOURCES += \ | |||
| ../src/ui/runtime_monitor_widget.cpp \ | |||
| ../src/ui/hmi_editor_widget.cpp \ | |||
| ../src/ui/logic_editor_widget.cpp \ | |||
| ../src/ui/logic_instruction_dialog.cpp \ | |||
| ../src/domain/register_address.cpp \ | |||
| ../src/domain/register_repository.cpp \ | |||
| ../src/domain/active_register_repository.cpp \ | |||
| @@ -49,6 +50,7 @@ HEADERS += \ | |||
| ../src/ui/runtime_monitor_widget.h \ | |||
| ../src/ui/hmi_editor_widget.h \ | |||
| ../src/ui/logic_editor_widget.h \ | |||
| ../src/ui/logic_instruction_dialog.h \ | |||
| ../src/domain/register_address.h \ | |||
| ../src/domain/register_repository.h \ | |||
| ../src/domain/active_register_repository.h \ | |||
| @@ -81,4 +83,5 @@ FORMS += \ | |||
| ../src/ui/register_comment_dialog.ui \ | |||
| ../src/ui/plc_connection_dialog.ui \ | |||
| ../src/ui/free_monitor_widget.ui \ | |||
| ../src/ui/runtime_monitor_widget.ui | |||
| ../src/ui/runtime_monitor_widget.ui \ | |||
| ../src/ui/logic_instruction_dialog.ui | |||