// deviceview.cpp - one controller below the tabs (see deviceview.h) #include "deviceview.h" #include "panelwidget.h" #include "remoteclient.h" #include "style.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace { // Button about n characters wide. QPushButton *makeButton(const QString &text, int chars, QWidget *parent) { auto *button = new QPushButton(text, parent); if (chars > 0) button->setMinimumWidth(button->fontMetrics().horizontalAdvance(QLatin1Char('0')) * chars + 16); return button; } } // namespace DeviceView::DeviceView(int index, int baudRate, const QString &port, QWidget *parent) : QWidget(parent), m_index(index), m_baudRate(baudRate), m_link(new AdvCtrl::ControllerLink(this)) { // --- top bar: buttons and the port list --- m_open = makeButton(QStringLiteral("OPEN"), 8, this); m_close = makeButton(QStringLiteral("CLOSE"), 8, this); m_close->setEnabled(false); m_ports = new QComboBox(this); m_ports->setMinimumContentsLength(34); m_ports->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); m_refresh = makeButton(QStringLiteral("Refresh"), 0, this); m_state = new QLabel(this); m_identify = makeButton(QStringLiteral("IDENTIFY"), 9, this); m_identify->setEnabled(false); m_help = makeButton(QStringLiteral("HELP"), 6, this); auto *bar = new QHBoxLayout; bar->setContentsMargins(8, 6, 8, 6); bar->setSpacing(0); bar->addWidget(m_open); bar->addSpacing(4); bar->addWidget(m_close); bar->addSpacing(12); bar->addWidget(m_ports); bar->addSpacing(4); bar->addWidget(m_refresh); bar->addSpacing(16); bar->addWidget(m_state, 1); bar->addSpacing(12); bar->addWidget(m_identify); bar->addSpacing(6); bar->addWidget(m_help); // --- the panel --- m_panel = new PanelWidget(this); auto *panelBox = new QHBoxLayout; panelBox->setContentsMargins(8, 0, 8, 4); panelBox->addWidget(m_panel); // --- bottom: last exchange / messages --- m_last = new QLabel(this); QFont mono(QStringLiteral("Courier New")); mono.setStyleHint(QFont::Monospace); mono.setPointSize(10); m_last->setFont(mono); m_last->setContentsMargins(10, 0, 10, 6); QPalette lastPalette = m_last->palette(); lastPalette.setColor(QPalette::WindowText, Style::Line); m_last->setPalette(lastPalette); auto *root = new QVBoxLayout(this); root->setContentsMargins(0, 0, 0, 0); root->setSpacing(0); root->addLayout(bar); root->addLayout(panelBox, 1); root->addWidget(m_last); setStateText(QStringLiteral("port closed"), Style::Text); connect(m_open, &QPushButton::clicked, this, &DeviceView::openPort); connect(m_close, &QPushButton::clicked, this, &DeviceView::closePort); connect(m_refresh, &QPushButton::clicked, this, &DeviceView::refreshPorts); connect(m_identify, &QPushButton::clicked, this, &DeviceView::identify); connect(m_help, &QPushButton::clicked, this, &DeviceView::openHelp); connect(m_panel, &PanelWidget::keyPressed, this, &DeviceView::sendKey); connect(m_link, &AdvCtrl::ControllerLink::stateChanged, this, &DeviceView::onStateChanged); connect(m_link, &AdvCtrl::ControllerLink::detected, this, &DeviceView::onDetected); connect(m_link, &AdvCtrl::ControllerLink::notDetected, this, &DeviceView::onNotDetected); connect(m_link, &AdvCtrl::ControllerLink::lost, this, &DeviceView::onLost); connect(m_link, &AdvCtrl::ControllerLink::leds, m_panel, &PanelWidget::setLeds); connect(m_link, &AdvCtrl::ControllerLink::reply, this, &DeviceView::onReply); connect(m_link, &AdvCtrl::ControllerLink::error, this, &DeviceView::onError); connect(m_link, &AdvCtrl::ControllerLink::closed, this, &DeviceView::onClosed); refreshPorts(); if (!port.isEmpty()) selectPort(port); } PanelWidget *DeviceView::panel() const { return m_panel; } void DeviceView::setStateText(const QString &text, const QColor &colour) { QPalette palette = m_state->palette(); palette.setColor(QPalette::WindowText, colour); m_state->setPalette(palette); m_state->setText(text); } // ------------------------------------------------------------------------- ports void DeviceView::refreshPorts() { const QString previousDevice = selectedPort(); const QString previousText = m_ports->currentText(); m_ports->clear(); const QList ports = AdvCtrl::RemoteClient::listPorts(); for (const AdvCtrl::PortInfo &port : ports) m_ports->addItem(port.name + QStringLiteral(" ") + port.description, port.name); if (previousDevice.isEmpty()) { if (m_ports->count() > 0) m_ports->setCurrentIndex(std::min(m_index, m_ports->count() - 1)); return; } int i = m_ports->findData(previousDevice); if (i < 0) { // gone: keep showing the selection m_ports->insertItem(0, previousText, previousDevice); i = 0; } m_ports->setCurrentIndex(i); } void DeviceView::selectPort(const QString &device) { int i = m_ports->findData(device); if (i < 0) { m_ports->addItem(device, device); i = m_ports->count() - 1; } m_ports->setCurrentIndex(i); } QString DeviceView::selectedPort() const { return m_ports->currentData().toString(); } void DeviceView::openPort() { const QString device = selectedPort(); if (device.isEmpty()) { setStateText(QStringLiteral("no port selected"), Style::LedOn); return; } m_open->setEnabled(false); setStateText(device + QStringLiteral(": detecting controller ..."), Style::Text); m_link->open(device, m_baudRate); m_close->setEnabled(true); } void DeviceView::closePort() { m_link->close(); m_close->setEnabled(false); } // -------------------------------------------------------------------------- help // Open docs/PANEL_HELP.txt (what every button does) in the system text viewer. void DeviceView::openHelp() { QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QStringLiteral("/../docs/PANEL_HELP.txt")); if (!QFileInfo::exists(path)) { path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QStringLiteral("/../../docs/PANEL_HELP.txt")); } if (!QFileInfo::exists(path)) { m_last->setText(QStringLiteral("help file not found: ") + path); return; } if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path))) m_last->setText(QStringLiteral("cannot open help: ") + path); } // ---------------------------------------------------------------- panel -> device void DeviceView::sendKey(const QString &key) { if (m_link->state() != AdvCtrl::ControllerLink::Link) return; m_link->send(QStringLiteral("KEY ") + key); m_last->setText(QStringLiteral("> KEY ") + key); } // The gear led of this controller blinks fast for 3 s (which device is it). void DeviceView::identify() { if (m_link->state() != AdvCtrl::ControllerLink::Link) return; m_link->send(QStringLiteral("IDENTIFY")); m_last->setText(QStringLiteral("> IDENTIFY")); } // ---------------------------------------------------------------- device -> window void DeviceView::onStateChanged(AdvCtrl::ControllerLink::State state) { const bool link = (state == AdvCtrl::ControllerLink::Link); m_panel->setInteractive(link); m_identify->setEnabled(link); emit stateChanged(m_index, state); } void DeviceView::onDetected(const QString &firmware, const QString &cameras, const QString &uid) { setStateText(QStringLiteral("Controller detected on %1: FW=%2 CAMS=%3 UID=%4") .arg(m_link->portName(), firmware, cameras, uid), Style::Line); } void DeviceView::onNotDetected() { setStateText(QStringLiteral("Controller NOT detected on %1 (retrying ...)").arg(m_link->portName()), Style::LedOn); } void DeviceView::onLost() { setStateText(QStringLiteral("Controller on %1 does not answer (retrying ...)").arg(m_link->portName()), Style::LedOn); m_panel->setLeds(0); } void DeviceView::onReply(const QString &commandLine, const QString &result) { m_last->setText(QStringLiteral("> %1 < %2").arg(commandLine, result)); } void DeviceView::onError(const QString &message) { m_last->setText(message); } void DeviceView::onClosed() { m_panel->setLeds(0); setStateText(QStringLiteral("port closed"), Style::Text); m_open->setEnabled(true); m_close->setEnabled(false); }