Compare commits

...

2 commits

Author SHA1 Message Date
Carl Philipp Klemm
af9263b041 Fix case where the ganged channel is channel 0 2025-10-13 11:05:21 +02:00
81e7e1a5b3 Implement ganged switches 2025-10-13 10:45:44 +02:00
3 changed files with 241 additions and 133 deletions

View file

@ -32,7 +32,9 @@ ChannelWidget::ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber,
hlayout.addWidget(&ganglabel); hlayout.addWidget(&ganglabel);
hlayout.addWidget(&gangcombo); hlayout.addWidget(&gangcombo);
hlayout.addWidget(&checkbox); hlayout.addWidget(&checkbox);
connect(&checkbox, &QCheckBox::toggled, this, &ChannelWidget::onChannelToggled); connect(&checkbox, &QCheckBox::toggled, this, &ChannelWidget::onChannelToggled);
connect(&gangcombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ChannelWidget::onGangComboChanged);
setFixedHeight(96); setFixedHeight(96);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@ -42,7 +44,7 @@ ChannelWidget::ChannelWidget(uint16_t deviceSerial, uint16_t channelNumber,
ChannelWidget::~ChannelWidget() ChannelWidget::~ChannelWidget()
{ {
// Nothing to clean up
} }
uint16_t ChannelWidget::getDeviceSerial() const uint16_t ChannelWidget::getDeviceSerial() const
@ -78,7 +80,7 @@ void ChannelWidget::onChannelToggled(bool checked)
qWarning() << "Failed to connect channel" << channelNumber << "on device" << deviceSerial; qWarning() << "Failed to connect channel" << channelNumber << "on device" << deviceSerial;
checkbox.blockSignals(true); checkbox.blockSignals(true);
checkbox.setChecked(false); checkbox.setChecked(false);
setEnabled(false); // Gray out the widget setEnabled(false);
} }
} }
else else
@ -90,8 +92,74 @@ void ChannelWidget::onChannelToggled(bool checked)
qWarning() << "Failed to disconnect channel" << channelNumber << "on device" << deviceSerial; qWarning() << "Failed to disconnect channel" << channelNumber << "on device" << deviceSerial;
checkbox.blockSignals(true); checkbox.blockSignals(true);
checkbox.setChecked(true); checkbox.setChecked(true);
setEnabled(false); // Gray out the widget setEnabled(false);
}
}
// Emit state change signal for other channels that might be ganged to this one
emit channelStateChanged(deviceSerial, channelNumber, checked);
}
void ChannelWidget::onGangComboChanged(int index)
{
if (index == 0) {
// Unganged selected - reset ganged channel tracking
gangedDeviceSerial = -1;
gangedChannelNumber = -1;
checkbox.setEnabled(true);
checkbox.setChecked(false);
checkbox.setChecked(false);
} else {
// A ganged channel was selected
QString currentText = gangcombo.currentText();
QStringList parts = currentText.split(", ");
if (parts.size() == 2) {
bool ok1, ok2;
uint16_t gangedSerial = parts[0].toUInt(&ok1);
uint16_t gangedChannel = parts[1].toUInt(&ok2);
if (ok1 && ok2) {
setGangedChannel(gangedSerial, gangedChannel);
}
} }
} }
} }
void ChannelWidget::onOtherChannelStateChanged(uint16_t deviceSerial, uint16_t channelNumber, bool checked)
{
// If this channel is ganged to the channel that changed state
if (gangedDeviceSerial == deviceSerial && gangedChannelNumber == channelNumber) {
// Update our checkbox state to follow the ganged channel
checkbox.blockSignals(true);
checkbox.setChecked(checked);
checkbox.blockSignals(false);
}
}
void ChannelWidget::updateGangCombo()
{
// Clear existing items except "Unganged"
while (gangcombo.count() > 1) {
gangcombo.removeItem(1);
}
}
void ChannelWidget::updateCheckboxState()
{
if (gangedDeviceSerial >= 0 && gangedChannelNumber >= 0) {
checkbox.setEnabled(false);
// TODO check current ganged channel state
} else {
checkbox.setEnabled(true);
}
}
void ChannelWidget::setGangedChannel(uint16_t gangedDeviceSerial, uint16_t gangedChannelNumber)
{
this->gangedDeviceSerial = gangedDeviceSerial;
this->gangedChannelNumber = gangedChannelNumber;
// Update checkbox state to follow the ganged channel
updateCheckboxState();
}

View file

@ -23,13 +23,25 @@ public:
uint16_t getChannelNumber() const; uint16_t getChannelNumber() const;
bool isChecked() const; bool isChecked() const;
signals: // Accessors for MainWindow to populate and access the gang combo
void channelAboutToBeTurnedOn(uint16_t deviceSerial, uint16_t channelNumber); QComboBox* getGangCombo() { return &gangcombo; }
void setGangedChannel(uint16_t deviceSerial, uint16_t channelNumber);
public slots:
void onOtherChannelStateChanged(uint16_t deviceSerial, uint16_t channelNumber, bool checked);
private slots: private slots:
void onChannelToggled(bool checked); void onChannelToggled(bool checked);
void onGangComboChanged(int index);
signals:
void channelAboutToBeTurnedOn(uint16_t deviceSerial, uint16_t channelNumber);
void channelStateChanged(uint16_t deviceSerial, uint16_t channelNumber, bool checked);
private: private:
void updateGangCombo();
void updateCheckboxState();
uint16_t deviceSerial; uint16_t deviceSerial;
uint16_t channelNumber; uint16_t channelNumber;
std::shared_ptr<struct eismultiplexer> multiplexer; std::shared_ptr<struct eismultiplexer> multiplexer;
@ -42,8 +54,11 @@ private:
QVBoxLayout vlayout; QVBoxLayout vlayout;
QHBoxLayout hlayout; QHBoxLayout hlayout;
QVBoxLayout labellayout; QVBoxLayout labellayout;
// Track the channel this one is ganged to (if any)
int gangedDeviceSerial = -1;
int gangedChannelNumber = -1;
}; };
#endif // CHANNELWIDGET_H #endif // CHANNELWIDGET_H

View file

@ -35,6 +35,7 @@ void MainWindow::enumerateDevices()
return; return;
} }
// First pass: create all widgets without connecting signals
for (size_t i = 0; i < count; i++) for (size_t i = 0; i < count; i++)
{ {
uint16_t serial = serials[i]; uint16_t serial = serials[i];
@ -61,9 +62,33 @@ void MainWindow::enumerateDevices()
tr("Failed to connect to device with serial %1").arg(serial)); tr("Failed to connect to device with serial %1").arg(serial));
qWarning()<<"Failed to connect to device with serial"<<serial<<"eismultiplexer_connect returned"<<ret; qWarning()<<"Failed to connect to device with serial"<<serial<<"eismultiplexer_connect returned"<<ret;
} }
ui->channelLayout->addStretch();
} }
ui->channelLayout->addStretch();
// Second pass: populate gang combos and connect signals
for (const auto& widget : channels) {
// Populate gang combo with all other channels
for (const auto& otherWidget : channels) {
if (widget->getDeviceSerial() != otherWidget->getDeviceSerial() ||
widget->getChannelNumber() != otherWidget->getChannelNumber()) {
QString channelText = QString::asprintf("%04u, %u",
otherWidget->getDeviceSerial(),
otherWidget->getChannelNumber());
widget->getGangCombo()->addItem(channelText);
}
}
// Connect state change signals
for (const auto& otherWidget : channels) {
if (widget.get() != otherWidget.get()) {
connect(otherWidget.get(), &ChannelWidget::channelStateChanged,
widget.get(), &ChannelWidget::onOtherChannelStateChanged);
}
}
}
ui->statusbar->showMessage("Ready"); ui->statusbar->showMessage("Ready");
free(serials); free(serials);
} }