diff --git a/tools/chatgui/src/accountdelegate.cpp b/tools/chatgui/src/accountdelegate.cpp index 8c8d0986..b58ad855 100644 --- a/tools/chatgui/src/accountdelegate.cpp +++ b/tools/chatgui/src/accountdelegate.cpp @@ -23,18 +23,22 @@ static QRect radioMuteButtonRect(const QRect& row) { return QRect(row.right() - 63, row.center().y() - 14, 28, 28); } -static void drawRadioMuteButton(QPainter* painter, const QRect& button, bool muted) { +// Волны показывают передачу, красное перечёркивание имеет приоритет при локальном mute. +static void drawRadioMuteButton(QPainter* painter, const QRect& button, bool muted, bool speaking) { painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->translate(button.center()); - QColor color(muted ? "#EF5350" : "#4CAF50"); + QColor color(muted ? "#EF5350" : speaking ? "#4CAF50" : "#9E9E9E"); QPainterPath speaker; speaker.moveTo(-8, -3); speaker.lineTo(-4, -3); speaker.lineTo(1, -7); speaker.lineTo(1, 7); speaker.lineTo(-4, 3); speaker.lineTo(-8, 3); speaker.closeSubpath(); painter->fillPath(speaker, color); painter->setPen(QPen(color, 1.8, Qt::SolidLine, Qt::RoundCap)); painter->setBrush(Qt::NoBrush); - painter->drawArc(QRectF(-3, -5, 10, 10), -60 * 16, 120 * 16); - painter->drawArc(QRectF(-6, -8, 16, 16), -60 * 16, 120 * 16); + if (muted) painter->drawLine(QPointF(-10, 10), QPointF(10, -10)); + else if (speaking) { + painter->drawArc(QRectF(-3, -5, 10, 10), -60 * 16, 120 * 16); + painter->drawArc(QRectF(-6, -8, 16, 16), -60 * 16, 120 * 16); + } painter->restore(); } @@ -69,7 +73,7 @@ void AccountDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio const int x = option.rect.left() + iconSz + margin * 3; const bool canInvite = !index.data(Qt::UserRole + 2).toBool(); - const int w = option.rect.right() - x - margin - (canInvite ? 64 : 0); + const int w = option.rect.right() - x - margin - 64; const int yMid = option.rect.top() + option.rect.height() / 2; uint8_t flags = (uint8_t)(index.data(Qt::UserRole + 3).toInt() & 0xFF); @@ -117,8 +121,9 @@ void AccountDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio painter->drawText(QRect(flagX, yMid + 2, w - (flagX - x), option.rect.bottom() - yMid - 2), Qt::AlignLeft | Qt::AlignTop, sub); + drawRadioMuteButton(painter, radioMuteButtonRect(option.rect), flags & CHAT_MEMBER_FLAG_RADIO_MUTED, + index.data(MemberListModel::RadioSpeakingRole).toBool()); if (canInvite) { - drawRadioMuteButton(painter, radioMuteButtonRect(option.rect), flags & CHAT_MEMBER_FLAG_RADIO_MUTED); QFont plusFont = nameFont; plusFont.setPixelSize(22); plusFont.setStrikeOut(false); painter->setFont(plusFont); painter->setPen(option.palette.color(QPalette::Link)); @@ -168,10 +173,13 @@ bool AccountDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, cons bool AccountDelegate::helpEvent(QHelpEvent* event, QAbstractItemView* view, const QStyleOptionViewItem& option, const QModelIndex& index) { - if (event && !index.data(Qt::UserRole + 2).toBool() && radioMuteButtonRect(option.rect).contains(event->pos())) { + if (event && radioMuteButtonRect(option.rect).contains(event->pos())) { const bool muted = index.data(Qt::UserRole + 3).toInt() & CHAT_MEMBER_FLAG_RADIO_MUTED; - QToolTip::showText(event->globalPos(), QCoreApplication::translate("ChatGui", - muted ? "Listen to this member in radio" : "Mute this member in radio"), view); + const bool speaking = index.data(MemberListModel::RadioSpeakingRole).toBool(); + QString text = QCoreApplication::translate("ChatGui", muted ? "Radio: muted" : speaking ? "Radio: speaking" : "Radio: silent"); + if (!index.data(Qt::UserRole + 2).toBool()) text += '\n' + QCoreApplication::translate("ChatGui", + muted ? "Listen to this member in radio" : "Mute this member in radio"); + QToolTip::showText(event->globalPos(), text, view); return true; } return QStyledItemDelegate::helpEvent(event, view, option, index); diff --git a/tools/chatgui/src/mainwindow.cpp b/tools/chatgui/src/mainwindow.cpp index defaeccf..77fa8444 100644 --- a/tools/chatgui/src/mainwindow.cpp +++ b/tools/chatgui/src/mainwindow.cpp @@ -4,6 +4,7 @@ #include "messagelist.h" #include "messagedelegate.h" #include "accountlist.h" +#include "memberlistmodel.h" #include "invitedialog.h" #include "dminvitedialog.h" #include "debug_ui.h" @@ -201,6 +202,7 @@ MainWindow::~MainWindow() { gui_bridge_set_member_list_cb(nullptr); gui_bridge_set_member_updated_cb(nullptr); gui_bridge_set_member_removed_cb(nullptr); + gui_bridge_set_radio_talk_cb(nullptr); gui_bridge_set_my_node_id_cb(nullptr); gui_bridge_set_auto_connect_status_cb(nullptr); gui_bridge_set_channel_peers_online_cb(nullptr); @@ -530,6 +532,8 @@ void MainWindow::setupBridgeCallbacks() { /* ── рация: индикация говорящего ── */ gui_bridge_set_radio_talk_cb([](uint64_t group_id, uint64_t src_node_id, uint8_t on) { + if (s_mainWindow && s_mainWindow->m_accountList) + s_mainWindow->m_accountList->model()->onRadioTalk(group_id, src_node_id, on != 0); if (s_mainWindow && s_mainWindow->m_messageList) s_mainWindow->m_messageList->onRadioTalk((quint64)group_id, (quint64)src_node_id, on != 0); }); @@ -546,6 +550,7 @@ void MainWindow::setupBridgeCallbacks() { gui_bridge_set_network_changed_cb([](int type) { if (!s_mainWindow) return; if (type == 13) { + s_mainWindow->m_accountList->model()->setRadioState(0, false, false); s_mainWindow->m_messageList->clearDmCallRoute(); s_mainWindow->m_channelList->clearDmPresence(); } else { @@ -567,6 +572,10 @@ void MainWindow::setupBridgeCallbacks() { } void MainWindow::setupConnects() { + connect(RadioAudioEngine::instance(), &RadioAudioEngine::stateChanged, this, [this] { + auto* engine = RadioAudioEngine::instance(); + m_accountList->model()->setRadioState(engine->groupId(), engine->isActive(), engine->isTransmitting()); + }); connect(m_channelList, &ChannelList::channelSelected, this, [this](const QString& channelId) { saveLastChannelId(channelId);