/** * @file TriggerBar.cpp */ #include "TriggerBar.h" #include "Hub.h" #include "Theme.h" #include #include #include #include #include #include #include #include #include namespace shq { /* Window presets (100 us .. 10 s), mirrors the web UI. */ static const double kWinVals[] = {1e-4, 1e-3, 1e-2, 1e-1, 1.0, 10.0}; static const char* kWinLabels[] = {"100 us", "1 ms", "10 ms", "100 ms", "1 s", "10 s"}; static const int kNumWins = 6; static const char* kEdgeWire[] = {"rising", "falling", "both"}; TriggerBar::TriggerBar(Hub* hub, QWidget* parent) : QWidget(parent), hub_(hub) { auto* lay = new QHBoxLayout(this); lay->setContentsMargins(6, 2, 6, 2); lay->setSpacing(6); lay->addWidget(new QLabel("Trig:", this)); sigCombo_ = new QComboBox(this); sigCombo_->setMinimumWidth(150); lay->addWidget(sigCombo_); edgeCombo_ = new QComboBox(this); edgeCombo_->addItems({"Rising", "Falling", "Both"}); lay->addWidget(edgeCombo_); lay->addWidget(new QLabel("Thr", this)); thrSpin_ = new QDoubleSpinBox(this); thrSpin_->setRange(-1e12, 1e12); thrSpin_->setDecimals(6); thrSpin_->setMaximumWidth(100); lay->addWidget(thrSpin_); lay->addWidget(new QLabel("Win", this)); winCombo_ = new QComboBox(this); for (int i = 0; i < kNumWins; i++) { winCombo_->addItem(kWinLabels[i]); } winCombo_->setCurrentIndex(3); /* 100 ms */ lay->addWidget(winCombo_); lay->addWidget(new QLabel("Pre", this)); preSlider_ = new QSlider(Qt::Horizontal, this); preSlider_->setRange(0, 100); preSlider_->setValue(20); preSlider_->setMaximumWidth(90); lay->addWidget(preSlider_); preLbl_ = new QLabel("20%", this); preLbl_->setMinimumWidth(34); lay->addWidget(preLbl_); normRadio_ = new QRadioButton("Norm", this); singleRadio_ = new QRadioButton("1x", this); normRadio_->setChecked(true); auto* grp = new QButtonGroup(this); grp->addButton(normRadio_); grp->addButton(singleRadio_); lay->addWidget(normRadio_); lay->addWidget(singleRadio_); badge_ = new QLabel("[IDLE]", this); badge_->setMinimumWidth(90); lay->addWidget(badge_); armBtn_ = new QPushButton("Arm", this); disarmBtn_ = new QPushButton("Disarm", this); stopBtn_ = new QPushButton("Stop", this); lay->addWidget(armBtn_); lay->addWidget(disarmBtn_); lay->addWidget(stopBtn_); trigTimeLbl_ = new QLabel("", this); trigTimeLbl_->setStyleSheet("color:#a6adc8;"); lay->addWidget(trigTimeLbl_); lay->addStretch(1); /* ── Wiring ── */ auto cfg = [this]() { if (!updating_) { pullFromUi(); sendConfig(); } }; connect(sigCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, [cfg](int){ cfg(); }); connect(edgeCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, [cfg](int){ cfg(); }); connect(thrSpin_, &QDoubleSpinBox::editingFinished, this, cfg); connect(winCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, [cfg](int){ cfg(); }); connect(preSlider_, &QSlider::valueChanged, this, [this](int v) { preLbl_->setText(QString("%1%").arg(v)); }); connect(preSlider_, &QSlider::sliderReleased, this, cfg); connect(normRadio_, &QRadioButton::toggled, this, [cfg](bool){ cfg(); }); connect(armBtn_, &QPushButton::clicked, this, [this]() { pullFromUi(); sendConfig(); hub_->sendArm(); }); connect(disarmBtn_, &QPushButton::clicked, this, [this]() { hub_->sendDisarm(); }); connect(stopBtn_, &QPushButton::clicked, this, [this]() { auto& t = hub_->trigger(); t.stopped = !t.stopped; hub_->sendTrigStop(t.stopped); }); refreshSignals(); onTriggerStateChanged(); } void TriggerBar::pullFromUi() { auto& t = hub_->trigger(); t.signalKey = sigCombo_->currentData().toString().toStdString(); t.edge = edgeCombo_->currentIndex(); t.threshold = thrSpin_->value(); t.windowSec = kWinVals[winCombo_->currentIndex()]; t.prePercent = preSlider_->value(); t.single = singleRadio_->isChecked(); } void TriggerBar::sendConfig() { auto& t = hub_->trigger(); if (t.signalKey.empty()) { return; } hub_->sendSetTrigger(t.signalKey, kEdgeWire[t.edge], t.threshold, t.windowSec, t.prePercent, t.single ? "single" : "normal"); } void TriggerBar::refreshSignals() { updating_ = true; QString prev = sigCombo_->currentData().toString(); sigCombo_->clear(); for (const auto& src : hub_->sources()) { for (const auto& sig : src.signals) { QString key = QString::fromStdString(src.id + ":" + sig.meta.name); sigCombo_->addItem(key, key); } } int idx = sigCombo_->findData(prev); if (idx >= 0) { sigCombo_->setCurrentIndex(idx); } updating_ = false; } void TriggerBar::onTriggerStateChanged() { const auto& t = hub_->trigger(); QString badge; QColor c; if (t.status == "armed") { badge = "[ARMED]"; c = col::yellow(); } else if (t.status == "collecting") { badge = "[COLLECTING]"; c = col::blue(); } else if (t.status == "triggered") { badge = "[TRIGGERED]"; c = col::green(); } else { badge = "[IDLE]"; c = col::overlay0(); } badge_->setText(badge); badge_->setStyleSheet(QString("color:%1; font-weight:bold;").arg(c.name())); stopBtn_->setVisible(!t.single); stopBtn_->setText(t.stopped ? "Run" : "Stop"); if (t.hasTrigTime && (t.status == "collecting" || t.status == "triggered")) { trigTimeLbl_->setText(QString("t=%1").arg(t.trigTime, 0, 'f', 6)); } else { trigTimeLbl_->clear(); } } } /* namespace shq */