267 lines
8.7 KiB
C++
267 lines
8.7 KiB
C++
// deviceview.cpp - one controller below the tabs (see deviceview.h)
|
|
|
|
#include "deviceview.h"
|
|
|
|
#include "panelwidget.h"
|
|
#include "remoteclient.h"
|
|
#include "style.h"
|
|
|
|
#include <QComboBox>
|
|
#include <QCoreApplication>
|
|
#include <QDesktopServices>
|
|
#include <QDir>
|
|
#include <QFileInfo>
|
|
#include <QFontMetrics>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QUrl>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <algorithm>
|
|
|
|
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<AdvCtrl::PortInfo> 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);
|
|
}
|