From e89f4400eb36209dedc4d218806da661df4c4e34 Mon Sep 17 00:00:00 2001 From: Cyano Hao Date: Mon, 3 Jul 2023 14:06:26 +0800 Subject: [PATCH] Uniform look for Red Panda C++ under KDE/DDE (#119) * KDE theme: fix visual problems with KDE dark mode; add system theme * Make "Light" theme truly light under Breeze Dark theme. * With this fix also expose dark mode support on Windows. * Add "Auto" (system) theme that follows system style and color. * Add "Adaptive" color scheme for system theme (using transparent background). * Add support for transparent background in color schemes. * move `alphaBlend` to utils * hide Auto (system) theme on Windows --- RedPandaIDE/RedPandaIDE.pro | 4 + RedPandaIDE/colorschemes/Adaptive.scheme | 110 ++++++++++++++++++ RedPandaIDE/editor.cpp | 4 +- RedPandaIDE/main.cpp | 15 +++ RedPandaIDE/mainwindow.cpp | 15 ++- RedPandaIDE/thememanager.cpp | 6 + RedPandaIDE/thememanager.h | 2 + RedPandaIDE/themes/contrast.json | 3 +- RedPandaIDE/themes/dark.json | 3 +- RedPandaIDE/themes/default.json | 43 +++++-- RedPandaIDE/themes/system.json | 9 ++ RedPandaIDE/translations/RedPandaIDE_pt_BR.ts | 4 + RedPandaIDE/translations/RedPandaIDE_zh_CN.ts | 5 + RedPandaIDE/translations/RedPandaIDE_zh_TW.ts | 4 + RedPandaIDE/utils.cpp | 10 ++ RedPandaIDE/utils.h | 1 + RedPandaIDE/widgets/choosethemedialog.cpp | 10 +- RedPandaIDE/widgets/choosethemedialog.h | 5 +- RedPandaIDE/widgets/choosethemedialog.ui | 41 ++++--- 19 files changed, 258 insertions(+), 36 deletions(-) create mode 100644 RedPandaIDE/colorschemes/Adaptive.scheme create mode 100644 RedPandaIDE/themes/system.json diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 004ff25c..be0463fa 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -530,6 +530,10 @@ iconsets_files.files += $$files(resources/iconsets/*.json, true) theme_files.files += $$files(themes/*.json, false) theme_files.files += $$files(themes/*.png, false) +windows: { + theme_files.files -= themes/system.json +} + colorscheme_files.files += $$files(colorschemes/*.scheme, false) colorscheme_files.prefix = /colorschemes diff --git a/RedPandaIDE/colorschemes/Adaptive.scheme b/RedPandaIDE/colorschemes/Adaptive.scheme new file mode 100644 index 00000000..4af40527 --- /dev/null +++ b/RedPandaIDE/colorschemes/Adaptive.scheme @@ -0,0 +1,110 @@ +{ + "Character" : { + "foreground" : "#ce543b" + }, + "Class" : { + "foreground" : "#267f99" + }, + "Comment" : { + "foreground" : "#3b9827" + }, + "Escape sequences" : { + "foreground" : "#e28346" + }, + "Float" : { + "foreground" : "#4bc854" + }, + "Function" : { + "foreground" : "#c4b65f" + }, + "Global variable" : { + "foreground" : "#2381fe" + }, + "Hexadecimal" : { + "foreground" : "#4bc854" + }, + "Identifier" : { + "foreground" : "#ce543b" + }, + "Illegal Char" : { + "foreground" : "#e63b3b" + }, + "Local Variable" : { + "foreground" : "#2381fe" + }, + "Number" : { + "foreground" : "#4bc854" + }, + "Octal" : { + "foreground" : "#4bc854" + }, + "Preprocessor" : { + "foreground" : "#cf46d5" + }, + "Reserve Word for Types": { + "foreground": "#336be5" + }, + "Reserved Word" : { + "foreground" : "#cf46d5" + }, + "Space" : { + "foreground" : "#40808080" + }, + "String" : { + "foreground" : "#ce543b" + }, + "Symbol" : { + "foreground" : "#e0808080" + }, + "Variable" : { + "foreground" : "#2381fe" + }, + "Editor Text": { + "foreground" : "#808080", + "background" : "#00000000" + }, + "Current Highlighted Word": { + "background": "#20808080" + }, + "Selected text" : { + "background" : "#3c55aaff" + }, + "Gutter" : { + "foreground" : "#c0808080", + "background" : "#20808080" + }, + "Gutter Active Line" : { + "foreground" : "#808080" + }, + "Error" : { + "foreground" : "#f52a22" + }, + "Active Breakpoint" : { + "foreground" : "#FFFFCE", + "background" : "#00376F" + }, + "Fold Line" : { + "foreground" : "#808080" + }, + "Active Line" : { + "background" : "#10808080" + }, + "Warning" : { + "foreground" : "#c69901" + }, + "Indent Guide Line" : { + "foreground" : "#80808080" + }, + "brace/parenthesis/bracket level 1" : { + "foreground" : "#569CD6" + }, + "brace/parenthesis/bracket level 2" : { + "foreground" : "#E080C0" + }, + "brace/parenthesis/bracket level 3" : { + "foreground" : "#D69D85" + }, + "brace/parenthesis/bracket level 4" : { + "foreground" : "#4EC9B0" + } +} diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 6fc46845..5ed31232 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -5307,7 +5307,7 @@ void Editor::applyColorScheme(const QString& schemeName) item = pColorManager->getItem(schemeName,COLOR_SCHEME_GUTTER); if (item) { gutter().setTextColor(item->foreground()); - gutter().setColor(item->background()); + gutter().setColor(alphaBlend(palette().color(QPalette::Base), item->background())); } item = pColorManager->getItem(schemeName,COLOR_SCHEME_GUTTER_ACTIVE_LINE); if (item) { @@ -5350,7 +5350,7 @@ void Editor::applyColorScheme(const QString& schemeName) item = pColorManager->getItem(schemeName,COLOR_SCHEME_TEXT); if (item) { this->setForegroundColor(item->foreground()); - this->setBackgroundColor(item->background()); + this->setBackgroundColor(alphaBlend(palette().color(QPalette::Base), item->background())); } else { this->setForegroundColor(palette().color(QPalette::Text)); this->setBackgroundColor(palette().color(QPalette::Base)); diff --git a/RedPandaIDE/main.cpp b/RedPandaIDE/main.cpp index 72a03fd8..ebe716a3 100644 --- a/RedPandaIDE/main.cpp +++ b/RedPandaIDE/main.cpp @@ -243,6 +243,11 @@ void setTheme(const QString& theme) { int main(int argc, char *argv[]) { +#ifdef Q_OS_WINDOWS + // Make title bar and palette follow system-wide dark mode setting on recent Windows releases. + qputenv("QT_QPA_PLATFORM", "windows:darkmode=2"); +#endif + QApplication app(argc, argv); app.setAttribute(Qt::AA_UseHighDpiPixmaps); @@ -337,11 +342,21 @@ int main(int argc, char *argv[]) if (firstRun) { //set theme ChooseThemeDialog themeDialog; +#ifdef Q_OS_WINDOWS + // Qt's default style on Windows is not good. + themeDialog.hideAutoFollowSystemTheme(); +#endif themeDialog.exec(); switch (themeDialog.theme()) { + case ChooseThemeDialog::Theme::AutoFollowSystem: + setTheme("system"); + break; case ChooseThemeDialog::Theme::Dark: setTheme("dark"); break; + case ChooseThemeDialog::Theme::Light: + setTheme("default"); + break; default: setTheme("default"); } diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index c9303b4a..b578e13e 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -867,10 +868,15 @@ void MainWindow::applySettings() themeManager.setUseCustomTheme(pSettings->environment().useCustomTheme()); try { PAppTheme appTheme = themeManager.theme(pSettings->environment().theme()); - if (appTheme->isDark()) - QApplication::setStyle(new DarkFusionStyle());//app takes the onwership - else - QApplication::setStyle(new LightFusionStyle());//app takes the onwership + if (appTheme->useQtFusionStyle()) { + if (appTheme->isDark()) + QApplication::setStyle(new DarkFusionStyle());//app takes the onwership + else + QApplication::setStyle(new LightFusionStyle());//app takes the onwership + } else { + QString systemStyle = QStyleFactory::keys()[0]; // Breeze for KDE, etc. + QApplication::setStyle(systemStyle); + } qApp->setPalette(appTheme->palette()); //fix for qstatusbar bug mFileEncodingStatus->setPalette(appTheme->palette()); @@ -1715,6 +1721,7 @@ void MainWindow::updateActionIcons() ui->toolbarCode->setIconSize(iconSize); ui->toolbarCompile->setIconSize(iconSize); ui->toolbarDebug->setIconSize(iconSize); + ui->toolbarCompilerSet->setIconSize(iconSize); for (QToolButton* btn: mClassBrowserToolbar->findChildren()) { btn->setIconSize(iconSize); } diff --git a/RedPandaIDE/thememanager.cpp b/RedPandaIDE/thememanager.cpp index 6a918483..f757d6f9 100644 --- a/RedPandaIDE/thememanager.cpp +++ b/RedPandaIDE/thememanager.cpp @@ -194,6 +194,7 @@ void AppTheme::load(const QString &filename) QString localeName = obj["name_"+pSettings->environment().language()].toString(); if (!localeName.isEmpty()) mDisplayName = localeName; + mUseQtFusionStyle = obj["useQtFusionStyle"].toBool(true); mIsDark = obj["isDark"].toBool(false); mDefaultColorScheme = obj["default scheme"].toString(); mDefaultIconSet = obj["default iconset"].toString(); @@ -268,6 +269,11 @@ void AppTheme::setDefaultColorScheme(const QString &newDefaultColorScheme) mDefaultColorScheme = newDefaultColorScheme; } +bool AppTheme::useQtFusionStyle() const +{ + return mUseQtFusionStyle; +} + bool AppTheme::isDark() const { return mIsDark; diff --git a/RedPandaIDE/thememanager.h b/RedPandaIDE/thememanager.h index 2f35934f..d5bfd540 100644 --- a/RedPandaIDE/thememanager.h +++ b/RedPandaIDE/thememanager.h @@ -80,6 +80,7 @@ public: void load(const QString& filename); + bool useQtFusionStyle() const; bool isDark() const; const QString &defaultColorScheme() const; @@ -98,6 +99,7 @@ private: QHash mColors; QString mName; QString mDisplayName; + bool mUseQtFusionStyle; bool mIsDark; QString mDefaultColorScheme; QString mDefaultIconSet; diff --git a/RedPandaIDE/themes/contrast.json b/RedPandaIDE/themes/contrast.json index 0677c41c..5dade68e 100644 --- a/RedPandaIDE/themes/contrast.json +++ b/RedPandaIDE/themes/contrast.json @@ -1,6 +1,7 @@ { - "name":"contrast", + "name":"Contract", "name_zh_CN": "高对比度主题", + "useQtFusionStyle": true, "isDark": true, "default scheme": "Twilight", "default iconset": "contrast", diff --git a/RedPandaIDE/themes/dark.json b/RedPandaIDE/themes/dark.json index 08bebc6c..7cec4959 100644 --- a/RedPandaIDE/themes/dark.json +++ b/RedPandaIDE/themes/dark.json @@ -1,6 +1,7 @@ { - "name":"dark", + "name":"Dark", "name_zh_CN": "深色主题", + "useQtFusionStyle": true, "isDark": true, "default scheme": "VS Code", "default iconset": "contrast", diff --git a/RedPandaIDE/themes/default.json b/RedPandaIDE/themes/default.json index 80915681..278eaf75 100644 --- a/RedPandaIDE/themes/default.json +++ b/RedPandaIDE/themes/default.json @@ -1,11 +1,36 @@ { - "name":"light", - "name_zh_CN":"浅色主题", - "isDark":false, - "default scheme": "Intellij Classic", - "default iconset": "newlook", - "palette": { - "PaletteHighlight":"#ffdddddd", - "PaletteHighlightedText":"#ff000000" - } + "name":"Light", + "name_zh_CN": "浅色主题", + "useQtFusionStyle": true, + "isDark": false, + "default scheme": "Intellij Classic", + "default iconset": "newlook", + "palette": { + "PaletteWindow":"#efefef", + "PaletteWindowText":"#000000", + "PaletteBase":"#ffffff", + "PaletteAlternateBase":"#f7f7f7", + "PaletteToolTipBase":"#ffffdc", + "PaletteToolTipText":"#000000", + "PaletteText":"#000000", + "PaletteButton": "#efefef", + "PaletteButtonText":"#000000", + "PaletteBrightText": "#ffffff", + "PaletteHighlight":"#308cc6", + "PaletteHighlightedText":"#ffffff", + "PaletteLink":"#0000ff", + "PaletteLinkVisited":"#ff00ff", + "PaletteLight": "#ffffff", + "PaletteMidLight": "#cacaca", + "PaletteDark":"#9f9f9f", + "PaletteMid": "#b8b8b8", + "PaletteWindowDisabled":"#efefef", + "PaletteWindowTextDisabled":"#bebebe", + "PaletteBaseDisabled":"#efefef", + "PaletteTextDisabled":"#bebebe", + "PaletteButtonDisabled": "#efefef", + "PaletteButtonTextDisabled":"#bebebe", + "PaletteHighlightDisabled":"#919191", + "PaletteHighlightedTextDisabled":"#ffffff" + } } diff --git a/RedPandaIDE/themes/system.json b/RedPandaIDE/themes/system.json new file mode 100644 index 00000000..7153b541 --- /dev/null +++ b/RedPandaIDE/themes/system.json @@ -0,0 +1,9 @@ +{ + "name":"Auto (follow system style and color)", + "name_zh_CN":"自动(跟随系统样式和颜色)", + "useQtFusionStyle": false, + "isDark": false, + "default scheme": "Adaptive", + "default iconset": "newlook", + "palette": {} +} diff --git a/RedPandaIDE/translations/RedPandaIDE_pt_BR.ts b/RedPandaIDE/translations/RedPandaIDE_pt_BR.ts index 3574a52d..cfe5c51c 100644 --- a/RedPandaIDE/translations/RedPandaIDE_pt_BR.ts +++ b/RedPandaIDE/translations/RedPandaIDE_pt_BR.ts @@ -307,6 +307,10 @@ C++ + + Auto (follow system style and color) + + CodeSnippetsManager diff --git a/RedPandaIDE/translations/RedPandaIDE_zh_CN.ts b/RedPandaIDE/translations/RedPandaIDE_zh_CN.ts index 330946d9..e9cd76a1 100644 --- a/RedPandaIDE/translations/RedPandaIDE_zh_CN.ts +++ b/RedPandaIDE/translations/RedPandaIDE_zh_CN.ts @@ -409,6 +409,11 @@ p, li { white-space: pre-wrap; } Light Theme 浅色主题 + + + Auto (follow system style and color) + 自动(跟随系统样式和颜色) + Default Language: diff --git a/RedPandaIDE/translations/RedPandaIDE_zh_TW.ts b/RedPandaIDE/translations/RedPandaIDE_zh_TW.ts index 6e300caf..b879f8e6 100644 --- a/RedPandaIDE/translations/RedPandaIDE_zh_TW.ts +++ b/RedPandaIDE/translations/RedPandaIDE_zh_TW.ts @@ -216,6 +216,10 @@ C++ + + Auto (follow system style and color) + + CodeSnippetsManager diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index 97ddd23f..83ff9f25 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -579,3 +579,13 @@ void openFileFolderInExplorer(const QString &path) } } + +QColor alphaBlend(const QColor &lower, const QColor &upper) { + qreal wu = upper.alphaF(); // weight of upper color + qreal wl = 1 - wu; // weight of lower color + return QColor( + int(lower.red() * wl + upper.red() * wu), + int(lower.green() * wl + upper.green() * wu), + int(lower.blue() * wl + upper.blue() * wu) + ); +} diff --git a/RedPandaIDE/utils.h b/RedPandaIDE/utils.h index 5218fa79..e9667b30 100644 --- a/RedPandaIDE/utils.h +++ b/RedPandaIDE/utils.h @@ -156,5 +156,6 @@ QString getSizeString(int size); class QComboBox; void saveComboHistory(QComboBox* cb,const QString& text); +QColor alphaBlend(const QColor &lower, const QColor &upper); #endif // UTILS_H diff --git a/RedPandaIDE/widgets/choosethemedialog.cpp b/RedPandaIDE/widgets/choosethemedialog.cpp index 18d193f0..ea1135ce 100644 --- a/RedPandaIDE/widgets/choosethemedialog.cpp +++ b/RedPandaIDE/widgets/choosethemedialog.cpp @@ -33,9 +33,13 @@ ChooseThemeDialog::~ChooseThemeDialog() ChooseThemeDialog::Theme ChooseThemeDialog::theme() { + if (ui->rbAuto->isChecked()) + return Theme::AutoFollowSystem; if (ui->rbDark->isChecked()) return Theme::Dark; - return Theme::Light; + if (ui->rbLight->isChecked()) + return Theme::Light; + return Theme::Unknown; } ChooseThemeDialog::Language ChooseThemeDialog::language() @@ -48,3 +52,7 @@ void ChooseThemeDialog::on_btnOk_clicked() accept(); } +void ChooseThemeDialog::hideAutoFollowSystemTheme() +{ + ui->rbAuto->hide(); +} diff --git a/RedPandaIDE/widgets/choosethemedialog.h b/RedPandaIDE/widgets/choosethemedialog.h index df88ca17..36ee2131 100644 --- a/RedPandaIDE/widgets/choosethemedialog.h +++ b/RedPandaIDE/widgets/choosethemedialog.h @@ -29,8 +29,10 @@ class ChooseThemeDialog : public QDialog public: enum class Theme { + Unknown = -1, + AutoFollowSystem = 0, Dark, - Light + Light, }; enum class Language { C, @@ -41,6 +43,7 @@ public: ~ChooseThemeDialog(); Theme theme(); Language language(); + void hideAutoFollowSystemTheme(); private slots: void on_btnOk_clicked(); diff --git a/RedPandaIDE/widgets/choosethemedialog.ui b/RedPandaIDE/widgets/choosethemedialog.ui index 7e8c86de..072596a1 100644 --- a/RedPandaIDE/widgets/choosethemedialog.ui +++ b/RedPandaIDE/widgets/choosethemedialog.ui @@ -20,14 +20,23 @@ Choose Theme - - + + + + QFrame::Box + + + QFrame::Sunken + - Dark Theme + + + + :/demos/light.png - + QFrame::Box @@ -43,26 +52,24 @@ - + + + + Dark Theme + + + + Light Theme - - - - QFrame::Box - - - QFrame::Sunken - + + - - - - :/demos/light.png + Auto (follow system style and color)