| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186 |
- #include "thememanager.h"
- #include <QApplication>
- #include <QFile>
- #include <QJsonDocument>
- #include <QMetaEnum>
- #include <cmath>
- static const QByteArray defaultConfig = R"Raw(
- {
- "color_mode": {
- "light": {
-
- },
- "dark": {
-
- }
- },
- "size_mode": {
- "small": {
- "font_base": "12px",
- "padding_base": "4px",
- "radius_base": "2px",
- "control_height": "20px"
- },
- "medium": {
- "font_base": "14px",
- "padding_base": "8px",
- "radius_base": "4px",
- "control_height": "28px"
- },
- "large": {
- "font_base": "16px",
- "padding_base": "12px",
- "radius_base": "6px",
- "control_height": "36px"
- }
- }
- }
- )Raw";
- static const QByteArray defaultQss = R"Raw(
- /********************* 基础样式 *********************/
- QWidget {
- font-family: "Segoe UI", "Microsoft YaHei";
- font-size: @font_base;
- color: @colorText;
- background-color: @colorBgContainer;
- }
- * {
- font-family: "Segoe UI", "Microsoft YaHei";
- font-size: @font_base;
- color: @colorText;
- background-color: @colorBgContainer;
- selection-background-color: @colorPrimaryBg;
- selection-color: @colorPrimaryText;
- }
- /********************* 窗口栏 *********************/
- QWK--WindowBar[bar-active=true] {
- background-color: @colorPrimary;
- }
- QWK--WindowBar[bar-active=false] {
- background-color: @colorPrimaryBgHover;
- }
- QWK--WindowBar>QLabel#win-title-label {
- padding: 0;
- border: none;
- color: @colorText;
- background-color: transparent;
- min-height: 28px;
- }
- /* 系统按钮 */
- QWK--WindowBar>QAbstractButton[system-button=true] {
- qproperty-iconSize: 12px 12px;
- min-width: 40px;
- border: none;
- padding: 0;
- background-color: transparent;
- }
- QWK--WindowBar>QAbstractButton#settings-button {
- qproperty-iconNormal: url(":/window-bar/more-line.svg");
- qproperty-iconChecked: url(":/window-bar/more-line.svg");
- qproperty-iconSize: 15px 15px;
- }
- QWK--WindowBar>QAbstractButton#settings-button:hover,
- QWK--WindowBar>QAbstractButton#settings-button:pressed {
- background-color: @colorPrimaryBgHover;
- }
- QWK--WindowBar>QAbstractButton#pin-button {
- qproperty-iconNormal: url(":/window-bar/pin.svg");
- qproperty-iconChecked: url(":/window-bar/pin-fill.svg");
- qproperty-iconSize: 15px 15px;
- }
- QWK--WindowBar>QAbstractButton#pin-button:hover,
- QWK--WindowBar>QAbstractButton#pin-button:pressed {
- background-color: @colorPrimaryBgHover;
- }
- QWK--WindowBar>QAbstractButton#min-button {
- qproperty-iconNormal: url(":/window-bar/minimize.svg");
- }
- QWK--WindowBar>QAbstractButton#min-button:hover,
- QWK--WindowBar>QAbstractButton#min-button:pressed {
- background-color: @colorPrimaryBgHover;
- }
- QWK--WindowBar>QAbstractButton#max-button {
- qproperty-iconNormal: url(":/window-bar/maximize.svg");
- qproperty-iconChecked: url(":/window-bar/restore.svg");
- }
- QWK--WindowBar>QAbstractButton#max-button:hover,
- QWK--WindowBar>QAbstractButton#max-button:pressed {
- background-color: @colorPrimaryBgHover;
- }
- QWK--WindowBar>QAbstractButton#close-button {
- qproperty-iconNormal: url(":/window-bar/close.svg");
- }
- QWK--WindowBar>QAbstractButton#close-button:hover,
- QWK--WindowBar>QAbstractButton#close-button:pressed {
- background-color: @colorError;
- }
- QWK--WindowBar>QAbstractButton#icon-button {
- qproperty-iconNormal: url(":/app/example.png");
- qproperty-iconSize: 18px 18px;
- min-width: 40px;
- border: none;
- padding: 0;
- background-color: transparent;
- }
- /********************* 通用控件 *********************/
- /* 按钮 */
- QPushButton {
- background-color: @colorPrimary;
- color: @colorWhite;
- border: 1px solid @colorPrimaryBorder;
- border-radius: @radius_base;
- padding: @padding_base;
- min-height: @control_height;
- min-width: 80px;
- }
- QPushButton:hover {
- background-color: @colorPrimaryHover;
- border-color: @colorPrimaryBorderHover;
- }
- QPushButton:pressed {
- background-color: @colorPrimaryActive;
- border-color: @colorPrimaryBorder;
- }
- QPushButton:disabled {
- background-color: @colorFillQuaternary;
- border-color: @colorBorderSecondary;
- color: @colorTextQuaternary;
- }
- /* 标签 */
- QLabel {
- background-color: transparent;
- padding: @padding_base;
- color: @colorText;
- }
- /* 输入控件 */
- QLineEdit, QTextEdit, QPlainTextEdit, QComboBox, QSpinBox, QDateTimeEdit {
- background-color: @colorBgContainer;
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- padding: @padding_base;
- min-height: @control_height;
- color: @colorText;
- }
- QLineEdit:hover, QTextEdit:hover, QPlainTextEdit:hover,
- QComboBox:hover, QSpinBox:hover, QDateTimeEdit:hover {
- border-color: @colorPrimaryHover;
- background-color: @colorBgContainer;
- }
- QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus,
- QComboBox:focus, QSpinBox:focus, QDateTimeEdit:focus {
- border-color: @colorPrimary;
- background-color: @colorBgContainer;
- }
- QComboBox::drop-down {
- subcontrol-origin: padding;
- subcontrol-position: center right;
- width: 20px;
- border-left: 1px solid @colorBorder;
- }
- QComboBox QAbstractItemView {
- background: @colorBgContainer;
- border: 1px solid @colorBorder;
- selection-background-color: @colorPrimaryBg;
- selection-color: @colorPrimaryText;
- }
- /* 选择控件 */
- QCheckBox, QRadioButton {
- background-color: transparent;
- color: @colorText;
- }
- QCheckBox::indicator, QRadioButton::indicator {
- width: 16px;
- height: 16px;
- }
- QCheckBox::indicator {
- border: 1px solid @colorBorder;
- border-radius: @radius_small;
- background: @colorBgContainer;
- }
- QCheckBox::indicator:checked {
- background-color: @colorPrimary;
- border-color: @colorPrimary;
- image: url(":/theme/checked.svg");
- }
- QCheckBox:disabled {
- color: @colorTextQuaternary;
- }
- QRadioButton::indicator {
- border: 1px solid @colorBorder;
- border-radius: 8px;
- background: @colorBgContainer;
- }
- QRadioButton::indicator:checked {
- background-color: @colorPrimary;
- border-color: @colorPrimary;
- image: url(":/theme/radio-checked.svg");
- }
- QRadioButton:disabled {
- color: @colorTextQuaternary;
- }
- /********************* 复杂控件 *********************/
- /* 选项卡 */
- QTabWidget::pane {
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- }
- QTabBar::tab {
- background: @colorBgContainer;
- border: 1px solid transparent;
- padding: @padding_base;
- margin-right: 4px;
- color: @colorText;
- }
- QTabBar::tab:selected {
- background: @colorPrimaryBg;
- border-bottom: 2px solid @colorPrimary;
- color: @colorPrimaryText;
- }
- QTabBar::tab:hover {
- background: @colorPrimaryBgHover;
- }
- /* 滚动条 */
- /* 滚动条整体 */
- QScrollBar:vertical {
- background: @colorFillQuaternary; /* 滚动条轨道背景 */
- width: 10px; /* 垂直滚动条宽度 */
- margin: 10px 0 10px 0; /* 上下留白 */
- }
- QScrollBar:horizontal {
- background: @colorFillQuaternary; /* 滚动条轨道背景 */
- height: 10px; /* 水平滚动条高度 */
- margin: 0 10px 0 10px; /* 左右留白 */
- }
- /* 滑块(Handle) */
- QScrollBar::handle:vertical {
- background: #eaeaea; /* 滑块颜色 */
- min-height: 30px; /* 垂直滑块最小高度(重要!) */
- border-radius: 5px; /* 可选圆角 */
- }
- QScrollBar::handle:horizontal {
- background: #eaeaea; /* 滑块颜色 */
- min-width: 30px; /* 水平滑块最小宽度(重要!) */
- border-radius: 5px; /* 可选圆角 */
- }
- /* 滑块悬停/按下效果 */
- QScrollBar::handle:vertical:hover,
- QScrollBar::handle:horizontal:hover {
- background: #b0b0b0; /* 悬停颜色 */
- }
- QScrollBar::handle:vertical:pressed,
- QScrollBar::handle:horizontal:pressed {
- background: #b0b0b0; /* 按下颜色 */
- }
- /* 上下/左右箭头按钮(隐藏箭头) */
- QScrollBar::add-line:vertical,
- QScrollBar::sub-line:vertical,
- QScrollBar::add-line:horizontal,
- QScrollBar::sub-line:horizontal {
- background: none; /* 隐藏箭头按钮背景 */
- border: none; /* 移除边框 */
- height: 0; /* 垂直箭头高度设为0 */
- width: 0; /* 水平箭头宽度设为0 */
- }
- /* 滚动条边缘的空白区域(Add-Page/Sub-Page) */
- QScrollBar::add-page:vertical,
- QScrollBar::sub-page:vertical,
- QScrollBar::add-page:horizontal,
- QScrollBar::sub-page:horizontal {
- background: none; /* 移除默认灰色背景 */
- }
- /* 树形视图 */
- QTreeView {
- show-decoration-selected: 1;
- alternate-background-color: @colorBgContainer;
- }
- QTreeView::item:hover {
- background: @colorPrimaryBgHover;
- }
- QTreeView::item:selected {
- background: @colorPrimaryBg;
- color: @colorPrimaryText;
- }
- /********************* 列表视图 *********************/
- QListView {
- outline: none;
- background-color: @colorBgContainer;
- alternate-background-color: @colorFillQuaternary;
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- padding: 2px;
- }
- QListView::item {
- border-radius: @radius_small;
- padding: @padding_base;
- margin: 1px;
- }
- QListView::item:hover {
- background: @colorPrimaryBgHover;
- }
- QListView::item:selected {
- background: @colorPrimaryBg;
- color: @colorPrimaryText;
- }
- QListView::item:selected:active {
- background: @colorPrimaryBg;
- color: @colorPrimaryText;
- }
- QListView::item:selected:!active {
- background: @colorFillSecondary;
- color: @colorTextSecondary;
- }
- /********************* 分组框 *********************/
- QGroupBox {
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- margin-top: 16px;
- padding-top: 20px;
- }
- QGroupBox::title {
- subcontrol-origin: margin;
- subcontrol-position: top left;
- padding: 0 4px;
- color: @colorTextSecondary;
- left: 12px;
- }
- QGroupBox {
- background-color: transparent;
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- margin-top: 1ex;
- }
- /********************* 滑块控件 *********************/
- QSlider::groove:horizontal {
- height: 4px;
- background: @colorFillQuaternary;
- border-radius: 2px;
- }
- QSlider::handle:horizontal {
- width: 16px;
- margin: -6px 0;
- background: @colorPrimary;
- border-radius: 8px;
- }
- QSlider::add-page:horizontal {
- background: @colorFillQuaternary;
- }
- QSlider::sub-page:horizontal {
- background: @colorPrimary;
- }
- /********************* 进度条 *********************/
- QProgressBar {
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- background: @colorFillQuaternary;
- text-align: center;
- color: @colorText;
- padding: 1px;
- min-height: 10px;
- }
- QProgressBar::chunk {
- background: @colorPrimary;
- border-radius: calc(@radius_base - 1px);
- }
- /********************* 菜单控件 *********************/
- QMenu {
- background: @colorBgContainer;
- border: 1px solid @colorBorder;
- padding: 4px;
- }
- QMenu::item {
- padding: 6px 24px;
- margin: 2px;
- border-radius: @radius_small;
- }
- QMenu::item:selected {
- background: @colorPrimaryBg;
- color: @colorPrimaryText;
- }
- QMenu::separator {
- height: 1px;
- background: @colorBorder;
- }
- /********************* 表格控件 *********************/
- QHeaderView::section {
- background: @colorBgContainer;
- padding: 4px;
- border: 1px solid @colorBorder;
- }
- QTableView QTableCornerButton::section {
- background: @colorBgContainer;
- border: 1px solid @colorBorder;
- }
- /********************* 工具栏 *********************/
- QToolBar {
- background: @colorBgContainer;
- border-bottom: 1px solid @colorBorder;
- spacing: 4px;
- padding: 4px;
- }
- QToolBar::separator {
- width: 1px;
- background: @colorBorder;
- margin: 0 4px;
- }
- /********************* 对话框 *********************/
- QDialog {
- background: @colorBgContainer;
- border: 1px solid @colorBorder;
- border-radius: @radius_base;
- }
- QMessageBox QLabel#qt_msgbox_label {
- color: @colorText;
- padding: 12px;
- }
- QMessageBox QPushButton {
- min-width: 80px;
- margin: 4px;
- }
- /********************* 工具提示 *********************/
- QToolTip {
- color: @colorText;
- background-color: @colorBgContainer;
- border: 1px solid @colorBorder;
- border-radius: @radius_small;
- padding: 4px 8px;
- }
- /********************* 特殊状态 *********************/
- /* 错误状态 */
- .error-border {
- border: 1px solid @colorError !important;
- }
- .error-text {
- color: @colorError !important;
- }
- /* 禁用状态 */
- .disabled-text {
- color: @colorTextQuaternary;
- }
- .disabled-bg {
- background-color: @colorFillQuaternary;
- }
- /* 链接样式 */
- QLabel[link="true"] {
- color: @colorLink;
- }
- QLabel[link="true"]:hover {
- color: @colorLinkHover;
- }
- /********************* 动态尺寸 *********************/
- .small {
- font-size: 12px;
- padding: 4px;
- qproperty-iconSize: 16px;
- }
- .medium {
- font-size: 14px;
- padding: 8px;
- qproperty-iconSize: 20px;
- }
- .large {
- font-size: 16px;
- padding: 12px;
- qproperty-iconSize: 24px;
- }
- /********************* 工具按钮 *********************/
- QToolButton {
- padding: 4px;
- border-radius: @radius_small;
- background: transparent;
- }
- QToolButton:hover {
- background: @colorPrimaryBgHover;
- }
- QToolButton:pressed {
- background: @colorPrimaryBg;
- }
- /********************* 分割线 *********************/
- QSplitter::handle {
- background: @colorBorder;
- margin: 2px;
- }
- QSplitter::handle:hover {
- background: @colorPrimary;
- }
- /********************* 状态栏 *********************/
- QStatusBar {
- background-color: @colorBgContainer;
- border-top: 1px solid @colorBorder;
- color: @colorText;
- min-height: 24px;
- padding: 2px 4px;
- }
- QStatusBar::item {
- border-right: 1px solid @colorBorder;
- margin: 0;
- }
- /********************* 状态类 *********************/
- .active {
- background-color: @colorPrimaryActive;
- color: @colorPrimaryTextActive;
- }
- .hover {
- background-color: @colorPrimaryBgHover;
- color: @colorPrimaryTextHover;
- }
- )Raw";
- namespace {
- const int hueStep = 2; // 色相阶梯
- const double saturationStep = 0.16; // 饱和度阶梯,浅色部分
- const double saturationStep2 = 0.05; // 饱和度阶梯,深色部分
- const double brightnessStep1 = 0.05; // 亮度阶梯,浅色部分
- const double brightnessStep2 = 0.15; // 亮度阶梯,深色部分
- const int lightColorCount = 5; // 浅色数量,主色上
- const int darkColorCount = 4; // 深色数量,主色下
- // 暗色主题颜色映射关系表
- const QVector<int> darkColorMap = {7, 6, 5, 5, 5, 5, 4, 3, 2, 1};
- const QVector<int> darkMixRatios = {15, 25, 30, 45, 65, 85, 90, 95, 97, 98};
- } // namespace
- ThemeManager &ThemeManager::instance()
- {
- static ThemeManager instance;
- return instance;
- }
- ThemeManager::ThemeManager(QObject *parent)
- : QObject(parent)
- {
- token.colorPrimary = QColor("#1677ff");
- token.colorSuccess = QColor("#52c41a");
- token.colorWarning = QColor("#faad14");
- token.colorError = QColor("#ff4d4f");
- token.colorInfo = QColor("#1677ff");
- token.colorLink = QColor("");
- token.colorTextBase = QColor("");
- token.colorBgBase = QColor("");
- token.fontFamily = QFont();
- // Line
- token.lineWidth = 1;
- token.lineType = "solid";
- // Radius
- token.borderRadius = 6;
- // Size
- token.sizeUnit = 4;
- token.sizeStep = 4;
- token.sizePopupArrow = 16;
- token.controlHeight = 32;
- QJsonDocument doc = QJsonDocument::fromJson(defaultConfig);
- loadConfig(doc.object());
- }
- void ThemeManager::loadConfig(const QJsonObject &object)
- {
- m_colorConfig = object.value("color_mode").toObject();
- m_sizeConfig = object.value("size_mode").toObject();
- generateDerivedColors();
- }
- void ThemeManager::loadConfig(const QString &configPath)
- {
- QFile configFile(configPath);
- if (!configFile.open(QIODevice::ReadOnly))
- return;
- QJsonDocument doc = QJsonDocument::fromJson(configFile.readAll());
- if (doc.isNull() || !doc.isObject()) {
- qWarning() << "Invalid JSON in config file:" << configPath;
- return;
- }
- loadConfig(doc.object());
- }
- void ThemeManager::applyTheme()
- {
- QString qss = loadQssTemplate();
- QString processed = processQss(qss);
- // qDebug().noquote() << "Processed QSS:" << processed; // 输出生成的 QSS
- qApp->setStyleSheet(processed);
- emit themeChanged();
- }
- QColor ThemeManager::color(const QString &name) const
- {
- QMetaEnum metaEnm = QMetaEnum::fromType<ColorToken>();
- bool isok = false;
- int value = metaEnm.keyToValue(name.toUtf8().data(), &isok);
- if (isok) {
- return m_colorTokens.value((ColorToken) value, QColor(Qt::black));
- }
- qDebug() << "no find " << name << m_colorTokens;
- return QColor(Qt::black);
- }
- QColor ThemeManager::color(ColorToken token) const
- {
- return m_colorTokens.value(token, QColor(Qt::black));
- }
- void ThemeManager::setPrimaryColor(const QColor &color)
- {
- if (token.colorPrimary != color && color.isValid()) {
- token.colorPrimary = color;
- generateDerivedColors();
- applyTheme();
- }
- }
- void ThemeManager::toggleThemeMode()
- {
- m_themeMode = (m_themeMode == Light) ? Dark : Light;
- generateDerivedColors();
- applyTheme();
- }
- ThemeManager::ThemeMode ThemeManager::themeMode() const
- {
- return m_themeMode;
- }
- void ThemeManager::setThemeMode(ThemeMode themeMode)
- {
- if (m_themeMode != themeMode) {
- m_themeMode = themeMode;
- generateDerivedColors();
- }
- applyTheme();
- }
- ThemeManager::SizeMode ThemeManager::sizeMode() const
- {
- return m_sizeMode;
- }
- void ThemeManager::setSizeMode(SizeMode mode)
- {
- if (m_sizeMode != mode) {
- m_sizeMode = mode;
- applyTheme();
- }
- }
- void ThemeManager::generateDerivedColors()
- {
- m_colors.clear();
- auto generateColorPalettes = [this](const QColor baseColor) {
- if (!baseColor.isValid()) {
- return QHash<int, QColor>();
- }
- const QVector<QColor> colors = generateAntdPalette(baseColor);
- return QHash<int, QColor>{
- {1, colors[0]}, //
- {2, colors[1]}, //
- {3, colors[2]}, //
- {4, colors[3]}, //
- {5, colors[4]}, //
- {6, colors[5]}, //
- {7, colors[6]}, //
- {8, colors[4]}, //
- {9, colors[5]}, //
- {10, colors[6]}, //
- //{8: colors[7]},
- //{9: colors[8]},
- //{10: colors[9]};
- };
- };
- QString themeKey = (m_themeMode == Light) ? "light" : "dark";
- QJsonObject themeColors = m_colorConfig.value(themeKey).toObject();
- // 加载基础颜色
- for (auto it = themeColors.begin(); it != themeColors.end(); ++it) {
- QColor color(it.value().toString());
- if (color.isValid()) {
- m_colors[it.key()] = color;
- }
- }
- // 创建 类似 antd 的颜色配置
- const auto primaryColors = generateColorPalettes(token.colorPrimary);
- const auto successColors = generateColorPalettes(token.colorSuccess);
- const auto warningColors = generateColorPalettes(token.colorWarning);
- const auto errorColors = generateColorPalettes(token.colorError);
- const auto infoColors = generateColorPalettes(token.colorInfo);
- generateNeutralColorPalettes(token.colorBgBase, token.colorTextBase);
- // Color Link
- auto colorLink = token.colorLink;
- if (!token.colorLink.isValid()) {
- colorLink = token.colorInfo;
- }
- const auto linkColors = generateColorPalettes(colorLink);
- const auto colorErrorBgFilledHover = mixColor(errorColors[1], errorColors[3], 50);
- m_colorTokens[ColorToken::colorPrimaryBg] = primaryColors[1];
- m_colorTokens[ColorToken::colorPrimaryBgHover] = primaryColors[2];
- m_colorTokens[ColorToken::colorPrimaryBorder] = primaryColors[3];
- m_colorTokens[ColorToken::colorPrimaryBorderHover] = primaryColors[4];
- m_colorTokens[ColorToken::colorPrimaryHover] = primaryColors[5];
- m_colorTokens[ColorToken::colorPrimary] = primaryColors[6];
- m_colorTokens[ColorToken::colorPrimaryActive] = primaryColors[7];
- m_colorTokens[ColorToken::colorPrimaryTextHover] = primaryColors[8];
- m_colorTokens[ColorToken::colorPrimaryText] = primaryColors[9];
- m_colorTokens[ColorToken::colorPrimaryTextActive] = primaryColors[10];
- m_colorTokens[ColorToken::colorSuccessBg] = successColors[1];
- m_colorTokens[ColorToken::colorSuccessBgHover] = successColors[2];
- m_colorTokens[ColorToken::colorSuccessBorder] = successColors[3];
- m_colorTokens[ColorToken::colorSuccessBorderHover] = successColors[4];
- m_colorTokens[ColorToken::colorSuccessHover] = successColors[4];
- m_colorTokens[ColorToken::colorSuccess] = successColors[6];
- m_colorTokens[ColorToken::colorSuccessActive] = successColors[7];
- m_colorTokens[ColorToken::colorSuccessTextHover] = successColors[8];
- m_colorTokens[ColorToken::colorSuccessText] = successColors[9];
- m_colorTokens[ColorToken::colorSuccessTextActive] = successColors[10];
- m_colorTokens[ColorToken::colorErrorBg] = errorColors[1];
- m_colorTokens[ColorToken::colorErrorBgHover] = errorColors[2];
- m_colorTokens[ColorToken::colorErrorBgFilledHover] = colorErrorBgFilledHover;
- m_colorTokens[ColorToken::colorErrorBgActive] = errorColors[3];
- m_colorTokens[ColorToken::colorErrorBorder] = errorColors[3];
- m_colorTokens[ColorToken::colorErrorBorderHover] = errorColors[4];
- m_colorTokens[ColorToken::colorErrorHover] = errorColors[5];
- m_colorTokens[ColorToken::colorError] = errorColors[6];
- m_colorTokens[ColorToken::colorErrorActive] = errorColors[7];
- m_colorTokens[ColorToken::colorErrorTextHover] = errorColors[8];
- m_colorTokens[ColorToken::colorErrorText] = errorColors[9];
- m_colorTokens[ColorToken::colorErrorTextActive] = errorColors[10];
- m_colorTokens[ColorToken::colorWarningBg] = warningColors[1];
- m_colorTokens[ColorToken::colorWarningBgHover] = warningColors[2];
- m_colorTokens[ColorToken::colorWarningBorder] = warningColors[3];
- m_colorTokens[ColorToken::colorWarningBorderHover] = warningColors[4];
- m_colorTokens[ColorToken::colorWarningHover] = warningColors[4];
- m_colorTokens[ColorToken::colorWarning] = warningColors[6];
- m_colorTokens[ColorToken::colorWarningActive] = warningColors[7];
- m_colorTokens[ColorToken::colorWarningTextHover] = warningColors[8];
- m_colorTokens[ColorToken::colorWarningText] = warningColors[9];
- m_colorTokens[ColorToken::colorWarningTextActive] = warningColors[10];
- m_colorTokens[ColorToken::colorInfoBg] = infoColors[1];
- m_colorTokens[ColorToken::colorInfoBgHover] = infoColors[2];
- m_colorTokens[ColorToken::colorInfoBorder] = infoColors[3];
- m_colorTokens[ColorToken::colorInfoBorderHover] = infoColors[4];
- m_colorTokens[ColorToken::colorInfoHover] = infoColors[4];
- m_colorTokens[ColorToken::colorInfo] = infoColors[6];
- m_colorTokens[ColorToken::colorInfoActive] = infoColors[7];
- m_colorTokens[ColorToken::colorInfoTextHover] = infoColors[8];
- m_colorTokens[ColorToken::colorInfoText] = infoColors[9];
- m_colorTokens[ColorToken::colorInfoTextActive] = infoColors[10];
- m_colorTokens[ColorToken::colorLinkHover] = linkColors[4];
- m_colorTokens[ColorToken::colorLink] = linkColors[6];
- m_colorTokens[ColorToken::colorLinkActive] = linkColors[7];
- m_colorTokens[ColorToken::colorWhite] = "#fff";
- // init m_color
- QMetaEnum metaEnum = QMetaEnum::fromType<ColorToken>();
- for (auto it = m_colorTokens.constBegin(); it != m_colorTokens.constEnd(); ++it) {
- const char *enumKey = metaEnum.valueToKey(static_cast<int>(it.key()));
- if (enumKey) {
- m_colors.insert(QString(enumKey), it.value());
- } else {
- qWarning() << "Invalid ColorToken value:" << static_cast<int>(it.key());
- }
- }
- }
- QString ThemeManager::loadQssTemplate() const
- {
- return QString::fromUtf8(defaultQss);
- }
- QString ThemeManager::processQss(const QString &qss) const
- {
- QString processed = qss;
- // 第一步:替换尺寸变量(无依赖关系)
- QString sizeKey;
- switch (m_sizeMode) {
- case Small:
- sizeKey = "small";
- break;
- case Medium:
- sizeKey = "medium";
- break;
- case Large:
- sizeKey = "large";
- break;
- }
- QJsonObject sizeValues = m_sizeConfig.value(sizeKey).toObject();
- for (auto it = sizeValues.begin(); it != sizeValues.end(); ++it) {
- processed.replace("@" + it.key(), it.value().toString());
- }
- // 第二步:使用正则表达式替换颜色变量(处理依赖关系)
- static const QRegularExpression varRegex("@([a-zA-Z0-9_]+)");
- QRegularExpressionMatchIterator it = varRegex.globalMatch(processed);
- QSet<QString> replacedVars;
- while (it.hasNext()) {
- QRegularExpressionMatch match = it.next();
- QString varName = match.captured(1);
- if (replacedVars.contains(varName))
- continue;
- if (m_colors.contains(varName)) {
- QColor color = m_colors[varName];
- QString colorStr = color.alpha() == 255 ? color.name()
- : QString("rgba(%1, %2, %3, %4)")
- .arg(color.red())
- .arg(color.green())
- .arg(color.blue())
- .arg(color.alphaF());
- // 使用单词边界确保精确匹配
- processed.replace(QRegularExpression(QString("@%1\\b").arg(varName)), colorStr);
- replacedVars.insert(varName);
- }
- }
- return processed;
- }
- QVector<QColor> ThemeManager::generateAntdPalette(const QColor &baseColor) const
- {
- QVector<QColor> palette;
- QColor base = baseColor.toHsv();
- qreal h, s, v;
- base.getHsvF(&h, &s, &v);
- h = qRound(h * 360);
- auto getHue = [](qreal hsv_h, int i, bool light) -> qreal {
- qreal hue;
- if (qRound(hsv_h) >= 60 && qRound(hsv_h) <= 240) {
- hue = light ? qRound(hsv_h) - hueStep * i : qRound(hsv_h) + hueStep * i;
- } else {
- hue = light ? qRound(hsv_h) + hueStep * i : qRound(hsv_h) - hueStep * i;
- }
- return std::fmod(hue + 360, 360);
- };
- auto getSaturation = [](qreal hsv_s, int i, bool light) -> qreal {
- // 灰色不改变饱和度
- if (qFuzzyIsNull(hsv_s)) {
- return hsv_s;
- }
- qreal saturation;
- if (light) {
- saturation = hsv_s - saturationStep * i;
- } else if (i == darkColorCount) {
- saturation = hsv_s + saturationStep;
- } else {
- saturation = hsv_s + saturationStep2 * i;
- }
- // 边界值修正
- if (saturation > 1) {
- saturation = 1;
- }
- // 第一格的 s 限制在 0.06-0.1 之间
- if (light && i == lightColorCount && saturation > 0.1) {
- saturation = 0.1;
- }
- if (saturation < 0.06) {
- saturation = 0.06;
- }
- return saturation;
- };
- auto getValue = [](qreal hsv_v, int i, bool light) -> qreal {
- qreal value;
- if (light) {
- value = hsv_v + brightnessStep1 * i;
- } else {
- value = hsv_v - brightnessStep2 * i;
- }
- return qBound(0.0, value, 1.0);
- };
- // 生成浅色系
- for (int i = lightColorCount; i > 0; --i) {
- qreal newH = getHue(h, i, true);
- qreal newS = getSaturation(s, i, true);
- qreal newV = getValue(v, i, true);
- palette.append(QColor::fromHsvF(newH / 360.0, newS, newV));
- }
- // 添加主色
- palette.append(baseColor);
- // 生成深色系
- for (int i = 1; i <= darkColorCount; ++i) {
- qreal newH = getHue(h, i, false);
- qreal newS = getSaturation(s, i, false);
- qreal newV = getValue(v, i, false);
- palette.append(QColor::fromHsvF(newH / 360.0, newS, newV));
- }
- // 暗色主题处理
- if (m_themeMode == Dark) {
- return applyDarkMap(palette);
- }
- return palette;
- }
- QVector<QColor> ThemeManager::applyDarkMap(const QVector<QColor> &palette,
- const QColor &backgroundColor) const
- {
- QVector<QColor> darkPalette;
- QColor bgColor = backgroundColor;
- if (!bgColor.isValid()) {
- bgColor = QColor("#141414");
- }
- for (int i = 0; i < palette.size(); ++i) {
- darkPalette.append(mixColor(bgColor, palette[darkColorMap[i]], darkMixRatios[i]));
- }
- return darkPalette;
- }
- void ThemeManager::generateNeutralColorPalettes(const QColor &baseColor, const QColor &textBaseColor)
- {
- QColor colorBgBase = baseColor;
- if (!colorBgBase.isValid()) {
- if (m_themeMode == Light) {
- colorBgBase = QColor("#FFFFFFFF");
- } else {
- colorBgBase = QColor("#000");
- }
- }
- QColor colorTextBase = textBaseColor;
- if (!colorTextBase.isValid()) {
- if (m_themeMode == Light) {
- colorTextBase = QColor("#000");
- } else {
- colorTextBase = QColor("#FFFFFFFF");
- }
- }
- m_colorTokens[ColorToken::colorBgBase] = colorBgBase;
- m_colorTokens[ColorToken::colorTextBase] = colorTextBase;
- auto getAlphaColor = [](const QColor &baseColor, qreal alpha) {
- QColor result = baseColor;
- result.setAlphaF(alpha);
- return result;
- };
- auto getSolidColor = [this](const QColor &baseColor, int amount) {
- // if (m_themeMode == Dark) {
- // return baseColor.darker(amount);
- // } else {
- // return baseColor.lighter(amount);
- // }
- QColor hsl = baseColor.toHsl();
- qreal h = hsl.hslHueF(); // 0.0 <= hueF < 360.0
- qreal s = hsl.hslSaturationF();
- qreal l = hsl.lightnessF();
- if (m_themeMode == Dark) {
- l = l + amount / 100.0;
- if (l > 1) {
- l = 1;
- }
- } else {
- l = l - amount / 100.0;
- if (l < 0) {
- l = 0;
- }
- }
- return QColor::fromHslF(h, s, l, baseColor.alphaF());
- };
- if (m_themeMode == Dark) {
- m_colorTokens[ColorToken::colorText] = getAlphaColor(colorTextBase, 0.85);
- m_colorTokens[ColorToken::colorTextSecondary] = getAlphaColor(colorTextBase, 0.65);
- m_colorTokens[ColorToken::colorTextTertiary] = getAlphaColor(colorTextBase, 0.45);
- m_colorTokens[ColorToken::colorTextQuaternary] = getAlphaColor(colorTextBase, 0.25);
- m_colorTokens[ColorToken::colorFill] = getAlphaColor(colorTextBase, 0.18);
- m_colorTokens[ColorToken::colorFillSecondary] = getAlphaColor(colorTextBase, 0.12);
- m_colorTokens[ColorToken::colorFillTertiary] = getAlphaColor(colorTextBase, 0.08);
- m_colorTokens[ColorToken::colorFillQuaternary] = getAlphaColor(colorTextBase, 0.04);
- m_colorTokens[ColorToken::colorBgSolid] = getAlphaColor(colorTextBase, 0.95);
- m_colorTokens[ColorToken::colorBgSolidHover] = getAlphaColor(colorTextBase, 1);
- m_colorTokens[ColorToken::colorBgSolidActive] = getAlphaColor(colorTextBase, 0.9);
- m_colorTokens[ColorToken::colorBgElevated] = getSolidColor(colorBgBase, 12);
- m_colorTokens[ColorToken::colorBgContainer] = getSolidColor(colorBgBase, 8);
- m_colorTokens[ColorToken::colorBgLayout] = getSolidColor(colorBgBase, 0);
- m_colorTokens[ColorToken::colorBgSpotlight] = getSolidColor(colorBgBase, 26);
- m_colorTokens[ColorToken::colorBgBlur] = getAlphaColor(colorTextBase, 0.04);
- m_colorTokens[ColorToken::colorBorder] = getSolidColor(colorBgBase, 26);
- m_colorTokens[ColorToken::colorBorderSecondary] = getSolidColor(colorBgBase, 19);
- } else {
- m_colorTokens[ColorToken::colorText] = getAlphaColor(colorTextBase, 0.88);
- m_colorTokens[ColorToken::colorTextSecondary] = getAlphaColor(colorTextBase, 0.65);
- m_colorTokens[ColorToken::colorTextTertiary] = getAlphaColor(colorTextBase, 0.45);
- m_colorTokens[ColorToken::colorTextQuaternary] = getAlphaColor(colorTextBase, 0.25);
- m_colorTokens[ColorToken::colorFill] = getAlphaColor(colorTextBase, 0.15);
- m_colorTokens[ColorToken::colorFillSecondary] = getAlphaColor(colorTextBase, 0.06);
- m_colorTokens[ColorToken::colorFillTertiary] = getAlphaColor(colorTextBase, 0.04);
- m_colorTokens[ColorToken::colorFillQuaternary] = getAlphaColor(colorTextBase, 0.02);
- m_colorTokens[ColorToken::colorBgSolid] = getAlphaColor(colorTextBase, 1);
- m_colorTokens[ColorToken::colorBgSolidHover] = getAlphaColor(colorTextBase, 0.75);
- m_colorTokens[ColorToken::colorBgSolidActive] = getAlphaColor(colorTextBase, 0.95);
- m_colorTokens[ColorToken::colorBgLayout] = getSolidColor(colorBgBase, 4);
- m_colorTokens[ColorToken::colorBgContainer] = getSolidColor(colorBgBase, 0);
- m_colorTokens[ColorToken::colorBgElevated] = getSolidColor(colorBgBase, 0);
- m_colorTokens[ColorToken::colorBgSpotlight] = getAlphaColor(colorTextBase, 0.85);
- m_colorTokens[ColorToken::colorBgBlur] = "transparent";
- m_colorTokens[ColorToken::colorBorder] = getSolidColor(colorBgBase, 15);
- m_colorTokens[ColorToken::colorBorderSecondary] = getSolidColor(colorBgBase, 6);
- }
- }
- QColor ThemeManager::mixColor(const QColor &base, const QColor &target, int ratio) const
- {
- const qreal p = ratio / 100.0;
- qreal r = (base.red() - target.red()) * p + target.red();
- qreal g = (base.green() - target.green()) * p + target.green();
- qreal b = (base.blue() - target.blue()) * p + target.blue();
- return QColor(r, g, b);
- }
- QMap<ThemeManager::ControlHeightToken, int> ThemeManager::genControlHeight(const SeedTokens &token)
- {
- const int controlHeight = token.controlHeight;
- return {
- {controlHeightSM, controlHeight * 0.75},
- {controlHeightXS, controlHeight * 0.5},
- {controlHeightLG, controlHeight * 1.25},
- };
- }
- QMap<ThemeManager::SizeToken, int> ThemeManager::genSizeMapToken(const SeedTokens &token)
- {
- const int sizeUnit = token.sizeUnit;
- const int sizeStep = token.sizeStep;
- const int compactSizeStep = sizeStep - 2;
- return {
- {SizeXXL, sizeUnit * (compactSizeStep + 10)},
- {SizeXL, sizeUnit * (compactSizeStep + 6)},
- {SizeLG, sizeUnit * (compactSizeStep + 2)},
- {SizeMD, sizeUnit * (compactSizeStep + 2)},
- {SizeMS, sizeUnit * (compactSizeStep + 1)},
- {size, sizeUnit * compactSizeStep},
- {SizeSM, sizeUnit * compactSizeStep},
- {SizeXS, sizeUnit * (compactSizeStep - 1)},
- {SizeXXS, sizeUnit * (compactSizeStep - 1)},
- };
- }
|