|
|
|
|
@ -16,6 +16,7 @@ extern "C" {
|
|
|
|
|
#include <QActionGroup> |
|
|
|
|
#include <QSignalBlocker> |
|
|
|
|
#include <QStyle> |
|
|
|
|
#include <QMouseEvent> |
|
|
|
|
#include <cstring> |
|
|
|
|
|
|
|
|
|
RadioPanel::RadioPanel(QWidget* parent) : QWidget(parent) { |
|
|
|
|
@ -52,13 +53,18 @@ RadioPanel::RadioPanel(QWidget* parent) : QWidget(parent) {
|
|
|
|
|
m_ptt = new QPushButton(QStringLiteral("PTT"), this); |
|
|
|
|
m_ptt->setObjectName(QStringLiteral("radioPttButton")); |
|
|
|
|
m_ptt->setAccessibleName(QCoreApplication::translate("ChatGui", "Hold to talk")); |
|
|
|
|
m_ptt->setToolTip(QCoreApplication::translate("ChatGui", "Hold the button or a global shortcut to transmit")); |
|
|
|
|
m_ptt->installEventFilter(this); |
|
|
|
|
m_ptt->setFixedSize(64, 34); |
|
|
|
|
m_ptt->setStyleSheet("QPushButton[transmitting=\"true\"] { background: #27ae60; color: white; }"); |
|
|
|
|
row->addWidget(m_ptt); |
|
|
|
|
auto* engine = RadioAudioEngine::instance(); |
|
|
|
|
connect(m_ptt, &QPushButton::pressed, engine, &RadioAudioEngine::talkBegin); |
|
|
|
|
connect(m_ptt, &QPushButton::released, engine, &RadioAudioEngine::talkEnd); |
|
|
|
|
connect(m_ptt, &QPushButton::pressed, this, [this, engine]() { |
|
|
|
|
if (m_pttLatched) setPttLatched(false, "button-pressed"); |
|
|
|
|
else engine->talkBegin(); |
|
|
|
|
}); |
|
|
|
|
connect(m_ptt, &QPushButton::released, this, [this, engine]() { |
|
|
|
|
if (!m_pttLatched) engine->talkEnd(); |
|
|
|
|
}); |
|
|
|
|
connect(m_vad, &QPushButton::clicked, this, [this](bool checked) { |
|
|
|
|
RadioAudioEngine::instance()->applySettings({{QStringLiteral("radio_vad_enabled"), checked ? 1 : 0}}); |
|
|
|
|
updateState(); |
|
|
|
|
@ -69,12 +75,47 @@ RadioPanel::RadioPanel(QWidget* parent) : QWidget(parent) {
|
|
|
|
|
updateDevices(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RadioPanel::~RadioPanel() { |
|
|
|
|
if (m_pttLatched) setPttLatched(false, "panel-destroyed"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Второе нажатие Qt приходит как DoubleClick: не отдаём его обычному переключателю pressed. */ |
|
|
|
|
bool RadioPanel::eventFilter(QObject* watched, QEvent* event) { |
|
|
|
|
if (watched == m_ptt && event->type() == QEvent::MouseButtonDblClick && m_ptt->isEnabled()) { |
|
|
|
|
auto* mouse = static_cast<QMouseEvent*>(event); |
|
|
|
|
if (mouse->button() == Qt::LeftButton && m_ptt->rect().contains(mouse->pos())) { |
|
|
|
|
setPttLatched(true, "double-click"); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return QWidget::eventFilter(watched, event); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Фиксация владеет только кнопочным PTT; хоткей и автоматическая передача остаются независимыми. */ |
|
|
|
|
void RadioPanel::setPttLatched(bool latched, const char* reason) { |
|
|
|
|
if (m_pttLatched == latched) return; |
|
|
|
|
m_pttLatched = latched; |
|
|
|
|
auto* engine = RadioAudioEngine::instance(); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_RADIO, "RadioPanel: PTT %s group=%016llx reason=%s", |
|
|
|
|
latched ? "latched (click to release)" : "latch released", (unsigned long long)engine->groupId(), reason); |
|
|
|
|
if (latched) engine->talkBegin(); |
|
|
|
|
else engine->talkEnd(); |
|
|
|
|
updateState(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RadioPanel::updateState() { |
|
|
|
|
auto* engine = RadioAudioEngine::instance(); |
|
|
|
|
if (m_pttLatched && (!engine->isActive() || !engine->captureAvailable())) |
|
|
|
|
setPttLatched(false, engine->isActive() ? "microphone-unavailable" : "radio-stopped"); |
|
|
|
|
QSignalBlocker blocker(m_vad); |
|
|
|
|
m_vad->setChecked(engine->vadEnabled()); |
|
|
|
|
m_vad->setEnabled(engine->isActive() && engine->settingsReady() && !engine->settingsBusy()); |
|
|
|
|
m_ptt->setEnabled(engine->isActive() && engine->captureAvailable()); |
|
|
|
|
m_ptt->setText(m_pttLatched ? QStringLiteral("PTT \U0001F512") : QStringLiteral("PTT")); |
|
|
|
|
m_ptt->setToolTip(m_pttLatched ? QCoreApplication::translate("ChatGui", "PTT locked. Click to release.") |
|
|
|
|
: QCoreApplication::translate("ChatGui", "Hold to talk, or double-click to lock PTT. Click again to release. Global shortcuts also work.")); |
|
|
|
|
m_ptt->setAccessibleName(m_pttLatched ? QCoreApplication::translate("ChatGui", "PTT locked. Click to release.") |
|
|
|
|
: QCoreApplication::translate("ChatGui", "Hold to talk")); |
|
|
|
|
bool transmitting = engine->isTransmitting(); |
|
|
|
|
if (m_ptt->property("transmitting").toBool() != transmitting || !m_ptt->property("transmitting").isValid()) { |
|
|
|
|
m_ptt->setProperty("transmitting", transmitting); |
|
|
|
|
|