From e918d4ca06a89420d23c4b560b36d66828b3d103 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 18:44:20 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E5=9B=BE=E6=A0=87=E5=8A=A0=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/misc/images/images.qrc | 1 + TeXmacs/misc/images/llm-chat/addchat.svg | 478 +++++++++++++++++++++++ 2 files changed, 479 insertions(+) create mode 100644 TeXmacs/misc/images/llm-chat/addchat.svg diff --git a/TeXmacs/misc/images/images.qrc b/TeXmacs/misc/images/images.qrc index 207d1c955c..ba5c8e5eca 100644 --- a/TeXmacs/misc/images/images.qrc +++ b/TeXmacs/misc/images/images.qrc @@ -19,6 +19,7 @@ llm-chat/send.svg llm-chat/sidebar.svg + llm-chat/addchat.svg ocr-button/left-align-white.svg diff --git a/TeXmacs/misc/images/llm-chat/addchat.svg b/TeXmacs/misc/images/llm-chat/addchat.svg new file mode 100644 index 0000000000..50ceb0d611 --- /dev/null +++ b/TeXmacs/misc/images/llm-chat/addchat.svg @@ -0,0 +1,478 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1bba26829fca1f5c0e678acad4ab4bbc4a81bb94 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 18:54:46 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/plugins/lang/dic/en_US/zh_CN.scm | 1 + 1 file changed, 1 insertion(+) diff --git a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm index ece576238c..b180b81672 100644 --- a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm +++ b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm @@ -1550,6 +1550,7 @@ ("new account" "新建账号") ("New Blank Document" "新建空白文档") ("new buffer" "") +("new chat" "开启新对话") ("new column" "添加一行") ("new document" "新建文档") ("new double page before" "新起双页(在前面)") From 4885dd21ce25bb3f5ee2374241dbb29010fa7204 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 18:56:18 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index 3aec0d0969..ba5a853d69 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -330,9 +331,25 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { newChatButton_->setFocusPolicy (Qt::NoFocus); newChatButton_->setCursor (Qt::PointingHandCursor); DpiUtils::applyScaledFont (newChatButton_, kNavButtonFontPx); - newChatButton_->setStyleSheet (QString ("padding: %1px %2px;") - .arg (DpiUtils::scaled (kNavButtonPadY)) - .arg (DpiUtils::scaled (kNavButtonPadX))); + newChatButton_->setIcon (QIcon (":llm-chat/addchat.svg")); + int newChatIconSize= DpiUtils::scaled (18); + newChatButton_->setIconSize (QSize (newChatIconSize, newChatIconSize)); + newChatButton_->setStyleSheet ( + QString ("QPushButton { text-align: left; border: none; " + "border-radius: %1px; padding: %2px %3px; " + "background-color: #ffffff; color: #333333; }" + "QPushButton:hover { background-color: #f0f0f0; }") + .arg (DpiUtils::scaled (6)) + .arg (DpiUtils::scaled (kNavButtonPadY)) + .arg (DpiUtils::scaled (kNavButtonPadX))); + + QGraphicsDropShadowEffect* newChatShadow= + new QGraphicsDropShadowEffect (newChatButton_); + newChatShadow->setBlurRadius (DpiUtils::scaled (8)); + newChatShadow->setColor (QColor (0, 0, 0, 40)); + newChatShadow->setOffset (0, DpiUtils::scaled (2)); + newChatButton_->setGraphicsEffect (newChatShadow); + connect (newChatButton_, &QPushButton::clicked, this, [this] () { string model= as_string (call ("chat-tab-session-select-model", string (""))); From 1a4962fe15e86f71579801323dadf676b6182e83 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:02:24 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index ba5a853d69..2ef7eef3eb 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -335,17 +335,17 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { int newChatIconSize= DpiUtils::scaled (18); newChatButton_->setIconSize (QSize (newChatIconSize, newChatIconSize)); newChatButton_->setStyleSheet ( - QString ("QPushButton { text-align: left; border: none; " + QString ("QPushButton { text-align: center; border: none; " "border-radius: %1px; padding: %2px %3px; " "background-color: #ffffff; color: #333333; }" - "QPushButton:hover { background-color: #f0f0f0; }") - .arg (DpiUtils::scaled (6)) + "QPushButton:hover { background-color: #e0e0e0; }") + .arg (DpiUtils::scaled (8)) .arg (DpiUtils::scaled (kNavButtonPadY)) .arg (DpiUtils::scaled (kNavButtonPadX))); QGraphicsDropShadowEffect* newChatShadow= new QGraphicsDropShadowEffect (newChatButton_); - newChatShadow->setBlurRadius (DpiUtils::scaled (8)); + newChatShadow->setBlurRadius (DpiUtils::scaled (4)); newChatShadow->setColor (QColor (0, 0, 0, 40)); newChatShadow->setOffset (0, DpiUtils::scaled (2)); newChatButton_->setGraphicsEffect (newChatShadow); From 2810efc04c3cc0180dc957597f44130e61d4e211 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:09:15 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/plugins/lang/dic/en_US/zh_CN.scm | 2 +- src/Plugins/Qt/qt_chat_tab_widget.cpp | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm index b180b81672..53aee08dc4 100644 --- a/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm +++ b/TeXmacs/plugins/lang/dic/en_US/zh_CN.scm @@ -1550,7 +1550,7 @@ ("new account" "新建账号") ("New Blank Document" "新建空白文档") ("new buffer" "") -("new chat" "开启新对话") +("New chat" "开启新对话") ("new column" "添加一行") ("new document" "新建文档") ("new double page before" "新起双页(在前面)") diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index 2ef7eef3eb..2b409c02af 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -174,6 +174,12 @@ constexpr int kToggleIconSize= 20; constexpr int kFloatingBtnMarginX= 12; /// 浮球展开按钮垂直边距(像素)。 constexpr int kFloatingBtnMarginY= 130; +/// New chat 按钮图标尺寸(像素)。 +constexpr int kNewChatIconSize= 18; +/// New chat 按钮固定高度(像素)。 +constexpr int kNewChatButtonHeight= 36; +/// New chat 按钮固定宽度(像素)。 +constexpr int kNewChatButtonWidth= 140; } // namespace @@ -332,22 +338,25 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { newChatButton_->setCursor (Qt::PointingHandCursor); DpiUtils::applyScaledFont (newChatButton_, kNavButtonFontPx); newChatButton_->setIcon (QIcon (":llm-chat/addchat.svg")); - int newChatIconSize= DpiUtils::scaled (18); - newChatButton_->setIconSize (QSize (newChatIconSize, newChatIconSize)); + newChatButton_->setIconSize (QSize (DpiUtils::scaled (kNewChatIconSize), + DpiUtils::scaled (kNewChatIconSize))); + newChatButton_->setFixedSize ( + QSize (DpiUtils::scaled (kNewChatButtonWidth), + DpiUtils::scaled (kNewChatButtonHeight))); newChatButton_->setStyleSheet ( QString ("QPushButton { text-align: center; border: none; " "border-radius: %1px; padding: %2px %3px; " "background-color: #ffffff; color: #333333; }" "QPushButton:hover { background-color: #e0e0e0; }") - .arg (DpiUtils::scaled (8)) + .arg (DpiUtils::scaled (kNewChatButtonHeight / 2)) .arg (DpiUtils::scaled (kNavButtonPadY)) .arg (DpiUtils::scaled (kNavButtonPadX))); QGraphicsDropShadowEffect* newChatShadow= new QGraphicsDropShadowEffect (newChatButton_); - newChatShadow->setBlurRadius (DpiUtils::scaled (4)); - newChatShadow->setColor (QColor (0, 0, 0, 40)); - newChatShadow->setOffset (0, DpiUtils::scaled (2)); + newChatShadow->setBlurRadius (DpiUtils::scaled (3)); + newChatShadow->setColor (QColor (0, 0, 0, 25)); + newChatShadow->setOffset (0, DpiUtils::scaled (1)); newChatButton_->setGraphicsEffect (newChatShadow); connect (newChatButton_, &QPushButton::clicked, this, [this] () { From dc3d61e29ea372d16b7e479b57b0c15f5e1ab302 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:16:19 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 29 +++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index 2b409c02af..328bebdcee 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -332,7 +332,7 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { normalLayout->addWidget (headerWidget); // New chat 按钮 - newChatButton_= new QPushButton ("New chat", normalContent); + newChatButton_= new QPushButton (qt_translate ("New chat"), normalContent); newChatButton_->setObjectName ("chat-tab-new-btn"); newChatButton_->setFocusPolicy (Qt::NoFocus); newChatButton_->setCursor (Qt::PointingHandCursor); @@ -346,8 +346,7 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { newChatButton_->setStyleSheet ( QString ("QPushButton { text-align: center; border: none; " "border-radius: %1px; padding: %2px %3px; " - "background-color: #ffffff; color: #333333; }" - "QPushButton:hover { background-color: #e0e0e0; }") + "background-color: #ffffff; color: #333333; }") .arg (DpiUtils::scaled (kNewChatButtonHeight / 2)) .arg (DpiUtils::scaled (kNavButtonPadY)) .arg (DpiUtils::scaled (kNavButtonPadX))); @@ -359,12 +358,14 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { newChatShadow->setOffset (0, DpiUtils::scaled (1)); newChatButton_->setGraphicsEffect (newChatShadow); + newChatButton_->setAttribute (Qt::WA_Hover); + newChatButton_->installEventFilter (this); connect (newChatButton_, &QPushButton::clicked, this, [this] () { string model= as_string (call ("chat-tab-session-select-model", string (""))); create_new_conversation_with_model (model); }); - normalLayout->addWidget (newChatButton_); + normalLayout->addWidget (newChatButton_, 0, Qt::AlignHCenter); conversationCountLabel_= new QLabel ("Conversations (0)", normalContent); conversationCountLabel_->setObjectName ("chat-tab-conversation-count"); @@ -1502,6 +1503,26 @@ QTChatTabWidget::eventFilter (QObject* watched, QEvent* event) { } } } + if (watched == newChatButton_) { + if (event->type () == QEvent::HoverEnter) { + if (QGraphicsDropShadowEffect* effect= + qobject_cast ( + newChatButton_->graphicsEffect ())) { + effect->setBlurRadius (DpiUtils::scaled (6)); + effect->setColor (QColor (0, 0, 0, 50)); + effect->setOffset (0, DpiUtils::scaled (2)); + } + } + else if (event->type () == QEvent::HoverLeave) { + if (QGraphicsDropShadowEffect* effect= + qobject_cast ( + newChatButton_->graphicsEffect ())) { + effect->setBlurRadius (DpiUtils::scaled (3)); + effect->setColor (QColor (0, 0, 0, 25)); + effect->setOffset (0, DpiUtils::scaled (1)); + } + } + } return QWidget::eventFilter (watched, event); } From 63eb9ebf959962c5c2fe85d967cbef730445ecd2 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:25:31 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 75 +++++++++++++++++++-------- src/Plugins/Qt/qt_chat_tab_widget.hpp | 1 + 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index 328bebdcee..02deb48427 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -174,6 +174,8 @@ constexpr int kToggleIconSize= 20; constexpr int kFloatingBtnMarginX= 12; /// 浮球展开按钮垂直边距(像素)。 constexpr int kFloatingBtnMarginY= 130; +/// 浮球新建聊天按钮垂直边距(像素)。 +constexpr int kFloatingNewChatBtnMarginY= 182; /// New chat 按钮图标尺寸(像素)。 constexpr int kNewChatIconSize= 18; /// New chat 按钮固定高度(像素)。 @@ -181,6 +183,30 @@ constexpr int kNewChatButtonHeight= 36; /// New chat 按钮固定宽度(像素)。 constexpr int kNewChatButtonWidth= 140; +/** + * @brief 创建统一风格的浮球按钮(圆形、无边框、灰色背景)。 + */ +QPushButton* +setup_floating_button (QWidget* parent, const QString& objectName, + const QString& iconPath) { + QPushButton* btn= new QPushButton (parent); + btn->setObjectName (objectName); + btn->setFocusPolicy (Qt::NoFocus); + btn->setCursor (Qt::PointingHandCursor); + btn->setIcon (QIcon (iconPath)); + btn->setIconSize (QSize (DpiUtils::scaled (kToggleIconSize), + DpiUtils::scaled (kToggleIconSize))); + btn->setFixedSize (DpiUtils::scaled (kToggleBtnSize), + DpiUtils::scaled (kToggleBtnSize)); + btn->setStyleSheet ( + QString ("QPushButton { border: none; border-radius: %1px; " + "background-color: #e8e8e8; } " + "QPushButton:hover { background-color: #d0d0d0; }") + .arg (DpiUtils::scaled (kToggleBtnSize / 2))); + btn->hide (); + return btn; +} + } // namespace /** @@ -227,13 +253,13 @@ QTChatTabWidget::QTChatTabWidget (QWidget* parent) archiveListWidget_ (nullptr), archiveListLayout_ (nullptr), archiveCollapsed_ (true), newChatButton_ (nullptr), collapseButton_ (nullptr), floatingExpandBtn_ (nullptr), - sidebarNormalContent_ (nullptr), conversationStack_ (nullptr), - activeConversation_ (nullptr), sidebarCollapsed_ (false), - sidebarExpandedWidth_ (0), chatMenuToolBar_ (nullptr), - chatModeToolBar_ (nullptr), chatFocusToolBar_ (nullptr), - multiSelectMode_ (false), archiveSelectMode_ (false), - multiSelectBar_ (nullptr), batchArchiveBtn_ (nullptr), - searchEdit_ (nullptr) { + floatingNewChatBtn_ (nullptr), sidebarNormalContent_ (nullptr), + conversationStack_ (nullptr), activeConversation_ (nullptr), + sidebarCollapsed_ (false), sidebarExpandedWidth_ (0), + chatMenuToolBar_ (nullptr), chatModeToolBar_ (nullptr), + chatFocusToolBar_ (nullptr), multiSelectMode_ (false), + archiveSelectMode_ (false), multiSelectBar_ (nullptr), + batchArchiveBtn_ (nullptr), searchEdit_ (nullptr) { setFocusPolicy (Qt::StrongFocus); QHBoxLayout* mainLayout= new QHBoxLayout (this); @@ -575,26 +601,25 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { mainLayout->addWidget (content, 1); // 浮球展开按钮(侧边栏收起时显示在内容区左上角) - QPushButton* floatingBtn= new QPushButton (this); - floatingBtn->setObjectName ("chat-tab-floating-expand-btn"); - floatingBtn->setFocusPolicy (Qt::NoFocus); - floatingBtn->setCursor (Qt::PointingHandCursor); - floatingBtn->setIcon (QIcon (":llm-chat/sidebar.svg")); - floatingBtn->setIconSize (QSize (DpiUtils::scaled (kToggleIconSize), - DpiUtils::scaled (kToggleIconSize))); - floatingBtn->setFixedSize (DpiUtils::scaled (kToggleBtnSize), - DpiUtils::scaled (kToggleBtnSize)); - floatingBtn->setStyleSheet ( - QString ("QPushButton { border: none; border-radius: %1px; " - "background-color: #e8e8e8; } " - "QPushButton:hover { background-color: #d0d0d0; }") - .arg (DpiUtils::scaled (kToggleBtnSize / 2))); + QPushButton* floatingBtn= setup_floating_button ( + this, "chat-tab-floating-expand-btn", ":llm-chat/sidebar.svg"); connect (floatingBtn, &QPushButton::clicked, this, [this] () { toggle_sidebar (); }); floatingBtn->move (DpiUtils::scaled (kFloatingBtnMarginX), DpiUtils::scaled (kFloatingBtnMarginY)); - floatingBtn->hide (); floatingExpandBtn_= floatingBtn; + + // 浮球新建聊天按钮(侧边栏收起时显示在内容区左上角) + QPushButton* floatingNewBtn= setup_floating_button ( + this, "chat-tab-floating-new-btn", ":llm-chat/addchat.svg"); + connect (floatingNewBtn, &QPushButton::clicked, this, [this] () { + string model= + as_string (call ("chat-tab-session-select-model", string (""))); + create_new_conversation_with_model (model); + }); + floatingNewBtn->move (DpiUtils::scaled (kFloatingBtnMarginX), + DpiUtils::scaled (kFloatingNewChatBtnMarginY)); + floatingNewChatBtn_= floatingNewBtn; } /** @@ -1229,6 +1254,7 @@ QTChatTabWidget::toggle_sidebar () { if (sidebarCollapsed_) { if (floatingExpandBtn_) floatingExpandBtn_->hide (); + if (floatingNewChatBtn_) floatingNewChatBtn_->hide (); sidebarWidget_->show (); sidebarCollapsed_= false; } @@ -1239,6 +1265,11 @@ QTChatTabWidget::toggle_sidebar () { DpiUtils::scaled (kFloatingBtnMarginY)); floatingExpandBtn_->show (); } + if (floatingNewChatBtn_) { + floatingNewChatBtn_->move (DpiUtils::scaled (kFloatingBtnMarginX), + DpiUtils::scaled (kFloatingNewChatBtnMarginY)); + floatingNewChatBtn_->show (); + } sidebarCollapsed_= true; } } diff --git a/src/Plugins/Qt/qt_chat_tab_widget.hpp b/src/Plugins/Qt/qt_chat_tab_widget.hpp index e94902e0f6..d104fad06d 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.hpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.hpp @@ -376,6 +376,7 @@ class QTChatTabWidget : public QWidget { bool archiveCollapsed_; ///< 归档区当前是否折叠。 QPushButton* collapseButton_; ///< 侧边栏内的收缩按钮。 QPushButton* floatingExpandBtn_; ///< 内容区左上角的浮球展开按钮。 + QPushButton* floatingNewChatBtn_; ///< 内容区左上角的新建聊天浮球按钮。 QPushButton* newChatButton_; ///< 新建会话按钮。 QWidget* sidebarNormalContent_; ///< 侧边栏展开时的内容容器。 QStackedWidget* conversationStack_; ///< 会话页面的堆叠控件。 From 94e579fe2f93f43b1d073d0fc9616df7e8a7efc7 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:28:56 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index 02deb48427..bcd97bef3f 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -174,8 +174,8 @@ constexpr int kToggleIconSize= 20; constexpr int kFloatingBtnMarginX= 12; /// 浮球展开按钮垂直边距(像素)。 constexpr int kFloatingBtnMarginY= 130; -/// 浮球新建聊天按钮垂直边距(像素)。 -constexpr int kFloatingNewChatBtnMarginY= 182; +/// 浮球新建聊天按钮水平边距(像素)。 +constexpr int kFloatingNewChatBtnMarginX= 60; /// New chat 按钮图标尺寸(像素)。 constexpr int kNewChatIconSize= 18; /// New chat 按钮固定高度(像素)。 @@ -617,8 +617,8 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { as_string (call ("chat-tab-session-select-model", string (""))); create_new_conversation_with_model (model); }); - floatingNewBtn->move (DpiUtils::scaled (kFloatingBtnMarginX), - DpiUtils::scaled (kFloatingNewChatBtnMarginY)); + floatingNewBtn->move (DpiUtils::scaled (kFloatingNewChatBtnMarginX), + DpiUtils::scaled (kFloatingBtnMarginY)); floatingNewChatBtn_= floatingNewBtn; } @@ -1266,8 +1266,8 @@ QTChatTabWidget::toggle_sidebar () { floatingExpandBtn_->show (); } if (floatingNewChatBtn_) { - floatingNewChatBtn_->move (DpiUtils::scaled (kFloatingBtnMarginX), - DpiUtils::scaled (kFloatingNewChatBtnMarginY)); + floatingNewChatBtn_->move (DpiUtils::scaled (kFloatingNewChatBtnMarginX), + DpiUtils::scaled (kFloatingBtnMarginY)); floatingNewChatBtn_->show (); } sidebarCollapsed_= true; From 8dd8e316a778035eabcdfb02442b0d08c6f17d8f Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:38:04 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 63 +++++++++++++++------------ src/Plugins/Qt/qt_chat_tab_widget.hpp | 1 + 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index bcd97bef3f..10e30348d7 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -253,13 +253,14 @@ QTChatTabWidget::QTChatTabWidget (QWidget* parent) archiveListWidget_ (nullptr), archiveListLayout_ (nullptr), archiveCollapsed_ (true), newChatButton_ (nullptr), collapseButton_ (nullptr), floatingExpandBtn_ (nullptr), - floatingNewChatBtn_ (nullptr), sidebarNormalContent_ (nullptr), - conversationStack_ (nullptr), activeConversation_ (nullptr), - sidebarCollapsed_ (false), sidebarExpandedWidth_ (0), - chatMenuToolBar_ (nullptr), chatModeToolBar_ (nullptr), - chatFocusToolBar_ (nullptr), multiSelectMode_ (false), - archiveSelectMode_ (false), multiSelectBar_ (nullptr), - batchArchiveBtn_ (nullptr), searchEdit_ (nullptr) { + floatingNewChatBtn_ (nullptr), floatingBtnContainer_ (nullptr), + sidebarNormalContent_ (nullptr), conversationStack_ (nullptr), + activeConversation_ (nullptr), sidebarCollapsed_ (false), + sidebarExpandedWidth_ (0), chatMenuToolBar_ (nullptr), + chatModeToolBar_ (nullptr), chatFocusToolBar_ (nullptr), + multiSelectMode_ (false), archiveSelectMode_ (false), + multiSelectBar_ (nullptr), batchArchiveBtn_ (nullptr), + searchEdit_ (nullptr) { setFocusPolicy (Qt::StrongFocus); QHBoxLayout* mainLayout= new QHBoxLayout (this); @@ -600,26 +601,40 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { mainLayout->addWidget (content, 1); - // 浮球展开按钮(侧边栏收起时显示在内容区左上角) - QPushButton* floatingBtn= setup_floating_button ( - this, "chat-tab-floating-expand-btn", ":llm-chat/sidebar.svg"); + // 浮球按钮容器(侧边栏收起时显示在内容区左上角) + QWidget* floatingContainer= new QWidget (this); + floatingContainer->setObjectName ("chat-tab-floating-container"); + QHBoxLayout* floatingLayout= new QHBoxLayout (floatingContainer); + floatingLayout->setContentsMargins (0, 0, 0, 0); + floatingLayout->setSpacing (0); + floatingContainer->setStyleSheet ( + QString ("QWidget#chat-tab-floating-container { " + "background-color: #e8e8e8; border-radius: %1px; }") + .arg (DpiUtils::scaled (kToggleBtnSize / 2))); + + QPushButton* floatingBtn= + setup_floating_button (floatingContainer, "chat-tab-floating-expand-btn", + ":llm-chat/sidebar.svg"); connect (floatingBtn, &QPushButton::clicked, this, [this] () { toggle_sidebar (); }); - floatingBtn->move (DpiUtils::scaled (kFloatingBtnMarginX), - DpiUtils::scaled (kFloatingBtnMarginY)); + floatingLayout->addWidget (floatingBtn); floatingExpandBtn_= floatingBtn; - // 浮球新建聊天按钮(侧边栏收起时显示在内容区左上角) QPushButton* floatingNewBtn= setup_floating_button ( - this, "chat-tab-floating-new-btn", ":llm-chat/addchat.svg"); + floatingContainer, "chat-tab-floating-new-btn", ":llm-chat/addchat.svg"); connect (floatingNewBtn, &QPushButton::clicked, this, [this] () { string model= as_string (call ("chat-tab-session-select-model", string (""))); create_new_conversation_with_model (model); }); - floatingNewBtn->move (DpiUtils::scaled (kFloatingNewChatBtnMarginX), - DpiUtils::scaled (kFloatingBtnMarginY)); + floatingLayout->addWidget (floatingNewBtn); floatingNewChatBtn_= floatingNewBtn; + + floatingContainer->adjustSize (); + floatingContainer->move (DpiUtils::scaled (kFloatingBtnMarginX), + DpiUtils::scaled (kFloatingBtnMarginY)); + floatingContainer->hide (); + floatingBtnContainer_= floatingContainer; } /** @@ -1253,22 +1268,16 @@ QTChatTabWidget::toggle_sidebar () { if (!sidebarWidget_) return; if (sidebarCollapsed_) { - if (floatingExpandBtn_) floatingExpandBtn_->hide (); - if (floatingNewChatBtn_) floatingNewChatBtn_->hide (); + if (floatingBtnContainer_) floatingBtnContainer_->hide (); sidebarWidget_->show (); sidebarCollapsed_= false; } else { sidebarWidget_->hide (); - if (floatingExpandBtn_) { - floatingExpandBtn_->move (DpiUtils::scaled (kFloatingBtnMarginX), - DpiUtils::scaled (kFloatingBtnMarginY)); - floatingExpandBtn_->show (); - } - if (floatingNewChatBtn_) { - floatingNewChatBtn_->move (DpiUtils::scaled (kFloatingNewChatBtnMarginX), - DpiUtils::scaled (kFloatingBtnMarginY)); - floatingNewChatBtn_->show (); + if (floatingBtnContainer_) { + floatingBtnContainer_->move (DpiUtils::scaled (kFloatingBtnMarginX), + DpiUtils::scaled (kFloatingBtnMarginY)); + floatingBtnContainer_->show (); } sidebarCollapsed_= true; } diff --git a/src/Plugins/Qt/qt_chat_tab_widget.hpp b/src/Plugins/Qt/qt_chat_tab_widget.hpp index d104fad06d..2558073e14 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.hpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.hpp @@ -377,6 +377,7 @@ class QTChatTabWidget : public QWidget { QPushButton* collapseButton_; ///< 侧边栏内的收缩按钮。 QPushButton* floatingExpandBtn_; ///< 内容区左上角的浮球展开按钮。 QPushButton* floatingNewChatBtn_; ///< 内容区左上角的新建聊天浮球按钮。 + QWidget* floatingBtnContainer_; ///< 浮球按钮的胶囊形容器。 QPushButton* newChatButton_; ///< 新建会话按钮。 QWidget* sidebarNormalContent_; ///< 侧边栏展开时的内容容器。 QStackedWidget* conversationStack_; ///< 会话页面的堆叠控件。 From aa4817011fea59f81d64aaeff9d0ae462479ad26 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:40:23 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index 10e30348d7..bd179eb0a2 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -200,10 +200,9 @@ setup_floating_button (QWidget* parent, const QString& objectName, DpiUtils::scaled (kToggleBtnSize)); btn->setStyleSheet ( QString ("QPushButton { border: none; border-radius: %1px; " - "background-color: #e8e8e8; } " + "background-color: transparent; } " "QPushButton:hover { background-color: #d0d0d0; }") .arg (DpiUtils::scaled (kToggleBtnSize / 2))); - btn->hide (); return btn; } From 61257a3137ea990875457dcfb36dc7015f813aea Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:42:02 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index bd179eb0a2..f00dfb4a02 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -604,7 +604,9 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { QWidget* floatingContainer= new QWidget (this); floatingContainer->setObjectName ("chat-tab-floating-container"); QHBoxLayout* floatingLayout= new QHBoxLayout (floatingContainer); - floatingLayout->setContentsMargins (0, 0, 0, 0); + floatingLayout->setContentsMargins ( + DpiUtils::scaled (4), DpiUtils::scaled (4), DpiUtils::scaled (4), + DpiUtils::scaled (4)); floatingLayout->setSpacing (0); floatingContainer->setStyleSheet ( QString ("QWidget#chat-tab-floating-container { " From d7400f91f52ee8712a112ecd7b82c40ca968731d Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:45:36 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index f00dfb4a02..c116696244 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -176,6 +176,8 @@ constexpr int kFloatingBtnMarginX= 12; constexpr int kFloatingBtnMarginY= 130; /// 浮球新建聊天按钮水平边距(像素)。 constexpr int kFloatingNewChatBtnMarginX= 60; +/// 浮球容器内边距(像素)。 +constexpr int kFloatingContainerPad= 4; /// New chat 按钮图标尺寸(像素)。 constexpr int kNewChatIconSize= 18; /// New chat 按钮固定高度(像素)。 @@ -605,13 +607,16 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { floatingContainer->setObjectName ("chat-tab-floating-container"); QHBoxLayout* floatingLayout= new QHBoxLayout (floatingContainer); floatingLayout->setContentsMargins ( - DpiUtils::scaled (4), DpiUtils::scaled (4), DpiUtils::scaled (4), - DpiUtils::scaled (4)); + DpiUtils::scaled (kFloatingContainerPad), + DpiUtils::scaled (kFloatingContainerPad), + DpiUtils::scaled (kFloatingContainerPad), + DpiUtils::scaled (kFloatingContainerPad)); floatingLayout->setSpacing (0); floatingContainer->setStyleSheet ( QString ("QWidget#chat-tab-floating-container { " "background-color: #e8e8e8; border-radius: %1px; }") - .arg (DpiUtils::scaled (kToggleBtnSize / 2))); + .arg (DpiUtils::scaled (kToggleBtnSize / 2 + + kFloatingContainerPad))); QPushButton* floatingBtn= setup_floating_button (floatingContainer, "chat-tab-floating-expand-btn", From cf462ac4216e174dd97a1e05e02bc729d5e1f89f Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:52:32 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E9=AD=94=E6=B3=95=E6=95=B0=E5=AD=97?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Plugins/Qt/qt_chat_tab_widget.cpp | 124 +++++++++++++++----------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index c116696244..fc339a431e 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -138,14 +138,6 @@ constexpr int kInputLineHeight= 22; constexpr int kInputDefaultLines= 3; /// 输入编辑器最大行数。 constexpr int kInputMaxLines= 10; -/// 发送按钮垂直内边距。 -constexpr int kSendButtonPadY= 6; -/// 发送按钮水平内边距。 -constexpr int kSendButtonPadX= 16; -/// 发送按钮字体大小(像素)。 -constexpr int kSendButtonFontPx= 13; -/// 内容区水平边距。 -constexpr int kContentMarginX= 24; /// 内容区垂直边距。 constexpr int kContentMarginY= 24; /// 内容区元素间距。 @@ -154,12 +146,8 @@ constexpr int kContentSpacing= 16; constexpr int kWelcomeTopOffsetY= 240; /// 会话模式下顶部占位高度(像素)。 constexpr int kConversationTopOffsetY= 24; -/// 顶部面板最大宽度(像素)。 -constexpr int kTopPanelMaxWidth= 680; /// 输入/消息框圆角半径。 constexpr int kInputFrameRadius= 8; -/// 输入/消息框边框宽度(像素)。 -constexpr int kInputFrameBorder= 1; /// 输入/消息框内边距。 constexpr int kInputFramePad= 8; /// 消息展示区最小高度(像素)。 @@ -174,8 +162,6 @@ constexpr int kToggleIconSize= 20; constexpr int kFloatingBtnMarginX= 12; /// 浮球展开按钮垂直边距(像素)。 constexpr int kFloatingBtnMarginY= 130; -/// 浮球新建聊天按钮水平边距(像素)。 -constexpr int kFloatingNewChatBtnMarginX= 60; /// 浮球容器内边距(像素)。 constexpr int kFloatingContainerPad= 4; /// New chat 按钮图标尺寸(像素)。 @@ -184,6 +170,38 @@ constexpr int kNewChatIconSize= 18; constexpr int kNewChatButtonHeight= 36; /// New chat 按钮固定宽度(像素)。 constexpr int kNewChatButtonWidth= 140; +/// New chat 按钮阴影模糊半径(像素)。 +constexpr int kNewChatShadowBlur= 3; +/// New chat 按钮阴影不透明度(0-255)。 +constexpr int kNewChatShadowAlpha= 25; +/// New chat 按钮阴影垂直偏移(像素)。 +constexpr int kNewChatShadowOffsetY= 1; +/// New chat 按钮悬停阴影模糊半径(像素)。 +constexpr int kNewChatHoverShadowBlur= 6; +/// New chat 按钮悬停阴影不透明度(0-255)。 +constexpr int kNewChatHoverShadowAlpha= 50; +/// New chat 按钮悬停阴影垂直偏移(像素)。 +constexpr int kNewChatHoverShadowOffsetY= 2; +/// 多选操作栏元素间距(像素)。 +constexpr int kMultiSelectSpacing= 4; +/// 会话项布局间距(像素)。 +constexpr int kSessionItemSpacing= 4; +/// 模型标签最小高度(像素)。 +constexpr int kModelLabelMinHeight= 20; +/// 模型标签圆角半径(像素)。 +constexpr int kModelLabelRadius= 4; +/// 发送按钮图标尺寸(像素)。 +constexpr int kSendIconSize= 24; +/// 发送按钮尺寸(像素)。 +constexpr int kSendButtonSize= 36; +/// 发送按钮圆角半径(像素)。 +constexpr int kSendButtonRadius= 18; +/// 会话按钮圆角半径(像素)。 +constexpr int kConversationBtnRadius= 6; +/// 输入框高度检查间隔(毫秒)。 +constexpr int kInputHeightCheckIntervalMs= 100; +/// 菜单栏固定高度(像素)。 +constexpr int kMenuBarHeight= 108; /** * @brief 创建统一风格的浮球按钮(圆形、无边框、灰色背景)。 @@ -381,9 +399,9 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { QGraphicsDropShadowEffect* newChatShadow= new QGraphicsDropShadowEffect (newChatButton_); - newChatShadow->setBlurRadius (DpiUtils::scaled (3)); - newChatShadow->setColor (QColor (0, 0, 0, 25)); - newChatShadow->setOffset (0, DpiUtils::scaled (1)); + newChatShadow->setBlurRadius (DpiUtils::scaled (kNewChatShadowBlur)); + newChatShadow->setColor (QColor (0, 0, 0, kNewChatShadowAlpha)); + newChatShadow->setOffset (0, DpiUtils::scaled (kNewChatShadowOffsetY)); newChatButton_->setGraphicsEffect (newChatShadow); newChatButton_->setAttribute (Qt::WA_Hover); @@ -424,7 +442,7 @@ QTChatTabWidget::setup_left_sidebar (QVBoxLayout* sidebarLayout) { multiSelectBar_->setObjectName ("chat-tab-multi-select-bar"); QHBoxLayout* multiSelectLayout= new QHBoxLayout (multiSelectBar_); multiSelectLayout->setContentsMargins (0, 0, 0, 0); - multiSelectLayout->setSpacing (DpiUtils::scaled (4)); + multiSelectLayout->setSpacing (DpiUtils::scaled (kMultiSelectSpacing)); QPushButton* cancelSelectBtn= new QPushButton ("取消", multiSelectBar_); cancelSelectBtn->setObjectName ("chat-tab-cancel-select-btn"); @@ -606,17 +624,15 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { QWidget* floatingContainer= new QWidget (this); floatingContainer->setObjectName ("chat-tab-floating-container"); QHBoxLayout* floatingLayout= new QHBoxLayout (floatingContainer); - floatingLayout->setContentsMargins ( - DpiUtils::scaled (kFloatingContainerPad), - DpiUtils::scaled (kFloatingContainerPad), - DpiUtils::scaled (kFloatingContainerPad), - DpiUtils::scaled (kFloatingContainerPad)); + floatingLayout->setContentsMargins (DpiUtils::scaled (kFloatingContainerPad), + DpiUtils::scaled (kFloatingContainerPad), + DpiUtils::scaled (kFloatingContainerPad), + DpiUtils::scaled (kFloatingContainerPad)); floatingLayout->setSpacing (0); floatingContainer->setStyleSheet ( QString ("QWidget#chat-tab-floating-container { " "background-color: #e8e8e8; border-radius: %1px; }") - .arg (DpiUtils::scaled (kToggleBtnSize / 2 + - kFloatingContainerPad))); + .arg (DpiUtils::scaled (kToggleBtnSize / 2 + kFloatingContainerPad))); QPushButton* floatingBtn= setup_floating_button (floatingContainer, "chat-tab-floating-expand-btn", @@ -689,9 +705,11 @@ QTChatTabWidget::create_conversation (const QString& title) { panel->modelLabel->setAlignment (Qt::AlignCenter); DpiUtils::applyScaledFont (panel->modelLabel, kNavTitleFontPx); panel->modelLabel->setStyleSheet ( - "color: #888888; padding: 2px 8px; background-color: #f0f0f0; " - "border-radius: 4px;"); - panel->modelLabel->setMinimumHeight (DpiUtils::scaled (20)); + QString ("color: #888888; padding: 2px %1px; background-color: #f0f0f0; " + "border-radius: %2px;") + .arg (DpiUtils::scaled (kNavButtonPadX)) + .arg (DpiUtils::scaled (kModelLabelRadius))); + panel->modelLabel->setMinimumHeight (DpiUtils::scaled (kModelLabelMinHeight)); topLayout->addWidget (panel->modelLabel, 0, Qt::AlignHCenter); panel->messageWidget= texmacs_input_widget ( @@ -776,16 +794,16 @@ QTChatTabWidget::create_conversation (const QString& title) { panel->sendButton->setFocusPolicy (Qt::NoFocus); panel->sendButton->setCursor (Qt::PointingHandCursor); panel->sendButton->setIcon (QIcon (":llm-chat/send.svg")); - int sendIconSize= DpiUtils::scaled (24); + int sendIconSize= DpiUtils::scaled (kSendIconSize); panel->sendButton->setIconSize (QSize (sendIconSize, sendIconSize)); - panel->sendButton->setFixedSize (DpiUtils::scaled (36), - DpiUtils::scaled (36)); + panel->sendButton->setFixedSize (DpiUtils::scaled (kSendButtonSize), + DpiUtils::scaled (kSendButtonSize)); panel->sendButton->setStyleSheet ( QString ("QPushButton { border: none; border-radius: %1px; " " background-color: transparent; }" "QPushButton:hover { background-color: #f0f0f0; }" "QPushButton:pressed { background-color: #e0e0e0; }") - .arg (DpiUtils::scaled (18))); + .arg (DpiUtils::scaled (kSendButtonRadius))); connect (panel->sendButton, &QPushButton::clicked, this, [this, panel] () { handle_send (panel); }); btnLayout->addWidget (panel->sendButton); @@ -794,7 +812,7 @@ QTChatTabWidget::create_conversation (const QString& title) { inputAreaLayout->addWidget (inputFrame, 0); QTimer* inputHeightTimer= new QTimer (inputFrame); - inputHeightTimer->setInterval (100); + inputHeightTimer->setInterval (kInputHeightCheckIntervalMs); connect (inputHeightTimer, &QTimer::timeout, this, [this, panel] () { adjust_input_height (panel); }); inputHeightTimer->start (); @@ -812,7 +830,7 @@ QTChatTabWidget::create_conversation (const QString& title) { panel->itemWidget->setObjectName ("chat-tab-session-item"); QHBoxLayout* itemLayout= new QHBoxLayout (panel->itemWidget); itemLayout->setContentsMargins (0, 0, 0, 0); - itemLayout->setSpacing (DpiUtils::scaled (4)); + itemLayout->setSpacing (DpiUtils::scaled (kSessionItemSpacing)); panel->selectCheckBox= new QCheckBox (panel->itemWidget); panel->selectCheckBox->setObjectName ("chat-tab-select-checkbox"); @@ -839,7 +857,7 @@ QTChatTabWidget::create_conversation (const QString& title) { "#ffffff; } " "QPushButton:checked { background-color: #e8eefc; " "border-color: #9bb3ff; font-weight: 600; }") - .arg (DpiUtils::scaled (6)) + .arg (DpiUtils::scaled (kConversationBtnRadius)) .arg (DpiUtils::scaled (kNavButtonPadY)) .arg (DpiUtils::scaled (kNavButtonPadX))); connect (panel->sidebarButton, &QPushButton::clicked, this, @@ -1554,18 +1572,18 @@ QTChatTabWidget::eventFilter (QObject* watched, QEvent* event) { if (QGraphicsDropShadowEffect* effect= qobject_cast ( newChatButton_->graphicsEffect ())) { - effect->setBlurRadius (DpiUtils::scaled (6)); - effect->setColor (QColor (0, 0, 0, 50)); - effect->setOffset (0, DpiUtils::scaled (2)); + effect->setBlurRadius (DpiUtils::scaled (kNewChatHoverShadowBlur)); + effect->setColor (QColor (0, 0, 0, kNewChatHoverShadowAlpha)); + effect->setOffset (0, DpiUtils::scaled (kNewChatHoverShadowOffsetY)); } } else if (event->type () == QEvent::HoverLeave) { if (QGraphicsDropShadowEffect* effect= qobject_cast ( newChatButton_->graphicsEffect ())) { - effect->setBlurRadius (DpiUtils::scaled (3)); - effect->setColor (QColor (0, 0, 0, 25)); - effect->setOffset (0, DpiUtils::scaled (1)); + effect->setBlurRadius (DpiUtils::scaled (kNewChatShadowBlur)); + effect->setColor (QColor (0, 0, 0, kNewChatShadowAlpha)); + effect->setOffset (0, DpiUtils::scaled (kNewChatShadowOffsetY)); } } } @@ -1580,7 +1598,7 @@ QTChatTabWidget::install_chat_menu_bar (widget menuWidget) { QMenuBar* dest = new QMenuBar (); double scale= DpiUtils::scaleFactor (); - int h = DpiUtils::scaled (108); + int h = DpiUtils::scaled (kMenuBarHeight); dest->setFixedHeight (h); if (tm_style_sheet == "") dest->setStyle (qtmstyle ()); dest->setNativeMenuBar (false); @@ -1886,9 +1904,11 @@ QTChatTabWidget::restore_conversation (const string& sessionId, panel->modelLabel->setAlignment (Qt::AlignCenter); DpiUtils::applyScaledFont (panel->modelLabel, kNavTitleFontPx); panel->modelLabel->setStyleSheet ( - "color: #888888; padding: 2px 8px; background-color: #f0f0f0; " - "border-radius: 4px;"); - panel->modelLabel->setMinimumHeight (DpiUtils::scaled (20)); + QString ("color: #888888; padding: 2px %1px; background-color: #f0f0f0; " + "border-radius: %2px;") + .arg (DpiUtils::scaled (kNavButtonPadX)) + .arg (DpiUtils::scaled (kModelLabelRadius))); + panel->modelLabel->setMinimumHeight (DpiUtils::scaled (kModelLabelMinHeight)); topLayout->addWidget (panel->modelLabel, 0, Qt::AlignHCenter); // 恢复会话时,buffer 中已有 Scheme 加载的消息内容,需使用 buffer 内容而非空 @@ -1977,16 +1997,16 @@ QTChatTabWidget::restore_conversation (const string& sessionId, panel->sendButton->setFocusPolicy (Qt::NoFocus); panel->sendButton->setCursor (Qt::PointingHandCursor); panel->sendButton->setIcon (QIcon (":llm-chat/send.svg")); - int sendIconSize= DpiUtils::scaled (24); + int sendIconSize= DpiUtils::scaled (kSendIconSize); panel->sendButton->setIconSize (QSize (sendIconSize, sendIconSize)); - panel->sendButton->setFixedSize (DpiUtils::scaled (36), - DpiUtils::scaled (36)); + panel->sendButton->setFixedSize (DpiUtils::scaled (kSendButtonSize), + DpiUtils::scaled (kSendButtonSize)); panel->sendButton->setStyleSheet ( QString ("QPushButton { border: none; border-radius: %1px; " " background-color: transparent; }" "QPushButton:hover { background-color: #f0f0f0; }" "QPushButton:pressed { background-color: #e0e0e0; }") - .arg (DpiUtils::scaled (18))); + .arg (DpiUtils::scaled (kSendButtonRadius))); connect (panel->sendButton, &QPushButton::clicked, this, [this, panel] () { handle_send (panel); }); btnLayout->addWidget (panel->sendButton); @@ -1995,7 +2015,7 @@ QTChatTabWidget::restore_conversation (const string& sessionId, inputAreaLayout->addWidget (inputFrame, 0); QTimer* inputHeightTimer= new QTimer (inputFrame); - inputHeightTimer->setInterval (100); + inputHeightTimer->setInterval (kInputHeightCheckIntervalMs); connect (inputHeightTimer, &QTimer::timeout, this, [this, panel] () { adjust_input_height (panel); }); inputHeightTimer->start (); @@ -2013,7 +2033,7 @@ QTChatTabWidget::restore_conversation (const string& sessionId, panel->itemWidget->setObjectName ("chat-tab-session-item"); QHBoxLayout* itemLayout= new QHBoxLayout (panel->itemWidget); itemLayout->setContentsMargins (0, 0, 0, 0); - itemLayout->setSpacing (DpiUtils::scaled (4)); + itemLayout->setSpacing (DpiUtils::scaled (kSessionItemSpacing)); panel->selectCheckBox= new QCheckBox (panel->itemWidget); panel->selectCheckBox->setObjectName ("chat-tab-select-checkbox"); @@ -2040,7 +2060,7 @@ QTChatTabWidget::restore_conversation (const string& sessionId, "#ffffff; } " "QPushButton:checked { background-color: #e8eefc; " "border-color: #9bb3ff; font-weight: 600; }") - .arg (DpiUtils::scaled (6)) + .arg (DpiUtils::scaled (kConversationBtnRadius)) .arg (DpiUtils::scaled (kNavButtonPadY)) .arg (DpiUtils::scaled (kNavButtonPadX))); connect (panel->sidebarButton, &QPushButton::clicked, this, From eb03f8c08226800a44e1c0983edad404123da53c Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 20 May 2026 19:55:42 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E6=96=B0=E5=AF=B9=E8=AF=9D=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E6=95=88=E6=9E=9C=E4=BC=98=E5=8C=96-11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devel/1019.md | 114 ++++++++++++++++++++++++++ src/Plugins/Qt/qt_chat_tab_widget.cpp | 4 +- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 devel/1019.md diff --git a/devel/1019.md b/devel/1019.md new file mode 100644 index 0000000000..5d13b88287 --- /dev/null +++ b/devel/1019.md @@ -0,0 +1,114 @@ +# [1019] 优化 New chat 按钮及浮球按钮 UI + +## 1 相关文档 +- [dddd.md](dddd.md) - 任务文档模板 +- [1018.md](1018.md) - 优化 LLM Chat 侧边栏开关按钮 UI + +## 2 任务相关的代码文件 +- `src/Plugins/Qt/qt_chat_tab_widget.cpp` +- `src/Plugins/Qt/qt_chat_tab_widget.hpp` +- `TeXmacs/misc/images/llm-chat/addchat.svg` +- `TeXmacs/misc/images/images.qrc` + +## 3 如何测试 + +### 3.1 确定性测试(单元测试) +```bash +xmake b qt_chat_tab_widget_test +xmake r qt_chat_tab_widget_test +``` + +### 3.2 非确定性测试(文档验证) +```bash +xmake b stem +``` +运行后打开 LLM Chat 标签页,验证: + +1. **New chat 按钮样式**: + - 文本左侧有 addchat.svg 图标(18px) + - 按钮居中显示在侧边栏 + - 固定尺寸 140x36px,pill 形状(圆角 18px) + - 无边框,白色背景,无 hover 背景色变化 + - 有柔和阴影(blur=3, alpha=25, offset=1px) + - 鼠标悬停时阴影加深(blur=6, alpha=50, offset=2px) + +2. **收起态浮球按钮**: + - 点击收缩按钮后侧边栏隐藏 + - 内容区左上角出现胶囊形容器,包含两个圆球按钮: + - 左侧:展开按钮(sidebar.svg) + - 右侧:新建聊天按钮(addchat.svg) + - 胶囊容器有 4px 内边距和圆角背景 + - 点击新建聊天按钮可创建新会话 + +3. **常量提取**:文件顶部所有魔法数字均已提取为 `constexpr` 常量 + +## 4 如何提交 + +提交前执行以下最少步骤: + +```bash +xmake b qt_chat_tab_widget_test +xmake r qt_chat_tab_widget_test +xmake b stem +``` + +## 5 What + +优化 LLM Chat 标签页的 New chat 按钮及收起态浮球按钮 UI。 + +1. **New chat 按钮视觉升级**: + - 添加 addchat.svg 图标到文本左侧 + - 固定尺寸 140x36px,pill 圆角(高度的一半) + - 去掉边框和 hover 背景色 + - 添加 `QGraphicsDropShadowEffect` 阴影效果 + - 悬停时通过 eventFilter 动态加深阴影(替代背景色变化) + - 按钮在侧边栏水平居中 + +2. **收起态添加浮球新建聊天按钮**: + - 在内容区左上角添加圆球新建聊天按钮(与展开按钮并排) + - 两个浮球按钮放入统一的胶囊形容器中 + - 容器有灰色背景、4px 内边距、4px 按钮间距和圆角 + +3. **提取魔法数字为常量**: + - 新增 17 个 `constexpr` 常量:按钮尺寸、阴影参数、间距、圆角等 + - 删除 7 个不再使用的无用常量 + - 所有 `DpiUtils::scaled()` 调用均使用命名常量 + +## 6 Why + +1. New chat 按钮原为纯文本且无样式,视觉上不够突出,缺乏现代感 +2. 收起态只有展开按钮,用户需要展开侧边栏才能新建聊天,操作路径长 +3. 代码中存在大量裸魔法数字,不利于维护和 DPI 适配 + +## 7 How + +### 7.1 New chat 按钮 +在 `setup_left_sidebar()` 中: +- `setIcon(QIcon(":llm-chat/addchat.svg"))` 添加图标 +- `setFixedSize(QSize(140, 36))` 固定尺寸 +- QSS 中 `border: none` 去掉边框,`border-radius: 18px` 形成 pill 形状 +- 去掉 `QPushButton:hover` 背景色规则 +- 创建 `QGraphicsDropShadowEffect`,设置 blur=3、alpha=25、offset_y=1 +- `installEventFilter` 监听 `HoverEnter`/`HoverLeave`,动态调整阴影参数 +- `normalLayout->addWidget(newChatButton_, 0, Qt::AlignHCenter)` 居中 + +### 7.2 浮球胶囊容器 +在 `setup_right_content()` 中: +- 创建 `QWidget` 作为容器,使用 `QHBoxLayout` 水平排列两个按钮 +- 容器设置 `#e8e8e8` 背景色和圆角(按钮半径 + 内边距) +- 两个按钮通过 `setup_floating_button()` 统一创建(透明背景,由容器提供底色) +- 容器统一显示/隐藏,通过 `move()` 定位到内容区左上角 + +### 7.3 常量提取 +新增常量示例: +- `kNewChatButtonHeight = 36`, `kNewChatButtonWidth = 140` +- `kNewChatShadowBlur = 3`, `kNewChatShadowAlpha = 25` +- `kNewChatHoverShadowBlur = 6`, `kNewChatHoverShadowAlpha = 50` +- `kSendButtonSize = 36`, `kSendButtonRadius = 18` +- `kConversationBtnRadius = 6`, `kModelLabelMinHeight = 20` +- 等 17 个常量 + +删除无用常量: +- `kSendButtonPadY`, `kSendButtonPadX`, `kSendButtonFontPx` +- `kContentMarginX`, `kTopPanelMaxWidth`, `kInputFrameBorder` +- `kFloatingNewChatBtnMarginX` diff --git a/src/Plugins/Qt/qt_chat_tab_widget.cpp b/src/Plugins/Qt/qt_chat_tab_widget.cpp index fc339a431e..0ef1918c8a 100644 --- a/src/Plugins/Qt/qt_chat_tab_widget.cpp +++ b/src/Plugins/Qt/qt_chat_tab_widget.cpp @@ -164,6 +164,8 @@ constexpr int kFloatingBtnMarginX= 12; constexpr int kFloatingBtnMarginY= 130; /// 浮球容器内边距(像素)。 constexpr int kFloatingContainerPad= 4; +/// 浮球按钮间距(像素)。 +constexpr int kFloatingBtnSpacing= 4; /// New chat 按钮图标尺寸(像素)。 constexpr int kNewChatIconSize= 18; /// New chat 按钮固定高度(像素)。 @@ -628,7 +630,7 @@ QTChatTabWidget::setup_right_content (QHBoxLayout* mainLayout) { DpiUtils::scaled (kFloatingContainerPad), DpiUtils::scaled (kFloatingContainerPad), DpiUtils::scaled (kFloatingContainerPad)); - floatingLayout->setSpacing (0); + floatingLayout->setSpacing (DpiUtils::scaled (kFloatingBtnSpacing)); floatingContainer->setStyleSheet ( QString ("QWidget#chat-tab-floating-container { " "background-color: #e8e8e8; border-radius: %1px; }")