Quellcode durchsuchen

初步完善界面的控制

zhuizhu vor 7 Monaten
Ursprung
Commit
e7c4002260

+ 111 - 38
MainPanel.cpp

@@ -122,6 +122,32 @@ QIcon createAudioDeviceIcon()
 
     return QIcon(icon);
 }
+
+QIcon createStreamIcon()
+{
+    QPixmap icon(24, 24);
+    icon.fill(Qt::transparent);
+
+    QPainter painter(&icon);
+    painter.setRenderHint(QPainter::Antialiasing);
+
+    // 绘制推流图标(播放按钮+信号波纹)
+    painter.setPen(QPen(Qt::white, 1.5));
+    painter.setBrush(Qt::white);
+    
+    // 播放按钮(三角形)
+    QPolygon triangle;
+    triangle << QPoint(6, 4) << QPoint(6, 20) << QPoint(18, 12);
+    painter.drawPolygon(triangle);
+    
+    // 信号波纹
+    painter.setBrush(Qt::NoBrush);
+    painter.drawArc(16, 8, 4, 8, 0, 180 * 16);
+    painter.drawArc(18, 6, 4, 12, 0, 180 * 16);
+    painter.drawArc(20, 4, 4, 16, 0, 180 * 16);
+
+    return QIcon(icon);
+}
 } // namespace IconUtils
 
 MainPanel::MainPanel(QWidget *parent)
@@ -139,6 +165,8 @@ MainPanel::MainPanel(QWidget *parent)
     webSocketClient = new WebSocketClient(this);
     chatView = new ChatWindow(webSocketClient);
     chatView->setMinimumWidth(400);
+    // 连接聊天窗口关闭请求信号
+    connect(chatView, &ChatWindow::windowCloseRequested, this, &MainPanel::onChatWindowCloseRequested);
     statsWidget = new StatsWidget(this);
 
     QWidget *rightWidget = new QWidget;
@@ -146,7 +174,13 @@ MainPanel::MainPanel(QWidget *parent)
     vbox->setContentsMargins(0, 0, 0, 0);
     vbox->addWidget(userProfile, 0);
     vbox->addWidget(statsWidget, 0);
-    vbox->addWidget(chatView, 1);
+    
+    // 创建聊天窗口容器
+    m_chatContainer = new QWidget(rightWidget);
+    QVBoxLayout *chatLayout = new QVBoxLayout(m_chatContainer);
+    chatLayout->setContentsMargins(0, 0, 0, 0);
+    chatLayout->addWidget(chatView);
+    vbox->addWidget(m_chatContainer, 1);
 
     splitter = new QSplitter(Qt::Horizontal, this);
     playerContainer = new QWidget(this);
@@ -235,19 +269,22 @@ MainPanel::MainPanel(QWidget *parent)
     // 按钮区域
     QHBoxLayout *buttonLayout = new QHBoxLayout();
     m_recordButton = new QPushButton(tr("开始录制"), audioContent);
-    m_streamButton = new QPushButton(tr("开始推流"), audioContent);
     m_settingsButton = new QPushButton(tr("设置"), audioContent);
     
     buttonLayout->addWidget(m_recordButton);
-    buttonLayout->addWidget(m_streamButton);
     buttonLayout->addWidget(m_settingsButton);
     audioLayout->addLayout(buttonLayout);
 
+    // 创建独立的推流按钮
+    m_streamButton = new FunctionButton(IconUtils::createStreamIcon(), "推流", this);
+
     audioDevicePopover->setContentWidget(audioContent);
 
     // 将按钮与 Popover 关联
     buttonGroup->addButton(audioDeviceBtn, audioDevicePopover);
 
+    // 添加独立的推流按钮到buttonGroup
+    buttonGroup->addButton(m_streamButton);
     // 设备枚举与填充逻辑
     auto populateAudioDevices = [this]() {
         // 清空缓存
@@ -481,10 +518,6 @@ MainPanel::~MainPanel()
         m_avPlayerStandalone->deleteLater();
         m_avPlayerStandalone = nullptr;
     }
-    if (m_chatStandalone) {
-        m_chatStandalone->deleteLater();
-        m_chatStandalone = nullptr;
-    }
 }
 void MainPanel::setRole(const QStringList &roleList)
 {
@@ -513,9 +546,6 @@ void MainPanel::setPushRoomId(const QString &id)
 
     // 重新进入房间
     chatView->initWebsocket(id);
-    if (m_chatStandalone) {
-        m_chatStandalone->initWebsocket(id);
-    }
 
     if (AVPlayerWidget *playWidget = qobject_cast<AVPlayerWidget *>(playerWidget)) {
         MaskOverlay::instance()->show(nullptr, 0, MaskOverlay::ActiveWindow);
@@ -689,36 +719,49 @@ void MainPanel::showPlayerStandalone()
 
 void MainPanel::showChatStandalone()
 {
-    if (!m_chatStandalone) {
-        m_chatStandalone = new ChatWindow(webSocketClient);
-        m_chatStandalone->setAttribute(Qt::WA_DeleteOnClose, false);
-        connect(m_chatStandalone, &QObject::destroyed, this, [this]() {
-            m_chatStandalone = nullptr;
-        });
-        m_chatStandalone->setMinimumWidth(400);
-        m_chatStandalone->setWindowTitle(tr("ChatWindow"));
-        // 同步当前房间
-        if (webSocketClient) {
-            const QString rid = webSocketClient->roomId();
-            if (!rid.isEmpty()) {
-                m_chatStandalone->initWebsocket(rid);
-            }
-        }
+    if (!chatView) {
+        return; // 如果聊天窗口不存在,直接返回
     }
-    m_chatStandalone->show();
-    m_chatStandalone->raise();
-    m_chatStandalone->activateWindow();
+    
+    // 从容器中移除聊天窗口(如果在容器中)
+    if (m_chatContainer && chatView->parent() == m_chatContainer) {
+        chatView->setParent(nullptr);
+    }
+    
+    // 设置为独立窗口
+    chatView->setWindowFlags(Qt::Window);
+    chatView->setAttribute(Qt::WA_DeleteOnClose, false);
+    chatView->setMinimumWidth(400);
+    chatView->setWindowTitle(tr("ChatWindow"));
+    chatView->show();
+    chatView->raise();
+    chatView->activateWindow();
 }
 
 void MainPanel::showChatEmbedded()
 {
-    if (chatView) {
+    if (!chatView) {
+        return; // 如果聊天窗口不存在,直接返回
+    }
+    
+    // 如果当前是独立窗口模式,先隐藏
+    if (chatView->isWindow()) {
+        chatView->hide();
+    }
+    
+    // 重置窗口标志为普通widget
+    chatView->setWindowFlags(Qt::Widget);
+    
+    // 将聊天窗口重新添加到容器中
+    if (m_chatContainer) {
+        chatView->setParent(m_chatContainer);
+        // 如果容器有布局,将聊天窗口添加到布局中
+        if (m_chatContainer->layout()) {
+            m_chatContainer->layout()->addWidget(chatView);
+        }
         chatView->show();
         chatView->raise();
     }
-    if (m_chatStandalone) {
-        m_chatStandalone->hide();
-    }
 }
 
 // 新增:录制控制按钮的槽函数实现
@@ -746,21 +789,36 @@ void MainPanel::onStreamButtonClicked()
 {
     if (RecorderWidget *rec = qobject_cast<RecorderWidget *>(playerWidget)) {
         // 同步选项设置到RecorderWidget
-        
-        // 调用RecorderWidget的推流方法
+
         rec->onStreamButtonClicked();
-        
-        // 更新按钮文本
+
+        // 更新按钮文本和状态
         if (m_streamButton) {
-            if (m_streamButton->text() == tr("开始推流")) {
+            if (!m_isStreaming) {
+                // 开始推流
                 m_streamButton->setText(tr("停止推流"));
+                m_isStreaming = true;
+                
+                // 隐藏预览
+                rec->hidePreview();
+                
+                // 显示独立聊天窗口
+                showChatStandalone();
+
             } else {
-                m_streamButton->setText(tr("开始推流"));
+                // 停止推流
+                m_streamButton->setText(tr("推流"));
+                m_isStreaming = false;
+                
+                // 恢复预览显示
+                rec->showPreview();
             }
         }
     }
 }
 
+
+
 void MainPanel::onSettingsButtonClicked()
 {
     if (RecorderWidget *rec = qobject_cast<RecorderWidget *>(playerWidget)) {
@@ -768,3 +826,18 @@ void MainPanel::onSettingsButtonClicked()
         rec->onSettingsButtonClicked();
     }
 }
+
+void MainPanel::onChatWindowCloseRequested()
+{
+    if (!chatView) {
+        return;
+    }
+    
+    if (m_isStreaming) {
+        // 推流状态下,只隐藏窗口
+        chatView->hide();
+    } else {
+        // 非推流状态下,切换回嵌入式显示
+        showChatEmbedded();
+    }
+}

+ 10 - 5
MainPanel.h

@@ -62,12 +62,11 @@ private:
     QWidget *playerContainer = nullptr;
     QWidget *playerWidget = nullptr;
     UserProfileWidget *userProfile = nullptr;
-    ChatWindow *chatView = nullptr;           // 嵌入式聊天窗口
-
-    // 新增:独立窗口实例
+    ChatWindow *chatView = nullptr;           // 统一的聊天窗口实例
+    // 新增:独立显示的窗口
     RecorderWidget *m_recorderStandalone = nullptr;
     AVPlayerWidget *m_avPlayerStandalone = nullptr;
-    ChatWindow *m_chatStandalone = nullptr;   // 独立显示的聊天窗口
+    QWidget *m_chatContainer = nullptr;       // 聊天窗口的容器(用于嵌入式显示)
 
     WebSocketClient *webSocketClient = nullptr;
     StatsWidget *statsWidget = nullptr;
@@ -94,7 +93,7 @@ private:
 
     // 新增:录制控制按钮(从RecorderWidget移动过来)
     QPushButton *m_recordButton = nullptr;        // 开始录制按钮
-    QPushButton *m_streamButton = nullptr;        // 开始推流按钮
+    class FunctionButton *m_streamButton = nullptr;        // 开始推流按钮(独立FunctionButton)
     QPushButton *m_settingsButton = nullptr;      // 设置按钮
     QCheckBox *m_drawCursorCheckBox = nullptr;    // 绘制鼠标指针选项
     QCheckBox *m_syncRecordCheckBox = nullptr;    // 推流时同步录制选项
@@ -102,6 +101,9 @@ private:
     // DockManager 相关
     ADS::DockManager *m_dockManager = nullptr;
     
+    // 推流状态跟踪
+    bool m_isStreaming = false;
+    
 private slots:
     void initAudioDeviceSelectors();
     
@@ -109,4 +111,7 @@ private slots:
     void onRecordButtonClicked();
     void onStreamButtonClicked();
     void onSettingsButtonClicked();
+    
+    // 聊天窗口关闭处理
+    void onChatWindowCloseRequested();
 };

+ 9 - 0
widgets/chatView/chatwindow.cpp

@@ -149,3 +149,12 @@ void ChatWindow::onRecallClicked()
     // QString name = (direction == BubbleMessage::Sent) ? "你" : "对方";
     // m_messageView->addRecallMessage(name, direction);
 }
+
+void ChatWindow::closeEvent(QCloseEvent *event)
+{
+    // 阻止默认关闭行为
+    event->ignore();
+    
+    // 发出关闭请求信号,让MainPanel处理
+    emit windowCloseRequested();
+}

+ 7 - 0
widgets/chatView/chatwindow.h

@@ -8,6 +8,7 @@
 #include <QMainWindow>
 #include <QPushButton>
 #include <QVBoxLayout>
+#include <QCloseEvent>
 #include "network/websocketclient.h"
 
 class ChatView;
@@ -20,6 +21,12 @@ public:
 
     void initWebsocket(const QString &roomId);
 
+protected:
+    void closeEvent(QCloseEvent *event) override;
+
+signals:
+    void windowCloseRequested();
+
 private slots:
     void onSendClicked();
 

+ 35 - 0
widgets/functionbutton.cpp

@@ -322,6 +322,17 @@ FunctionButton::FunctionButton(const QIcon& icon, const QString& text, QWidget*
     setCursor(Qt::PointingHandCursor);
 }
 
+void FunctionButton::setText(const QString& text)
+{
+    m_text = text;
+    update(); // 触发重绘
+}
+
+QString FunctionButton::text() const
+{
+    return m_text;
+}
+
 void FunctionButton::paintEvent(QPaintEvent* event)
 {
     Q_UNUSED(event);
@@ -452,6 +463,30 @@ void PopoverButtonGroup::addPopoverToButton(FunctionButton* button, Popover* pop
     }
 }
 
+void PopoverButtonGroup::removeButton(FunctionButton* button)
+{
+    if (!buttons.contains(button))
+        return;
+
+    // 移除按钮从列表中
+    buttons.removeAll(button);
+
+    // 如果有关联的Popover按钮,也要移除
+    if (buttonPopoverMap.contains(button)) {
+        QPushButton* popoverBtn = buttonPopoverMap[button];
+        popoverMap.remove(popoverBtn);
+        buttonPopoverMap.remove(button);
+        popoverBtn->deleteLater();
+    }
+
+    // 找到按钮所在的容器并从布局中移除
+    QWidget* container = button->parentWidget();
+    if (container && container->parentWidget() == this) {
+        layout->removeWidget(container);
+        container->deleteLater();
+    }
+}
+
 QPushButton* PopoverButtonGroup::createPopoverTriggerButton()
 {
     auto btn = new PopoverTriggerButton(this);

+ 6 - 0
widgets/functionbutton.h

@@ -66,6 +66,9 @@ class FunctionButton : public QPushButton
     Q_OBJECT
 public:
     FunctionButton(const QIcon& icon, const QString& text, QWidget* parent = nullptr);
+    
+    void setText(const QString& text);
+    QString text() const;
 
 protected:
     void paintEvent(QPaintEvent* event) override;
@@ -90,6 +93,9 @@ public:
 
     // 为已有按钮添加Popover
     void addPopoverToButton(FunctionButton* button, Popover* popover);
+    
+    // 移除按钮
+    void removeButton(FunctionButton* button);
 
 protected:
     QSize sizeHint() const override;

+ 21 - 1
widgets/recorderwidget.cpp

@@ -566,12 +566,32 @@ void RecorderWidget::onSettingsButtonClicked()
 
 void RecorderWidget::updatePreview()
 {
-    // 预览更新在回调函数中处理
     if (m_previewWidget && m_previewWidth > 0 && m_previewHeight > 0) {
         m_previewWidget->update();
     }
 }
 
+// 预览显示控制方法实现
+void RecorderWidget::showPreview()
+{
+    if (m_previewWidget) {
+        m_previewWidget->show();
+    }
+}
+
+void RecorderWidget::hidePreview()
+{
+    if (m_previewWidget) {
+        m_previewWidget->hide();
+    }
+}
+
+bool RecorderWidget::isPreviewVisible() const
+{
+    return m_previewWidget ? m_previewWidget->isVisible() : false;
+}
+
+
 void RecorderWidget::updateStatus()
 {
     if (m_isRecording || m_isStreaming) {

+ 5 - 0
widgets/recorderwidget.h

@@ -73,6 +73,11 @@ public:
     void onStreamButtonClicked();
     void onSettingsButtonClicked();
     
+    // 预览显示控制
+    void showPreview();
+    void hidePreview();
+    bool isPreviewVisible() const;
+    
     // 获取状态栏
     QWidget* statusBar() const { return m_statusBar; }