feat: 主题切换(light/dark QSS)、QSS资源编译修复、托盘图标主题色
- 新增 main_dark.qss 暗色主题样式表 - 使用 .qrc + add_executable 方式确保 QSS 资源正确编译 - Application::applyTheme 动态切换主题和样式表 - 托盘图标 light 主题黑色、dark 主题白色 - Settings 保存后实时应用主题/字体 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
f8173cd0c1
commit
ae35404d26
@ -139,7 +139,9 @@ else()
|
||||
list(APPEND HEADERS src/core/caps_lock_voice_hotkey.h src/core/wayland_text_injector.h)
|
||||
add_compile_definitions(PLATFORM_LINUX)
|
||||
endif()
|
||||
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
|
||||
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}
|
||||
src/ui/resources/styles/styles.qrc
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
@ -197,15 +199,6 @@ if(WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ============================================================================
|
||||
# 资源文件
|
||||
# ============================================================================
|
||||
# 样式表
|
||||
qt_add_resources(${PROJECT_NAME} "styles"
|
||||
PREFIX "/"
|
||||
FILES
|
||||
src/ui/resources/styles/main.qss
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
# 安装
|
||||
|
||||
@ -3,11 +3,21 @@
|
||||
#include "core/sense_voice_engine.h"
|
||||
#include "utils/logger.h"
|
||||
#include <QFile>
|
||||
|
||||
static const char* const kTag = "Application";
|
||||
#include <QPalette>
|
||||
#include <QColor>
|
||||
#include <QStyleFactory>
|
||||
#include <QStyle>
|
||||
#include <QFont>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
|
||||
namespace impress {
|
||||
|
||||
static QString s_currentTheme; // 跟踪当前主题
|
||||
|
||||
static const char* const kTag = "Application";
|
||||
|
||||
Application::Application(int& argc, char** argv)
|
||||
: QApplication(argc, argv)
|
||||
{
|
||||
@ -71,4 +81,88 @@ void Application::loadGlobalModel() {
|
||||
sttEngine_->loadModelAsync(modelPath, tokensPath, device, numThreads);
|
||||
}
|
||||
|
||||
void Application::applyTheme(const QString& theme) {
|
||||
s_currentTheme = theme;
|
||||
|
||||
// 1. 先设置风格(必须在 palette 和 stylesheet 之前)
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
// 2. 设置调色板
|
||||
QPalette palette;
|
||||
if (theme == "dark") {
|
||||
palette.setColor(QPalette::Window, QColor(53, 53, 53));
|
||||
palette.setColor(QPalette::WindowText, Qt::white);
|
||||
palette.setColor(QPalette::Base, QColor(25, 25, 25));
|
||||
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
||||
palette.setColor(QPalette::ToolTipBase, Qt::white);
|
||||
palette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
palette.setColor(QPalette::Text, Qt::white);
|
||||
palette.setColor(QPalette::Button, QColor(53, 53, 53));
|
||||
palette.setColor(QPalette::ButtonText, Qt::white);
|
||||
palette.setColor(QPalette::BrightText, Qt::cyan);
|
||||
palette.setColor(QPalette::Link, QColor(42, 130, 218));
|
||||
palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
|
||||
palette.setColor(QPalette::HighlightedText, Qt::black);
|
||||
palette.setColor(QPalette::Disabled, QPalette::Text, QColor(127, 127, 127));
|
||||
palette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127));
|
||||
palette.setColor(QPalette::Disabled, QPalette::WindowText, QColor(127, 127, 127));
|
||||
palette.setColor(QPalette::Disabled, QPalette::Highlight, QColor(80, 80, 80));
|
||||
palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QColor(127, 127, 127));
|
||||
} else {
|
||||
palette = qApp->style()->standardPalette();
|
||||
}
|
||||
qApp->setPalette(palette);
|
||||
|
||||
// 3. 最后设置样式表(覆盖 palette)
|
||||
const QString qssPath = (theme == "dark") ? ":/styles/main_dark.qss" : ":/styles/main.qss";
|
||||
QFile styleFile(qssPath);
|
||||
if (styleFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qApp->setStyleSheet(styleFile.readAll());
|
||||
styleFile.close();
|
||||
} else {
|
||||
LOG_ERROR("Theme", QString("无法加载样式表: %1").arg(qssPath));
|
||||
}
|
||||
|
||||
LOG_INFO("Theme", QString("主题已切换: %1").arg(theme));
|
||||
}
|
||||
|
||||
void Application::applyFontSize(int size) {
|
||||
QFont font = qApp->font();
|
||||
font.setPointSize(size);
|
||||
qApp->setFont(font);
|
||||
LOG_INFO("Theme", QString("字体大小已设置: %1").arg(size));
|
||||
}
|
||||
|
||||
QIcon Application::createTrayIcon(bool active) {
|
||||
const QColor color = (s_currentTheme == "dark") ? Qt::white : Qt::black;
|
||||
const int size = 16;
|
||||
|
||||
QPixmap pixmap(size, size);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(color);
|
||||
|
||||
if (active) {
|
||||
// 播放图标(三角形)
|
||||
const int margin = 3;
|
||||
QPolygon triangle;
|
||||
triangle << QPoint(margin, margin)
|
||||
<< QPoint(margin, size - margin)
|
||||
<< QPoint(size - margin, size / 2);
|
||||
painter.drawPolygon(triangle);
|
||||
} else {
|
||||
// 停止图标(正方形)
|
||||
const int margin = 3;
|
||||
painter.drawRect(margin, margin, size - 2 * margin, size - 2 * margin);
|
||||
}
|
||||
|
||||
return QIcon(pixmap);
|
||||
}
|
||||
|
||||
bool Application::isDarkTheme() {
|
||||
return s_currentTheme == "dark";
|
||||
}
|
||||
|
||||
} // namespace impress
|
||||
|
||||
@ -35,6 +35,18 @@ public:
|
||||
/** @brief 加载全局模型(在配置加载后手动调用) */
|
||||
void loadGlobalModel();
|
||||
|
||||
/** @brief 应用主题(light/dark),可在运行时调用 */
|
||||
static void applyTheme(const QString& theme);
|
||||
|
||||
/** @brief 应用全局字体大小 */
|
||||
static void applyFontSize(int size);
|
||||
|
||||
/** @brief 生成托盘图标(light=黑色,dark=白色) */
|
||||
static QIcon createTrayIcon(bool active);
|
||||
|
||||
/** @brief 当前主题是否为 dark */
|
||||
static bool isDarkTheme();
|
||||
|
||||
signals:
|
||||
/** @brief 模型加载中(带路径) */
|
||||
void modelLoading(const QString& modelPath);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QCommandLineParser>
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
@ -66,6 +67,13 @@ int main(int argc, char* argv[])
|
||||
configManager->set("stt.model_path", modelPath);
|
||||
}
|
||||
|
||||
// 应用主题和字体
|
||||
QString theme = configManager->get("ui.theme").toString();
|
||||
int fontSize = configManager->get("ui.font_size").toInt();
|
||||
impress::Application::applyTheme(theme);
|
||||
if (fontSize > 0) impress::Application::applyFontSize(fontSize);
|
||||
LOG_INFO("Main", QString("主题: %1, 字体: %2").arg(theme).arg(fontSize));
|
||||
|
||||
// 配置加载完成后,启动全局模型加载
|
||||
app.loadGlobalModel();
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "core/voice_input_service.h"
|
||||
#include "core/sense_voice_engine.h"
|
||||
#include "app/config_manager.h"
|
||||
#include "app/application.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#include <QMenuBar>
|
||||
@ -37,7 +38,6 @@ MainWindow::MainWindow(ConfigManager* configManager,
|
||||
setupMenuBar();
|
||||
setupStatusBar(sttEngine);
|
||||
setupTrayIcon();
|
||||
loadStyleSheet();
|
||||
|
||||
// 初始化语音输入服务(共享全局引擎)
|
||||
voiceInputService_ = new VoiceInputService(configManager_, sttEngine, this);
|
||||
@ -126,9 +126,9 @@ void MainWindow::setupTrayIcon() {
|
||||
trayIcon_ = new QSystemTrayIcon(this);
|
||||
trayIcon_->setContextMenu(trayMenu_);
|
||||
|
||||
// 默认状态:停止图标(SP_MediaStop)
|
||||
idleIcon_ = style()->standardIcon(QStyle::SP_MediaStop);
|
||||
activeIcon_ = style()->standardIcon(QStyle::SP_MediaPlay);
|
||||
// 默认状态:根据主题颜色生成图标
|
||||
idleIcon_ = Application::createTrayIcon(false);
|
||||
activeIcon_ = Application::createTrayIcon(true);
|
||||
|
||||
trayIcon_->setIcon(idleIcon_);
|
||||
trayIcon_->setToolTip("Impress Voice Input - 语音输入就绪");
|
||||
@ -236,6 +236,17 @@ void MainWindow::updateModelStatus() {
|
||||
void MainWindow::onVoiceInputConfigChanged() {
|
||||
if (!voiceInputService_) return;
|
||||
|
||||
// 动态应用主题和字体
|
||||
QString theme = configManager_->get("ui.theme").toString();
|
||||
int fontSize = configManager_->get("ui.font_size").toInt();
|
||||
Application::applyTheme(theme);
|
||||
if (fontSize > 0) Application::applyFontSize(fontSize);
|
||||
|
||||
// 刷新托盘图标颜色
|
||||
idleIcon_ = Application::createTrayIcon(false);
|
||||
activeIcon_ = Application::createTrayIcon(true);
|
||||
updateTrayIcon("语音输入就绪");
|
||||
|
||||
// 更新模型状态显示
|
||||
updateModelStatus();
|
||||
|
||||
|
||||
@ -1,143 +1,157 @@
|
||||
/* Impress Voice Input - 全局样式表 */
|
||||
/* Impress Voice Input - 亮色主题样式表 */
|
||||
|
||||
/* ========== 全局 ========== */
|
||||
* {
|
||||
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
|
||||
}
|
||||
|
||||
QMainWindow, QWidget {
|
||||
QWidget {
|
||||
background-color: #ffffff;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
/* 容器控件必须显式设置背景 */
|
||||
QFrame {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
QScrollArea, QScrollArea > QWidget {
|
||||
background-color: #ffffff;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
/* ========== QTabWidget ========== */
|
||||
QTabWidget::pane {
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
background: #fafafa;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
QTabBar::tab {
|
||||
background: #f0f2f5;
|
||||
border: 1px solid #dcdfe6;
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
padding: 10px 24px;
|
||||
margin-right: 2px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
QTabBar::tab:selected {
|
||||
background: #ffffff;
|
||||
border-bottom: 2px solid #409eff;
|
||||
color: #409eff;
|
||||
border-bottom: 2px solid #1976d2;
|
||||
color: #1976d2;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
QTabBar::tab:hover {
|
||||
color: #409eff;
|
||||
color: #1976d2;
|
||||
background: #e8eaf6;
|
||||
}
|
||||
|
||||
/* ========== QPushButton ========== */
|
||||
QPushButton {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 4px;
|
||||
padding: 6px 16px;
|
||||
color: #606266;
|
||||
color: #333333;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
background-color: #ecf5ff;
|
||||
border-color: #b3d8ff;
|
||||
color: #409eff;
|
||||
background-color: #e3f2fd;
|
||||
border-color: #1976d2;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: #e6f0ff;
|
||||
background-color: #bbdefb;
|
||||
}
|
||||
|
||||
/* 主要操作按钮 */
|
||||
QPushButton[objectName="saveBtn"],
|
||||
QPushButton[text="保存配置"] {
|
||||
background-color: #409eff;
|
||||
background-color: #1976d2;
|
||||
color: #ffffff;
|
||||
border: 1px solid #409eff;
|
||||
border: 1px solid #1976d2;
|
||||
}
|
||||
|
||||
QPushButton[objectName="saveBtn"]:hover,
|
||||
QPushButton[text="保存配置"]:hover {
|
||||
background-color: #66b1ff;
|
||||
background-color: #1565c0;
|
||||
}
|
||||
|
||||
/* 危险操作按钮 */
|
||||
QPushButton[text="停止"],
|
||||
QPushButton[text="停止录音"] {
|
||||
background-color: #f56c6c;
|
||||
background-color: #e53935;
|
||||
color: #ffffff;
|
||||
border: 1px solid #f56c6c;
|
||||
border: 1px solid #e53935;
|
||||
}
|
||||
|
||||
QPushButton[text="停止"]:hover,
|
||||
QPushButton[text="停止录音"]:hover {
|
||||
background-color: #f78989;
|
||||
background-color: #c62828;
|
||||
}
|
||||
|
||||
/* ========== QGroupBox ========== */
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
margin-top: 12px;
|
||||
padding-top: 16px;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top left;
|
||||
padding: 0 8px;
|
||||
color: #303133;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
/* ========== QLabel ========== */
|
||||
QLabel {
|
||||
color: #606266;
|
||||
color: #333333;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* ========== QLineEdit ========== */
|
||||
QLineEdit {
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
background: #ffffff;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
QLineEdit:focus {
|
||||
border-color: #409eff;
|
||||
border-color: #1976d2;
|
||||
}
|
||||
|
||||
QLineEdit[readOnly="true"] {
|
||||
background-color: #f5f7fa;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* ========== QComboBox ========== */
|
||||
QComboBox {
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
background: #ffffff;
|
||||
color: #1a1a1a;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
QComboBox:hover {
|
||||
border-color: #c0c4cc;
|
||||
border-color: #909090;
|
||||
}
|
||||
|
||||
QComboBox:focus {
|
||||
border-color: #409eff;
|
||||
border-color: #1976d2;
|
||||
}
|
||||
|
||||
QComboBox::drop-down {
|
||||
@ -145,52 +159,62 @@ QComboBox::drop-down {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
background-color: #ffffff;
|
||||
color: #1a1a1a;
|
||||
selection-background-color: #e3f2fd;
|
||||
}
|
||||
|
||||
/* ========== QSpinBox / QDoubleSpinBox ========== */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
background: #ffffff;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
QSpinBox:focus, QDoubleSpinBox:focus {
|
||||
border-color: #409eff;
|
||||
border-color: #1976d2;
|
||||
}
|
||||
|
||||
/* ========== QProgressBar ========== */
|
||||
QProgressBar {
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
background: #f5f7fa;
|
||||
background: #f5f5f5;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #409eff, stop:1 #66b1ff);
|
||||
stop:0 #1976d2, stop:1 #42a5f5);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* ========== QTextEdit ========== */
|
||||
QTextEdit {
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background: #ffffff;
|
||||
selection-background-color: #ecf5ff;
|
||||
color: #1a1a1a;
|
||||
selection-background-color: #e3f2fd;
|
||||
}
|
||||
|
||||
QTextEdit:focus {
|
||||
border-color: #409eff;
|
||||
border-color: #1976d2;
|
||||
}
|
||||
|
||||
/* ========== QListWidget ========== */
|
||||
QListWidget {
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
padding: 4px;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
QListWidget::item {
|
||||
@ -199,58 +223,62 @@ QListWidget::item {
|
||||
}
|
||||
|
||||
QListWidget::item:selected {
|
||||
background-color: #ecf5ff;
|
||||
color: #409eff;
|
||||
background-color: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
QListWidget::item:hover {
|
||||
background-color: #f5f7fa;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* ========== QCheckBox ========== */
|
||||
QCheckBox {
|
||||
spacing: 8px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
QCheckBox::indicator {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 3px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #409eff;
|
||||
border-color: #409eff;
|
||||
background-color: #1976d2;
|
||||
border-color: #1976d2;
|
||||
}
|
||||
|
||||
/* ========== QMenu / QMenuBar ========== */
|
||||
QMenuBar {
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 2px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
QMenuBar::item:selected {
|
||||
background-color: #ecf5ff;
|
||||
color: #409eff;
|
||||
background-color: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
QMenu {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #dcdfe6;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
QMenu::item:selected {
|
||||
background-color: #ecf5ff;
|
||||
color: #409eff;
|
||||
background-color: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
QMenu::separator {
|
||||
height: 1px;
|
||||
background-color: #ebeef5;
|
||||
background-color: #e0e0e0;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
@ -260,25 +288,25 @@ QMessageBox {
|
||||
}
|
||||
|
||||
QMessageBox QLabel {
|
||||
color: #303133;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
/* ========== 滚动条 ========== */
|
||||
QScrollBar:vertical {
|
||||
border: none;
|
||||
background: #f5f7fa;
|
||||
background: #f5f5f5;
|
||||
width: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background: #c0c4cc;
|
||||
background: #bdbdbd;
|
||||
border-radius: 4px;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background: #909399;
|
||||
background: #9e9e9e;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical,
|
||||
|
||||
312
src/ui/resources/styles/main_dark.qss
Normal file
312
src/ui/resources/styles/main_dark.qss
Normal file
@ -0,0 +1,312 @@
|
||||
/* Impress Voice Input - 暗色主题样式表 */
|
||||
|
||||
/* ========== 全局 ========== */
|
||||
* {
|
||||
font-family: "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
|
||||
}
|
||||
|
||||
QWidget {
|
||||
background-color: #353535;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QFrame {
|
||||
background-color: #353535;
|
||||
}
|
||||
|
||||
QScrollArea, QScrollArea > QWidget {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
/* ========== QTabWidget ========== */
|
||||
QTabWidget::pane {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
QTabBar::tab {
|
||||
background: #3a3a3a;
|
||||
border: 1px solid #555555;
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
padding: 10px 24px;
|
||||
margin-right: 2px;
|
||||
font-size: 14px;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
QTabBar::tab:selected {
|
||||
background: #2a2a2a;
|
||||
border-bottom: 2px solid #4286f4;
|
||||
color: #4286f4;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
QTabBar::tab:hover {
|
||||
color: #4286f4;
|
||||
}
|
||||
|
||||
/* ========== QPushButton ========== */
|
||||
QPushButton {
|
||||
background-color: #353535;
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
padding: 6px 16px;
|
||||
color: #cccccc;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
background-color: #4286f4;
|
||||
border-color: #4286f4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: #3a6fd8;
|
||||
}
|
||||
|
||||
/* 主要操作按钮 */
|
||||
QPushButton[objectName="saveBtn"],
|
||||
QPushButton[text="保存配置"] {
|
||||
background-color: #4286f4;
|
||||
color: #ffffff;
|
||||
border: 1px solid #4286f4;
|
||||
}
|
||||
|
||||
QPushButton[objectName="saveBtn"]:hover,
|
||||
QPushButton[text="保存配置"]:hover {
|
||||
background-color: #5a9aff;
|
||||
}
|
||||
|
||||
/* 危险操作按钮 */
|
||||
QPushButton[text="停止"],
|
||||
QPushButton[text="停止录音"] {
|
||||
background-color: #e74c3c;
|
||||
color: #ffffff;
|
||||
border: 1px solid #e74c3c;
|
||||
}
|
||||
|
||||
QPushButton[text="停止"]:hover,
|
||||
QPushButton[text="停止录音"]:hover {
|
||||
background-color: #f05e50;
|
||||
}
|
||||
|
||||
/* ========== QGroupBox ========== */
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
border: 1px solid #555555;
|
||||
border-radius: 6px;
|
||||
margin-top: 12px;
|
||||
padding-top: 16px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top left;
|
||||
padding: 0 8px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* ========== QLabel ========== */
|
||||
QLabel {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
/* ========== QLineEdit ========== */
|
||||
QLineEdit {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
background: #1a1a1a;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QLineEdit:focus {
|
||||
border-color: #4286f4;
|
||||
}
|
||||
|
||||
QLineEdit[readOnly="true"] {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
/* ========== QComboBox ========== */
|
||||
QComboBox {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px;
|
||||
background: #1a1a1a;
|
||||
color: #ffffff;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
QComboBox:hover {
|
||||
border-color: #888888;
|
||||
}
|
||||
|
||||
QComboBox:focus {
|
||||
border-color: #4286f4;
|
||||
}
|
||||
|
||||
QComboBox::drop-down {
|
||||
border: none;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
background-color: #1a1a1a;
|
||||
color: #ffffff;
|
||||
selection-background-color: #4286f4;
|
||||
}
|
||||
|
||||
/* ========== QSpinBox / QDoubleSpinBox ========== */
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
background: #1a1a1a;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QSpinBox:focus, QDoubleSpinBox:focus {
|
||||
border-color: #4286f4;
|
||||
}
|
||||
|
||||
/* ========== QProgressBar ========== */
|
||||
QProgressBar {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
height: 20px;
|
||||
background: #2a2a2a;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QProgressBar::chunk {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
|
||||
stop:0 #4286f4, stop:1 #5a9aff);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* ========== QTextEdit ========== */
|
||||
QTextEdit {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
background: #1a1a1a;
|
||||
color: #ffffff;
|
||||
selection-background-color: #4286f4;
|
||||
}
|
||||
|
||||
QTextEdit:focus {
|
||||
border-color: #4286f4;
|
||||
}
|
||||
|
||||
/* ========== QListWidget ========== */
|
||||
QListWidget {
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
background: #1a1a1a;
|
||||
padding: 4px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QListWidget::item {
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QListWidget::item:selected {
|
||||
background-color: #4286f4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QListWidget::item:hover {
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
|
||||
/* ========== QCheckBox ========== */
|
||||
QCheckBox {
|
||||
spacing: 8px;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
QCheckBox::indicator {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #555555;
|
||||
border-radius: 3px;
|
||||
background-color: #1a1a1a;
|
||||
}
|
||||
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #4286f4;
|
||||
border-color: #4286f4;
|
||||
}
|
||||
|
||||
/* ========== QMenu / QMenuBar ========== */
|
||||
QMenuBar {
|
||||
background-color: #353535;
|
||||
border-bottom: 1px solid #555555;
|
||||
padding: 2px;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
QMenuBar::item:selected {
|
||||
background-color: #4286f4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QMenu {
|
||||
background-color: #353535;
|
||||
border: 1px solid #555555;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
QMenu::item:selected {
|
||||
background-color: #4286f4;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QMenu::separator {
|
||||
height: 1px;
|
||||
background-color: #555555;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
/* ========== QMessageBox ========== */
|
||||
QMessageBox {
|
||||
background-color: #353535;
|
||||
}
|
||||
|
||||
QMessageBox QLabel {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* ========== 滚动条 ========== */
|
||||
QScrollBar:vertical {
|
||||
border: none;
|
||||
background: #2a2a2a;
|
||||
width: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
background: #666666;
|
||||
border-radius: 4px;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
QScrollBar::handle:vertical:hover {
|
||||
background: #888888;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical,
|
||||
QScrollBar::sub-line:vertical {
|
||||
height: 0;
|
||||
}
|
||||
6
src/ui/resources/styles/styles.qrc
Normal file
6
src/ui/resources/styles/styles.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/styles">
|
||||
<file>main.qss</file>
|
||||
<file>main_dark.qss</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Loading…
Reference in New Issue
Block a user