From a796644cde3be43b245879b6c8958cad8d077c81 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Fri, 1 Nov 2024 23:35:49 -0600 Subject: [PATCH 01/10] Add theming preferences --- app/src/generalpage.cpp | 30 ++++++ app/src/generalpage.h | 2 + app/src/pencil2d.cpp | 57 ++++++++++- app/src/pencil2d.h | 4 + app/ui/generalpage.ui | 62 +++++++++++- core_lib/core_lib.pro | 2 + core_lib/data/core_lib.qrc | 4 + core_lib/data/theme_palettes/Darker.conf | 4 + core_lib/data/theme_palettes/Ia_Ora.conf | 4 + core_lib/data/theme_palettes/Rose_Pine.conf | 4 + core_lib/data/theme_palettes/Waves.conf | 4 + core_lib/src/managers/preferencemanager.cpp | 8 ++ core_lib/src/managers/thememanager.cpp | 0 core_lib/src/managers/thememanager.h | 0 core_lib/src/util/pencildef.h | 2 + core_lib/src/util/preferencesdef.h | 2 + core_lib/src/util/theming.cpp | 105 ++++++++++++++++++++ core_lib/src/util/theming.h | 20 ++++ 18 files changed, 309 insertions(+), 5 deletions(-) create mode 100644 core_lib/data/theme_palettes/Darker.conf create mode 100644 core_lib/data/theme_palettes/Ia_Ora.conf create mode 100644 core_lib/data/theme_palettes/Rose_Pine.conf create mode 100644 core_lib/data/theme_palettes/Waves.conf create mode 100644 core_lib/src/managers/thememanager.cpp create mode 100644 core_lib/src/managers/thememanager.h create mode 100644 core_lib/src/util/theming.cpp create mode 100644 core_lib/src/util/theming.h diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index 77044ca5ea..8760e83c50 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -24,6 +24,7 @@ GNU General Public License for more details. #include "pencildef.h" #include "preferencemanager.h" +#include "theming.h" #include "ui_generalpage.h" @@ -33,6 +34,17 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage) QSettings settings(PENCIL2D, PENCIL2D); + ui->styleCombo->addItem("System Default", ""); + ui->styleCombo->addItems(Theming::availableStyles()); + + ui->paletteCombo->addItem("Default", ""); + for (const QString& palette : Theming::availablePalettes()) + { + QString paletteName(palette); + paletteName.replace('_', ' '); + ui->paletteCombo->addItem(paletteName, palette); + } + QString languages [][3] { // translatable string, endonym, locale code @@ -109,6 +121,8 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage) connect(ui->languageCombo, curIndexChanged, this, &GeneralPage::languageChanged); connect(ui->windowOpacityLevel, &QSlider::valueChanged, this, &GeneralPage::windowOpacityChange); connect(ui->backgroundButtons, buttonClicked, this, &GeneralPage::backgroundChanged); + connect(ui->styleCombo, curIndexChanged, this, &GeneralPage::styleChanged); + connect(ui->paletteCombo, curIndexChanged, this, &GeneralPage::paletteChanged); connect(ui->shadowsBox, &QCheckBox::stateChanged, this, &GeneralPage::shadowsCheckboxStateChanged); connect(ui->toolCursorsBox, &QCheckBox::stateChanged, this, &GeneralPage::toolCursorsCheckboxStateChanged); connect(ui->antialiasingBox, &QCheckBox::stateChanged, this, &GeneralPage::antiAliasCheckboxStateChanged); @@ -150,6 +164,12 @@ void GeneralPage::updateValues() ui->curveSmoothingLevel->setValue(mManager->getInt(SETTING::CURVE_SMOOTHING)); QSignalBlocker b2(ui->windowOpacityLevel); ui->windowOpacityLevel->setValue(100 - mManager->getInt(SETTING::WINDOW_OPACITY)); + QSignalBlocker b19(ui->styleCombo); + int styleIndex = ui->styleCombo->findText(mManager->getString(SETTING::STYLE_ID), Qt::MatchFixedString); + ui->styleCombo->setCurrentIndex(qMax(0, styleIndex)); + QSignalBlocker b20(ui->styleCombo); + int paletteIndex = ui->paletteCombo->findText(mManager->getString(SETTING::PALETTE_ID), Qt::MatchFixedString); + ui->paletteCombo->setCurrentIndex(qMax(0, paletteIndex)); QSignalBlocker b3(ui->shadowsBox); ui->shadowsBox->setChecked(mManager->isOn(SETTING::SHADOW)); QSignalBlocker b4(ui->toolCursorsBox); @@ -249,6 +269,16 @@ void GeneralPage::highResCheckboxStateChanged(int b) mManager->set(SETTING::HIGH_RESOLUTION, b != Qt::Unchecked); } +void GeneralPage::styleChanged(int index) +{ + mManager->set(SETTING::STYLE_ID, ui->styleCombo->itemText(index)); +} + +void GeneralPage::paletteChanged(int index) +{ + mManager->set(SETTING::PALETTE_ID, ui->paletteCombo->itemData(index).toString()); +} + void GeneralPage::shadowsCheckboxStateChanged(int b) { mManager->set(SETTING::SHADOW, b != Qt::Unchecked); diff --git a/app/src/generalpage.h b/app/src/generalpage.h index 2b951f7765..615a601d8d 100644 --- a/app/src/generalpage.h +++ b/app/src/generalpage.h @@ -48,6 +48,8 @@ public slots: private slots: void languageChanged(int i); + void styleChanged(int index); + void paletteChanged(int index); void shadowsCheckboxStateChanged(int b); void antiAliasCheckboxStateChanged(int b); void toolCursorsCheckboxStateChanged(int b); diff --git a/app/src/pencil2d.cpp b/app/src/pencil2d.cpp index 74e8cba94b..845905fa21 100644 --- a/app/src/pencil2d.cpp +++ b/app/src/pencil2d.cpp @@ -24,6 +24,7 @@ GNU General Public License for more details. #include #include #include +#include #include #include #include @@ -32,9 +33,11 @@ GNU General Public License for more details. #include "commandlineexporter.h" #include "commandlineparser.h" +#include "editor.h" #include "mainwindow2.h" #include "pencildef.h" #include "platformhandler.h" +#include "theming.h" #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) @@ -42,7 +45,8 @@ GNU General Public License for more details. #endif Pencil2D::Pencil2D(int& argc, char** argv) : - QApplication(argc, argv) + QApplication(argc, argv), + DEFAULT_STYLE(style()->objectName()) { // Set organization and application name setOrganizationName("Pencil2D"); @@ -134,6 +138,40 @@ bool Pencil2D::event(QEvent* event) return QApplication::event(event); } +void Pencil2D::setStyleId(const QString styleId) +{ + QPalette oldPalette = palette(); + QStyle* style = Theming::getStyle(styleId); + if (style != nullptr) + { + setStyle(style); + } + else + { + setStyle(DEFAULT_STYLE); + } + + // setStyle is supposed to overwrite the palette, so it must be reapplied + setPalette(oldPalette); + + mainWindow->update(); +} + +void Pencil2D::setPaletteId(const QString paletteId) +{ + std::unique_ptr palette(Theming::getPalette(paletteId)); + if (palette != nullptr) + { + setPalette(*palette); + } + else + { + setPalette(this->style()->standardPalette()); + } + + mainWindow->update(); +} + void Pencil2D::installTranslators() { QSettings setting(PENCIL2D, PENCIL2D); @@ -171,7 +209,24 @@ void Pencil2D::prepareGuiStartup(const QString& inputPath) PlatformHandler::configurePlatformSpecificSettings(); mainWindow.reset(new MainWindow2); + PreferenceManager* prefs = mainWindow->mEditor->preference(); + setStyleId(prefs->getString(SETTING::STYLE_ID)); + setPaletteId(prefs->getString(SETTING::PALETTE_ID)); + connect(this, &Pencil2D::openFileRequested, mainWindow.get(), &MainWindow2::openFile); + connect(prefs, &PreferenceManager::optionChanged, [=](SETTING setting) { + switch (setting) + { + case SETTING::STYLE_ID: + setStyleId(prefs->getString(SETTING::STYLE_ID)); + break; + case SETTING::PALETTE_ID: + setPaletteId(prefs->getString(SETTING::PALETTE_ID)); + break; + default: + break; + } + }); mainWindow->show(); mainWindow->openStartupFile(inputPath); diff --git a/app/src/pencil2d.h b/app/src/pencil2d.h index 4789788371..53a8f06986 100644 --- a/app/src/pencil2d.h +++ b/app/src/pencil2d.h @@ -72,6 +72,8 @@ class Pencil2D : public QApplication bool event(QEvent* event) override; + void setStyleId(const QString styleId); + void setPaletteId(const QString paletteId); signals: /** * Emitted when the operating system requests that a file should be opened. @@ -93,6 +95,8 @@ class Pencil2D : public QApplication */ void prepareGuiStartup(const QString &inputPath); + const QString DEFAULT_STYLE; + std::unique_ptr mainWindow; std::unique_ptr mProcessLock; diff --git a/app/ui/generalpage.ui b/app/ui/generalpage.ui index 1d96d9e204..da910ae6a7 100644 --- a/app/ui/generalpage.ui +++ b/app/ui/generalpage.ui @@ -26,9 +26,9 @@ 0 - -407 - 314 - 932 + 0 + 363 + 1239 @@ -88,6 +88,60 @@ Appearance + + + + + + Window style: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Color palette: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -434,7 +488,7 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + 6 diff --git a/core_lib/core_lib.pro b/core_lib/core_lib.pro index 9e0e8df982..93cd3e6eaa 100644 --- a/core_lib/core_lib.pro +++ b/core_lib/core_lib.pro @@ -105,6 +105,7 @@ HEADERS += \ src/util/pencilerror.h \ src/util/pencilsettings.h \ src/util/preferencesdef.h \ + src/util/theming.h \ src/util/transform.h \ src/util/util.h \ src/util/log.h \ @@ -186,6 +187,7 @@ SOURCES += src/graphics/bitmap/bitmapimage.cpp \ src/util/pencilerror.cpp \ src/util/pencilsettings.cpp \ src/util/log.cpp \ + src/util/theming.cpp \ src/util/transform.cpp \ src/util/util.cpp \ src/util/pointerevent.cpp \ diff --git a/core_lib/data/core_lib.qrc b/core_lib/data/core_lib.qrc index 5bc67e882b..f5673e2d19 100644 --- a/core_lib/data/core_lib.qrc +++ b/core_lib/data/core_lib.qrc @@ -1,5 +1,9 @@ resources/kb.ini + theme_palettes/Darker.conf + theme_palettes/Ia_Ora.conf + theme_palettes/Waves.conf + theme_palettes/Rose_Pine.conf diff --git a/core_lib/data/theme_palettes/Darker.conf b/core_lib/data/theme_palettes/Darker.conf new file mode 100644 index 0000000000..cf2f69f7f6 --- /dev/null +++ b/core_lib/data/theme_palettes/Darker.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffffffff, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffffffff, #ffffffff, #ffffffff, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #fff9f9f9, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff +disabled_colors=#ff808080, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ff808080, #ffffffff, #ff808080, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #ff808080, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff +inactive_colors=#ffffffff, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffffffff, #ffffffff, #ffffffff, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #fff9f9f9, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff diff --git a/core_lib/data/theme_palettes/Ia_Ora.conf b/core_lib/data/theme_palettes/Ia_Ora.conf new file mode 100644 index 0000000000..7875fc4d05 --- /dev/null +++ b/core_lib/data/theme_palettes/Ia_Ora.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ff000000, #ffeff3f7, #ffffffff, #ffe9e7e3, #ffc7cbce, #ffa0a0a4, #ff000000, #ffffffff, #ff000000, #ffeff3f7, #ffeff3f7, #ffb8bbbe, #ff4965ae, #ffffffff, #ff0000ff, #ffff00ff, #ffeff3f7, #ff000000, #ffffffdc, #ff000000, #80000000 +disabled_colors=#ff808080, #ffeff3f7, #ffffffff, #ffe9e7e3, #ffc7cbce, #ffa0a0a4, #ff808080, #ffffffff, #ff808080, #ffeff3f7, #ffeff3f7, #ffb8bbbe, #ff4965ae, #ff808080, #ff0000ff, #ffff00ff, #ffeff3f7, #ff000000, #ffffffdc, #ff000000, #80000000 +inactive_colors=#ff000000, #ffeff3f7, #ffffffff, #ffe9e7e3, #ffc7cbce, #ffa0a0a4, #ff000000, #ffffffff, #ff000000, #ffeff3f7, #ffeff3f7, #ffb8bbbe, #ff4965ae, #ffffffff, #ff0000ff, #ffff00ff, #ffeff3f7, #ff000000, #ffffffdc, #ff000000, #80000000 diff --git a/core_lib/data/theme_palettes/Rose_Pine.conf b/core_lib/data/theme_palettes/Rose_Pine.conf new file mode 100644 index 0000000000..4c557492ed --- /dev/null +++ b/core_lib/data/theme_palettes/Rose_Pine.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffe0def4, #ff26233a, #ff524f67, #ff403d52, #ff21202e, #ff26233a, #ff6e6a86, #ffeb6f92, #ffebbcba, #ff26233a, #ff191724, #ff26233a, #ff524f67, #fff6c177, #ff9ccfd8, #ffc4a7e7, #ff1a1c1e, #ff000000, #ff21202e, #ff908caa, #809e9e9e +disabled_colors=#ffebbcba, #ff1f1d2e, #ff524f67, #ff403d52, #ff21202e, #ff26233a, #ff6e6a86, #ffeb6f92, #ffebbcba, #ff26233a, #ff191724, #ff26233a, #ff403d52, #ff524f67, #ff908caa, #ff524f67, #ff1a1c1e, #ff000000, #ff21202e, #ff9ccfd8, #809e9e9e +inactive_colors=#ffe0def4, #ff26233a, #ff524f67, #ff403d52, #ff21202e, #ff26233a, #ff6e6a86, #ffeb6f92, #ffebbcba, #ff26233a, #ff191724, #ff26233a, #ff403d52, #ffebbcba, #ff31748f, #ff6e6a86, #ff1a1c1e, #ff000000, #ff21202e, #ffc4a7e7, #809e9e9e diff --git a/core_lib/data/theme_palettes/Waves.conf b/core_lib/data/theme_palettes/Waves.conf new file mode 100644 index 0000000000..e0de92fd6b --- /dev/null +++ b/core_lib/data/theme_palettes/Waves.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffb0b0b0, #ff010b2c, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffb0b0b0, #ffb0b0b0, #ffb0b0b0, #ff010b2c, #ff010b2c, #ffb0b0b0, #ff302f2e, #ffb0b0b0, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff0a0a0a, #ffffffff, #80b0b0b0 +disabled_colors=#ff808080, #ff010b2c, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ff808080, #ff808080, #ff808080, #ff00071d, #ff00071d, #ffb0b0b0, #ff00071d, #ff808080, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff0a0a0a, #ffffffff, #80b0b0b0 +inactive_colors=#ffb0b0b0, #ff010b2c, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffb0b0b0, #ffb0b0b0, #ffb0b0b0, #ff010b2c, #ff010b2c, #ffb0b0b0, #ff302f2e, #ffb0b0b0, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff0a0a0a, #ffffffff, #80b0b0b0 diff --git a/core_lib/src/managers/preferencemanager.cpp b/core_lib/src/managers/preferencemanager.cpp index 8cb247aa63..281c621051 100644 --- a/core_lib/src/managers/preferencemanager.cpp +++ b/core_lib/src/managers/preferencemanager.cpp @@ -75,6 +75,8 @@ void PreferenceManager::loadPrefs() set(SETTING::TOOL_CURSOR, settings.value(SETTING_TOOL_CURSOR, true).toBool()); set(SETTING::CANVAS_CURSOR, settings.value(SETTING_CANVAS_CURSOR, true).toBool()); set(SETTING::HIGH_RESOLUTION, settings.value(SETTING_HIGH_RESOLUTION, true).toBool()); + set(SETTING::STYLE_ID, settings.value(SETTING_STYLE_ID, "").toString()); + set(SETTING::PALETTE_ID, settings.value(SETTING_PALETTE_ID, "").toString()); set(SETTING::SHADOW, settings.value(SETTING_SHADOW, false).toBool()); set(SETTING::QUICK_SIZING, settings.value(SETTING_QUICK_SIZING, true).toBool()); set(SETTING::SHOW_SELECTION_INFO, settings.value(SETTING_SHOW_SELECTION_INFO, false).toBool()); @@ -197,6 +199,12 @@ void PreferenceManager::set(SETTING option, QString value) QSettings settings(PENCIL2D, PENCIL2D); switch (option) { + case SETTING::STYLE_ID: + settings.setValue(SETTING_STYLE_ID, value); + break; + case SETTING::PALETTE_ID: + settings.setValue(SETTING_PALETTE_ID, value); + break; case SETTING::BACKGROUND_STYLE: settings.setValue(SETTING_BACKGROUND_STYLE, value); break; diff --git a/core_lib/src/managers/thememanager.cpp b/core_lib/src/managers/thememanager.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core_lib/src/managers/thememanager.h b/core_lib/src/managers/thememanager.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core_lib/src/util/pencildef.h b/core_lib/src/util/pencildef.h index a16f6f89c6..5580dd099a 100644 --- a/core_lib/src/util/pencildef.h +++ b/core_lib/src/util/pencildef.h @@ -278,6 +278,8 @@ const static int MaxFramesBound = 9999; #define SETTING_ANTIALIAS "Antialiasing" #define SETTING_SHOW_GRID "ShowGrid" #define SETTING_COUNT "Count" +#define SETTING_STYLE_ID "StyleId" +#define SETTING_PALETTE_ID "PaletteId" #define SETTING_SHADOW "Shadow" #define SETTING_PREV_ONION "PrevOnion" #define SETTING_NEXT_ONION "NextOnion" diff --git a/core_lib/src/util/preferencesdef.h b/core_lib/src/util/preferencesdef.h index 66683c2e5a..e3156b872e 100644 --- a/core_lib/src/util/preferencesdef.h +++ b/core_lib/src/util/preferencesdef.h @@ -91,6 +91,8 @@ enum class SETTING LOAD_MOST_RECENT, LOAD_DEFAULT_PRESET, DEFAULT_PRESET, + STYLE_ID, + PALETTE_ID, COUNT, // COUNT must always be the last one. }; diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp new file mode 100644 index 0000000000..97f34b4860 --- /dev/null +++ b/core_lib/src/util/theming.cpp @@ -0,0 +1,105 @@ +#include "theming.h" + +#include +#include +#include +#include +#include + +/** + * Get a list of all valid keys that can be passed to Theming::getStyle(). + * + * The exact list will vary depending on the platform, loaded Qt plugins, + * and the Qt runtime configuration. + * + * @return A list of string keys. + * @see getStyle() + */ +QStringList Theming::availableStyles() +{ + return QStyleFactory::keys(); +} + +/** + * Get a list of all valid keys that can be passed to Theming::getPalette(). + * + * This list is generated by finding all palette configuration files in the + * standard search path and removing any that cannot be validated. + * + * @return A list of string keys. + * @see getPalette() + */ +QStringList Theming::availablePalettes() +{ + QStringList palettes; + for (const QString& palette : QDir(":/theme_palettes").entryList({"*.conf"}, QDir::Files)) + { + palettes.append(palette.chopped(5)); + } + return palettes; +} + +/** + * Fetch a style with a given key. + * + * @param key A case-insensitive style identifier. Current defined by the Qt plugin providing the style. + * @return A QStyle instance corresponding to the given key or a null pointer if there is none. + * @see availableStyles() + */ +QStyle* Theming::getStyle(const QString& key) +{ + QStyle* style = QStyleFactory::create(key); + + return style; +} + +/** + * Fetch a palette with a given key. + * + * @param key A palette identifier. + * @return A QPalette instance corresponding to the given key. If no palette with the key exists, + * or the conf file for the palette is invalid, a null pointer will be returned. + * @see availablePalettes() + */ +QPalette* Theming::getPalette(const QString& key) +{ + return loadPaletteConf(QString(":/theme_palettes/%1.conf").arg(key)); +} + +/** + * Create a QPalette instance from a .conf palette file. + * + * The file format must be in the INI format. It should have a ColorScheme group with + * active_colors, disabled_colors, and inactive_colors keys. Each should have at least 20 string list values + * corresponding to colors (typically in a hexadecimal RGBA format, ex #ff424245). + * + * @param filename The path to the .conf file to load. + * @return A QPalette instance with the color set from the .conf or nullptr if the file cannot be loaded or is not valid. + */ +QPalette* Theming::loadPaletteConf(const QString& filename) +{ + QPalette palette; + QSettings conf(filename, QSettings::IniFormat); + conf.beginGroup("ColorScheme"); + QList> colorGroups = { + { QPalette::Active, "active_colors" }, + { QPalette::Disabled, "disabled_colors" }, + { QPalette::Inactive, "inactive_colors" } + }; + for (const auto& colorGroup : colorGroups) + { + QStringList colors = conf.value(colorGroup.second).toStringList(); + // 20 is QPalette::NColorRoles prior to Qt 5.12, and is the minimum number of colors required + if (colors.count() < 20) + { + return nullptr; + } + + for (int i = 0; i < colors.count(); i++) + { + palette.setColor(colorGroup.first, QPalette::ColorRole(i), colors[i]); + } + } + + return new QPalette(palette); +} diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h new file mode 100644 index 0000000000..213cbeaac8 --- /dev/null +++ b/core_lib/src/util/theming.h @@ -0,0 +1,20 @@ +#ifndef THEMING_H +#define THEMING_H + +class QStyle; +class QPalette; + +class Theming +{ +public: + static QStringList availableStyles(); + static QStringList availablePalettes(); + + static QStyle* getStyle(const QString& key); + static QPalette* getPalette(const QString& key); + +private: + static QPalette* loadPaletteConf(const QString& filename); +}; + +#endif // THEMING_H From 99b6bf304b6436a8d6aead0c27ed2183725aaeea Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 2 Nov 2024 17:28:31 -0600 Subject: [PATCH 02/10] Fix some bugs with the theme preferences --- app/src/generalpage.cpp | 2 +- app/src/pencil2d.cpp | 27 ++++++++------------------- app/src/pencil2d.h | 3 +-- core_lib/src/util/theming.cpp | 11 ++++------- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index 8760e83c50..bcbafda932 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -168,7 +168,7 @@ void GeneralPage::updateValues() int styleIndex = ui->styleCombo->findText(mManager->getString(SETTING::STYLE_ID), Qt::MatchFixedString); ui->styleCombo->setCurrentIndex(qMax(0, styleIndex)); QSignalBlocker b20(ui->styleCombo); - int paletteIndex = ui->paletteCombo->findText(mManager->getString(SETTING::PALETTE_ID), Qt::MatchFixedString); + int paletteIndex = ui->paletteCombo->findData(mManager->getString(SETTING::PALETTE_ID), Qt::UserRole, Qt::MatchFixedString); ui->paletteCombo->setCurrentIndex(qMax(0, paletteIndex)); QSignalBlocker b3(ui->shadowsBox); ui->shadowsBox->setChecked(mManager->isOn(SETTING::SHADOW)); diff --git a/app/src/pencil2d.cpp b/app/src/pencil2d.cpp index 845905fa21..08e93f1eda 100644 --- a/app/src/pencil2d.cpp +++ b/app/src/pencil2d.cpp @@ -138,27 +138,19 @@ bool Pencil2D::event(QEvent* event) return QApplication::event(event); } -void Pencil2D::setStyleId(const QString styleId) +void Pencil2D::setTheme(const QString styleId, const QString paletteId) { - QPalette oldPalette = palette(); - QStyle* style = Theming::getStyle(styleId); - if (style != nullptr) + QStyle* newStyle = Theming::getStyle(styleId); + if (newStyle != nullptr) { - setStyle(style); + setStyle(newStyle); } else { setStyle(DEFAULT_STYLE); } - // setStyle is supposed to overwrite the palette, so it must be reapplied - setPalette(oldPalette); - - mainWindow->update(); -} - -void Pencil2D::setPaletteId(const QString paletteId) -{ + // Palette should be set after style is set std::unique_ptr palette(Theming::getPalette(paletteId)); if (palette != nullptr) { @@ -166,7 +158,7 @@ void Pencil2D::setPaletteId(const QString paletteId) } else { - setPalette(this->style()->standardPalette()); + setPalette(style()->standardPalette()); } mainWindow->update(); @@ -210,18 +202,15 @@ void Pencil2D::prepareGuiStartup(const QString& inputPath) mainWindow.reset(new MainWindow2); PreferenceManager* prefs = mainWindow->mEditor->preference(); - setStyleId(prefs->getString(SETTING::STYLE_ID)); - setPaletteId(prefs->getString(SETTING::PALETTE_ID)); + setTheme(prefs->getString(SETTING::STYLE_ID), prefs->getString(SETTING::PALETTE_ID)); connect(this, &Pencil2D::openFileRequested, mainWindow.get(), &MainWindow2::openFile); connect(prefs, &PreferenceManager::optionChanged, [=](SETTING setting) { switch (setting) { case SETTING::STYLE_ID: - setStyleId(prefs->getString(SETTING::STYLE_ID)); - break; case SETTING::PALETTE_ID: - setPaletteId(prefs->getString(SETTING::PALETTE_ID)); + setTheme(prefs->getString(SETTING::STYLE_ID), prefs->getString(SETTING::PALETTE_ID)); break; default: break; diff --git a/app/src/pencil2d.h b/app/src/pencil2d.h index 53a8f06986..ee49c30231 100644 --- a/app/src/pencil2d.h +++ b/app/src/pencil2d.h @@ -72,8 +72,7 @@ class Pencil2D : public QApplication bool event(QEvent* event) override; - void setStyleId(const QString styleId); - void setPaletteId(const QString paletteId); + void setTheme(const QString styleId, const QString paletteId); signals: /** * Emitted when the operating system requests that a file should be opened. diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index 97f34b4860..b40f077ac4 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -32,7 +32,7 @@ QStringList Theming::availableStyles() QStringList Theming::availablePalettes() { QStringList palettes; - for (const QString& palette : QDir(":/theme_palettes").entryList({"*.conf"}, QDir::Files)) + for (const QString& palette : QDir(":/theme_palettes").entryList({"*.conf"}, QDir::Files)) { palettes.append(palette.chopped(5)); } @@ -89,13 +89,10 @@ QPalette* Theming::loadPaletteConf(const QString& filename) for (const auto& colorGroup : colorGroups) { QStringList colors = conf.value(colorGroup.second).toStringList(); - // 20 is QPalette::NColorRoles prior to Qt 5.12, and is the minimum number of colors required - if (colors.count() < 20) - { - return nullptr; - } + // 20 is QPalette::NColorRoles prior to Qt 5.12, and is the minimum number of colors required for this format. + if (colors.count() < 20) return nullptr; - for (int i = 0; i < colors.count(); i++) + for (int i = 0; i < qMin(colors.count(), static_cast(QPalette::NColorRoles)); i++) { palette.setColor(colorGroup.first, QPalette::ColorRole(i), colors[i]); } From b20fd2c2d01e9d156045cea733c3d92c13c51af6 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 2 Nov 2024 17:46:42 -0600 Subject: [PATCH 03/10] Move window opacity to appearance section and fix tab order --- app/ui/generalpage.ui | 72 ++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/app/ui/generalpage.ui b/app/ui/generalpage.ui index da910ae6a7..80da40bfbb 100644 --- a/app/ui/generalpage.ui +++ b/app/ui/generalpage.ui @@ -28,7 +28,7 @@ 0 0 363 - 1239 + 1195 @@ -53,47 +53,42 @@ - - - - Window opacity - - - - - - Opacity - - - - - - - 30 - - - 100 - - - Qt::Horizontal - - - - - - Appearance + + + + + + Window opacity + + + + + + + 30 + + + 100 + + + Qt::Horizontal + + + + + - Window style: + Window style @@ -120,7 +115,7 @@ - Color palette: + Color palette @@ -632,6 +627,8 @@ scrollArea languageCombo windowOpacityLevel + styleCombo + paletteCombo shadowsBox toolCursorsBox canvasCursorBox @@ -646,6 +643,17 @@ gridCheckBox gridSizeInputW gridSizeInputH + actionSafeCheckBox + actionSafeInput + titleSafeCheckBox + titleSafeInput + safeHelperTextCheckbox + invertScrollDirectionBox + framePoolSizeSpin + newUndoRedoCheckBox + undoStepsBox + undoRedoGroupApplyButton + undoRedoGroupCancelButton From 4903adf9fe422224db91744bb2d21cf3be7fa8e5 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Sat, 2 Nov 2024 21:53:56 -0600 Subject: [PATCH 04/10] Allow users to add and remove their own color palettes --- app/src/filedialog.cpp | 8 ++++- app/src/generalpage.cpp | 57 +++++++++++++++++++++++++---- app/src/generalpage.h | 3 ++ app/src/pencil2d.cpp | 4 +-- app/ui/generalpage.ui | 28 ++++++++++++++- core_lib/src/util/fileformat.h | 5 +++ core_lib/src/util/filetype.h | 3 +- core_lib/src/util/theming.cpp | 65 +++++++++++++++++++++++++++++++++- core_lib/src/util/theming.h | 7 ++++ 9 files changed, 167 insertions(+), 13 deletions(-) diff --git a/app/src/filedialog.cpp b/app/src/filedialog.cpp index e1b21bf1ce..6fc2947394 100644 --- a/app/src/filedialog.cpp +++ b/app/src/filedialog.cpp @@ -74,7 +74,7 @@ void FileDialog::setLastSavePaths(const QString& filePath) QFileInfo filePathInfo(filePath); QDir projectPath = filePathInfo.absoluteDir(); QString baseName = filePathInfo.baseName(); - QList fileTypes = { FileType::IMAGE, FileType::IMAGE_SEQUENCE, FileType::GIF, FileType::MOVIE, FileType::SOUND, FileType::PALETTE }; + QList fileTypes = { FileType::IMAGE, FileType::IMAGE_SEQUENCE, FileType::GIF, FileType::MOVIE, FileType::SOUND, FileType::PALETTE, FileType::THEME_PALETTE }; for (FileType& fileType : fileTypes) { setLastSavePath(fileType, projectPath.absoluteFilePath(defaultFileName(fileType, baseName))); @@ -123,6 +123,7 @@ QString FileDialog::getDefaultExtensionByFileType(const FileType fileType) case FileType::PALETTE: return PFF_DEFAULT_PALETTE_EXT; case FileType::MOVIE: return PFF_DEFAULT_MOVIE_EXT; case FileType::SOUND: return PFF_DEFAULT_SOUND_EXT; + case FileType::THEME_PALETTE: return PFF_DEFAULT_THEME_PALETTE_EXT; default: Q_UNREACHABLE(); } @@ -172,6 +173,7 @@ QString FileDialog::openDialogCaption(FileType fileType) case FileType::MOVIE: return tr("Import movie"); case FileType::SOUND: return tr("Import sound"); case FileType::PALETTE: return tr("Open palette"); + case FileType::THEME_PALETTE: return tr("Import color palette"); } return ""; } @@ -188,6 +190,7 @@ QString FileDialog::saveDialogCaption(FileType fileType) case FileType::MOVIE: return tr("Export movie"); case FileType::SOUND: return ""; case FileType::PALETTE: return tr("Export palette"); + case FileType::THEME_PALETTE: return ""; } return ""; } @@ -204,6 +207,7 @@ QString FileDialog::openFileFilters(FileType fileType) case FileType::MOVIE: return PFF_MOVIE_EXT; case FileType::SOUND: return PFF_SOUND_EXT_FILTER; case FileType::PALETTE: return PFF_PALETTE_EXT_FILTER; + case FileType::THEME_PALETTE: return PFF_THEME_PALETTE_EXT_FILTER; } return ""; } @@ -220,6 +224,7 @@ QString FileDialog::saveFileFilters(FileType fileType) case FileType::MOVIE: return "MP4 (*.mp4);; AVI (*.avi);; WebM (*.webm);; APNG (*.apng)"; case FileType::SOUND: return ""; case FileType::PALETTE: return PFF_PALETTE_EXT_FILTER; + case FileType::THEME_PALETTE: return ""; } return ""; } @@ -297,6 +302,7 @@ QString FileDialog::toSettingKey(FileType fileType) case FileType::MOVIE: return "Movie"; case FileType::SOUND: return "Sound"; case FileType::PALETTE: return "Palette"; + case FileType::THEME_PALETTE: return "ThemePalette"; } return ""; } diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index bcbafda932..d319a69879 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -18,10 +18,12 @@ GNU General Public License for more details. #include "generalpage.h" #include +#include #include #include #include +#include "filedialog.h" #include "pencildef.h" #include "preferencemanager.h" #include "theming.h" @@ -37,13 +39,7 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage) ui->styleCombo->addItem("System Default", ""); ui->styleCombo->addItems(Theming::availableStyles()); - ui->paletteCombo->addItem("Default", ""); - for (const QString& palette : Theming::availablePalettes()) - { - QString paletteName(palette); - paletteName.replace('_', ' '); - ui->paletteCombo->addItem(paletteName, palette); - } + populatePaletteCombo(false); QString languages [][3] { @@ -123,6 +119,8 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage) connect(ui->backgroundButtons, buttonClicked, this, &GeneralPage::backgroundChanged); connect(ui->styleCombo, curIndexChanged, this, &GeneralPage::styleChanged); connect(ui->paletteCombo, curIndexChanged, this, &GeneralPage::paletteChanged); + connect(ui->addPaletteButton, &QPushButton::pressed, this, &GeneralPage::addPalette); + connect(ui->removePaletteButton, &QPushButton::pressed, this, &GeneralPage::removePalette); connect(ui->shadowsBox, &QCheckBox::stateChanged, this, &GeneralPage::shadowsCheckboxStateChanged); connect(ui->toolCursorsBox, &QCheckBox::stateChanged, this, &GeneralPage::toolCursorsCheckboxStateChanged); connect(ui->antialiasingBox, &QCheckBox::stateChanged, this, &GeneralPage::antiAliasCheckboxStateChanged); @@ -279,6 +277,30 @@ void GeneralPage::paletteChanged(int index) mManager->set(SETTING::PALETTE_ID, ui->paletteCombo->itemData(index).toString()); } +void GeneralPage::addPalette() +{ + QString filePath = FileDialog::getOpenFileName(this, FileType::THEME_PALETTE); + if (!filePath.isEmpty()) + { + QFileInfo fileInfo(filePath); + if (Theming::addPalette(filePath).ok()) + { + mManager->set(SETTING::PALETTE_ID, fileInfo.baseName()); + populatePaletteCombo(); + } + } +} + +void GeneralPage::removePalette() +{ + QString key = ui->paletteCombo->currentData().toString(); + if (Theming::removePalette(key).ok()) + { + ui->paletteCombo->removeItem(ui->paletteCombo->currentIndex()); + ui->paletteCombo->setCurrentIndex(0); + } +} + void GeneralPage::shadowsCheckboxStateChanged(int b) { mManager->set(SETTING::SHADOW, b != Qt::Unchecked); @@ -438,3 +460,24 @@ void GeneralPage::undoRedoCancelButtonPressed() ui->undoRedoGroupCancelButton->setDisabled(true); ui->undoRedoGroupApplyButton->setDisabled(true); } + +void GeneralPage::populatePaletteCombo(bool usePreference) +{ + QSignalBlocker b(ui->paletteCombo); + + ui->paletteCombo->clear(); + ui->paletteCombo->addItem("Default", ""); + for (const QString& palette : Theming::availablePalettes()) + { + QString paletteName(palette); + paletteName.replace('_', ' '); + ui->paletteCombo->addItem(paletteName, palette); + } + + if (usePreference) + { + QString paletteKey = mManager->getString(SETTING::PALETTE_ID); + int paletteIndex = ui->paletteCombo->findData(paletteKey, Qt::UserRole, Qt::MatchFixedString); + ui->paletteCombo->setCurrentIndex(qMax(0, paletteIndex)); + } +} diff --git a/app/src/generalpage.h b/app/src/generalpage.h index 615a601d8d..0c04489c5a 100644 --- a/app/src/generalpage.h +++ b/app/src/generalpage.h @@ -50,6 +50,8 @@ private slots: void languageChanged(int i); void styleChanged(int index); void paletteChanged(int index); + void addPalette(); + void removePalette(); void shadowsCheckboxStateChanged(int b); void antiAliasCheckboxStateChanged(int b); void toolCursorsCheckboxStateChanged(int b); @@ -67,6 +69,7 @@ private slots: void undoRedoCancelButtonPressed(); private: + void populatePaletteCombo(bool usePreference = true); bool canApplyOrCancelUndoRedoChanges() const; void updateSafeHelperTextEnabledState(); diff --git a/app/src/pencil2d.cpp b/app/src/pencil2d.cpp index 08e93f1eda..cb8b052abc 100644 --- a/app/src/pencil2d.cpp +++ b/app/src/pencil2d.cpp @@ -147,7 +147,7 @@ void Pencil2D::setTheme(const QString styleId, const QString paletteId) } else { - setStyle(DEFAULT_STYLE); + newStyle = setStyle(DEFAULT_STYLE); } // Palette should be set after style is set @@ -158,7 +158,7 @@ void Pencil2D::setTheme(const QString styleId, const QString paletteId) } else { - setPalette(style()->standardPalette()); + setPalette(newStyle->standardPalette()); } mainWindow->update(); diff --git a/app/ui/generalpage.ui b/app/ui/generalpage.ui index 80da40bfbb..1c2ffbcac6 100644 --- a/app/ui/generalpage.ui +++ b/app/ui/generalpage.ui @@ -122,6 +122,28 @@ + + + + + + + + :/icons/themes/playful/misc/add-color.svg:/icons/themes/playful/misc/add-color.svg + + + + + + + + + + + :/icons/themes/playful/misc/remove-color.svg:/icons/themes/playful/misc/remove-color.svg + + + @@ -629,6 +651,8 @@ windowOpacityLevel styleCombo paletteCombo + addPaletteButton + removePaletteButton shadowsBox toolCursorsBox canvasCursorBox @@ -655,7 +679,9 @@ undoRedoGroupApplyButton undoRedoGroupCancelButton - + + + diff --git a/core_lib/src/util/fileformat.h b/core_lib/src/util/fileformat.h index 6935d0aa44..7d1d6d67d5 100644 --- a/core_lib/src/util/fileformat.h +++ b/core_lib/src/util/fileformat.h @@ -57,6 +57,8 @@ GNU General Public License for more details. #define PFF_SOUND_EXT_FILTER \ QCoreApplication::translate("FileFormat", "Sound formats") + " (*.wav *.mp3 *.wma *.ogg *.flac *.opus *.aiff *.aac *.caf);;WAV (*.wav);;MP3 (*.mp3);;WMA (*.wma);;OGG (*.ogg);;FLAC (*.flac);;Opus (*.opus);;AIFF (*.aiff);;AAC (*.aac);;CAF (*.caf)" +#define PFF_THEME_PALETTE_EXT_FILTER \ + QCoreApplication::translate("FileFormat", "qt5ct Color Palette") + " (*.conf);;" #define PFF_DEFAULT_PROJECT_EXT \ QString(".pclx") @@ -79,6 +81,9 @@ GNU General Public License for more details. #define PFF_DEFAULT_SOUND_EXT \ QString(".wav") +#define PFF_DEFAULT_THEME_PALETTE_EXT \ + QString(".conf") + #define PFF_OLD_DATA_DIR "data" #define PFF_DATA_DIR "data" #define PFF_XML_FILE_NAME "main.xml" diff --git a/core_lib/src/util/filetype.h b/core_lib/src/util/filetype.h index 9a88fad1e8..8dd47b7d68 100644 --- a/core_lib/src/util/filetype.h +++ b/core_lib/src/util/filetype.h @@ -10,7 +10,8 @@ enum class FileType ANIMATED_IMAGE, MOVIE, SOUND, - PALETTE + PALETTE, + THEME_PALETTE, }; #endif // FILETYPE_H diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index b40f077ac4..4e9af0f582 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -3,9 +3,12 @@ #include #include #include +#include #include #include +#include "pencilerror.h" + /** * Get a list of all valid keys that can be passed to Theming::getStyle(). * @@ -32,10 +35,19 @@ QStringList Theming::availableStyles() QStringList Theming::availablePalettes() { QStringList palettes; + + // Built-in palettes for (const QString& palette : QDir(":/theme_palettes").entryList({"*.conf"}, QDir::Files)) { palettes.append(palette.chopped(5)); } + + // User palettes + for (const QString& palette : userPaletteDir().entryList({"*.conf"}, QDir::Files)) + { + palettes.append(palette.chopped(5)); + } + return palettes; } @@ -63,7 +75,50 @@ QStyle* Theming::getStyle(const QString& key) */ QPalette* Theming::getPalette(const QString& key) { - return loadPaletteConf(QString(":/theme_palettes/%1.conf").arg(key)); + QPalette* builtinPalette = loadPaletteConf(QString(":/theme_palettes/%1.conf").arg(key)); + if (builtinPalette != nullptr) return builtinPalette; + + return loadPaletteConf(userPaletteDir().filePath(QString("%1.conf").arg(key))); +} + +/** + * Saves a palette to the user's palette directory. + * + * @param filepath The path to a .conf palette file to load. + * @return A Status indicating if the palette was added successfully. + */ +Status Theming::addPalette(const QString &filePath) +{ + if (!filePath.endsWith(".conf")) return Status::INVALID_ARGUMENT; + QFileInfo fileInfo(filePath); + if (fileInfo.baseName().isEmpty()) return Status::INVALID_ARGUMENT; + if (!fileInfo.isFile()) return Status::FILE_NOT_FOUND; + if (!fileInfo.isReadable()) return Status::ERROR_FILE_CANNOT_OPEN; + + QFile inFile(filePath); + if (inFile.copy(userPaletteDir().filePath(fileInfo.fileName()))) + { + return Status::OK; + } + return Status::FAIL; +} + +/** + * Removes a palette from the user's palette directory. + * + * The .conf palette file will be deleted by this function and cannot be undone. + * + * @param key The palette id of the palette to remove. + * @return A Status indicated if the palette was removed successfully. + */ +Status Theming::removePalette(const QString& key) +{ + QFile paletteFile(userPaletteDir().filePath(QString("%1.conf").arg(key))); + if (paletteFile.remove()) + { + return Status::OK; + } + return Status::FAIL; } /** @@ -100,3 +155,11 @@ QPalette* Theming::loadPaletteConf(const QString& filename) return new QPalette(palette); } + +const QDir Theming::userPaletteDir() +{ + QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + dir.cd("theme_palettes"); + + return dir; +} diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h index 213cbeaac8..a9293f177d 100644 --- a/core_lib/src/util/theming.h +++ b/core_lib/src/util/theming.h @@ -1,9 +1,12 @@ #ifndef THEMING_H #define THEMING_H +class QDir; class QStyle; class QPalette; +class Status; + class Theming { public: @@ -13,8 +16,12 @@ class Theming static QStyle* getStyle(const QString& key); static QPalette* getPalette(const QString& key); + static Status addPalette(const QString& filePath); + static Status removePalette(const QString& key); private: static QPalette* loadPaletteConf(const QString& filename); + + static const QDir userPaletteDir(); }; #endif // THEMING_H From 25156c7139829573c15a5f7f8b989d77f328176a Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 4 Nov 2024 17:06:19 -0700 Subject: [PATCH 05/10] Add more color palettes --- core_lib/data/core_lib.qrc | 8 ++++++++ core_lib/data/theme_palettes/Arc_Dark.conf | 4 ++++ core_lib/data/theme_palettes/Arc_Light.conf | 4 ++++ core_lib/data/theme_palettes/Frappe.conf | 4 ++++ core_lib/data/theme_palettes/Gruvbox_Dark.conf | 4 ++++ core_lib/data/theme_palettes/Gruvbox_Light.conf | 4 ++++ core_lib/data/theme_palettes/Latte.conf | 4 ++++ core_lib/data/theme_palettes/Macchiato.conf | 4 ++++ core_lib/data/theme_palettes/Mocha.conf | 4 ++++ 9 files changed, 40 insertions(+) create mode 100644 core_lib/data/theme_palettes/Arc_Dark.conf create mode 100644 core_lib/data/theme_palettes/Arc_Light.conf create mode 100644 core_lib/data/theme_palettes/Frappe.conf create mode 100644 core_lib/data/theme_palettes/Gruvbox_Dark.conf create mode 100644 core_lib/data/theme_palettes/Gruvbox_Light.conf create mode 100644 core_lib/data/theme_palettes/Latte.conf create mode 100644 core_lib/data/theme_palettes/Macchiato.conf create mode 100644 core_lib/data/theme_palettes/Mocha.conf diff --git a/core_lib/data/core_lib.qrc b/core_lib/data/core_lib.qrc index f5673e2d19..3f9aa2a1a1 100644 --- a/core_lib/data/core_lib.qrc +++ b/core_lib/data/core_lib.qrc @@ -5,5 +5,13 @@ theme_palettes/Ia_Ora.conf theme_palettes/Waves.conf theme_palettes/Rose_Pine.conf + theme_palettes/Arc_Dark.conf + theme_palettes/Arc_Light.conf + theme_palettes/Frappe.conf + theme_palettes/Gruvbox_Dark.conf + theme_palettes/Gruvbox_Light.conf + theme_palettes/Latte.conf + theme_palettes/Macchiato.conf + theme_palettes/Mocha.conf diff --git a/core_lib/data/theme_palettes/Arc_Dark.conf b/core_lib/data/theme_palettes/Arc_Dark.conf new file mode 100644 index 0000000000..3096780ce9 --- /dev/null +++ b/core_lib/data/theme_palettes/Arc_Dark.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffffff, #383C4A, #979797, #5e5c5b, #302f2e, #4a4947, #ffffff, #ffffff, #ffffff, #3d3d3d, #2F343F, #e7e4e0, #5294e2, #f9f9f9, #5294e2, #a70b06, #5c5b5a, #ffffff, #3f3f36, #ffffff +disabled_colors=#808080, #383C4A, #979797, #5e5c5b, #302f2e, #4a4947, #808080, #ffffff, #808080, #3d3d3d, #2F343F, #e7e4e0, #5294e2, #808080, #5294e2, #a70b06, #5c5b5a, #ffffff, #3f3f36, #ffffff +inactive_colors=#ffffff, #383C4A, #979797, #5e5c5b, #302f2e, #4a4947, #ffffff, #ffffff, #ffffff, #3d3d3d, #2F343F, #e7e4e0, #5294e2, #f9f9f9, #5294e2, #a70b06, #5c5b5a, #ffffff, #3f3f36, #ffffff diff --git a/core_lib/data/theme_palettes/Arc_Light.conf b/core_lib/data/theme_palettes/Arc_Light.conf new file mode 100644 index 0000000000..f93ff03400 --- /dev/null +++ b/core_lib/data/theme_palettes/Arc_Light.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#000000, #F5F6F7, #ffffff, #F3F3F3, #9f9d9a, #b8b5b2, #000000, #ffffff, #000000, #ffffff, #E7E8EB, #b1aeab, #5492DF, #ffffff, #0000ff, #ff0000, #f7f5f3, #000000, #ffffdc, #000000 +disabled_colors=#bebebe, #F5F6F7, #ffffff, #F3F3F3, #9f9d9a, #b8b5b2, #bebebe, #ffffff, #bebebe, #efebe7, #E7E8EB, #b1aeab, #9f9d9a, #ffffff, #0000ff, #ff0000, #f7f5f3, #000000, #ffffdc, #000000 +inactive_colors=#000000, #F5F6F7, #ffffff, #F3F3F3, #9f9d9a, #b8b5b2, #000000, #ffffff, #000000, #ffffff, #E7E8EB, #b1aeab, #5492DF, #ffffff, #0000ff, #ff0000, #f7f5f3, #000000, #ffffdc, #000000 diff --git a/core_lib/data/theme_palettes/Frappe.conf b/core_lib/data/theme_palettes/Frappe.conf new file mode 100644 index 0000000000..48e41690b6 --- /dev/null +++ b/core_lib/data/theme_palettes/Frappe.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffc6d0f5, #ff292c3c, #ffa5adce, #ff949cbb, #ff51576d, #ff737994, #ffc6d0f5, #ffc6d0f5, #ffc6d0f5, #ff303446, #ff292c3c, #ff838ba7, #ff8caaee, #ff303446, #ff8caaee, #ffe78284, #ff303446, #ffc6d0f5, #ff232634, #ffc6d0f5, #80838ba7 +disabled_colors=#ffa5adce, #ff292c3c, #ffa5adce, #ff949cbb, #ff51576d, #ff737994, #ffa5adce, #ffa5adce, #ffa5adce, #ff303446, #ff292c3c, #ff838ba7, #ff626880, #ffb5bfe2, #ff8caaee, #ffe78284, #ff303446, #ffc6d0f5, #ff232634, #ffc6d0f5, #80838ba7 +inactive_colors=#ffc6d0f5, #ff292c3c, #ffa5adce, #ff949cbb, #ff51576d, #ff737994, #ffc6d0f5, #ffc6d0f5, #ffc6d0f5, #ff303446, #ff292c3c, #ff838ba7, #ff414559, #ffa5adcb, #ff8caaee, #ffe78284, #ff303446, #ffc6d0f5, #ff232634, #ffc6d0f5, #80838ba7 diff --git a/core_lib/data/theme_palettes/Gruvbox_Dark.conf b/core_lib/data/theme_palettes/Gruvbox_Dark.conf new file mode 100644 index 0000000000..dc6dbf7449 --- /dev/null +++ b/core_lib/data/theme_palettes/Gruvbox_Dark.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffebdbb2, #ff1d2021, #ffbdae93, #ffa89984, #ff3c3836, #ff504945, #ffebdbb2, #ffebdbb2, #ffebdbb2, #ff282828, #ff1d2021, #ff504945, #ff458588, #ff282828, #ff458588, #ffcc241d, #ff282828, #ffebdbb2, #ff1d2021, #ffebdbb2, #ffbdae93 +disabled_colors=#ffbdae93, #ff1d2021, #ffbdae93, #ffa89984, #ff3c3836, #ff504945, #ffbdae93, #ffbdae93, #ffbdae93, #ff282828, #ff1d2021, #ff504945, #ff438184, #ff3c3836, #ff458588, #ffcc241d, #ff282828, #ffebdbb2, #ff1d2021, #ffebdbb2, #ffbdae93 +inactive_colors=#ffebdbb2, #ff1d2021, #ffbdae93, #ffa89984, #ff3c3836, #ff504945, #ffebdbb2, #ffebdbb2, #ffebdbb2, #ff282828, #ff1d2021, #ff504945, #ff438184, #ffa89984, #ff458588, #ffcc241d, #ff282828, #ffebdbb2, #ff1d2021, #ffebdbb2, #ffbdae93 diff --git a/core_lib/data/theme_palettes/Gruvbox_Light.conf b/core_lib/data/theme_palettes/Gruvbox_Light.conf new file mode 100644 index 0000000000..a363a2ff88 --- /dev/null +++ b/core_lib/data/theme_palettes/Gruvbox_Light.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ff504945, #ffebdbb2, #ff665c54, #ff7c6f64, #ffd5c4a1, #ffbdae93, #ff3c3836, #ff3c3836, #ff3c3836, #fffbf1c7, #fffbf1c7, #ffa89984, #ff458588, #fffbf1c7, #ff458588, #ffcc241d, #ffebdbb2, #ff3c3836, #ffebdbb2, #ff3c3836, #ff928374 +disabled_colors=#ff665c54, #ffebdbb2, #ff665c54, #ff7c6f64, #ffd5c4a1, #ffbdae93, #ff665c54, #ff665c54, #ff665c54, #fffbf1c7, #fffbf1c7, #ffa79883, #ffbdae93, #ff504945, #ff458588, #ffbd211b, #ffebdbb2, #ff3c3836, #ffebdbb2, #ff3c3836, #ff928374 +inactive_colors=#ff504945, #ffebdbb2, #ff665c54, #ff7c6f64, #ffd5c4a1, #ffbdae93, #ff373432, #ff3c3836, #ff3c3836, #fffbf1c7, #fffbf1c7, #ffa79883, #ffd5c4a1, #ff665c54, #ff458588, #ffbd211b, #ffebdbb2, #ff3c3836, #ffebdbb2, #ff3c3836, #ff928374 diff --git a/core_lib/data/theme_palettes/Latte.conf b/core_lib/data/theme_palettes/Latte.conf new file mode 100644 index 0000000000..42db9c58f3 --- /dev/null +++ b/core_lib/data/theme_palettes/Latte.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff1e66f5, #ffeff1f5, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1 +disabled_colors=#ff6c6f85, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff6c6f85, #ff6c6f85, #ff6c6f85, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff9ca0b0, #ff5c5f77, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1 +inactive_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ffccd0da, #ff6c6f85, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1 diff --git a/core_lib/data/theme_palettes/Macchiato.conf b/core_lib/data/theme_palettes/Macchiato.conf new file mode 100644 index 0000000000..fdae012c1c --- /dev/null +++ b/core_lib/data/theme_palettes/Macchiato.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffcad3f5, #ff1e2030, #ffa5adcb, #ff939ab7, #ff494d64, #ff6e738d, #ffcad3f5, #ffcad3f5, #ffcad3f5, #ff24273a, #ff1e2030, #ff8087a2, #ff8aadf4, #ff24273a, #ff8aadf4, #ffed8796, #ff24273a, #ffcad3f5, #ff181926, #ffcad3f5, #808087a2 +disabled_colors=#ffa5adcb, #ff1e2030, #ffa5adcb, #ff939ab7, #ff494d64, #ff6e738d, #ffa5adcb, #ffa5adcb, #ffa5adcb, #ff24273a, #ff1e2030, #ff8087a2, #ff8aadf4, #ff494d64, #ff8aadf4, #ffed8796, #ff24273a, #ffcad3f5, #ff181926, #ffcad3f5, #808087a2 +inactive_colors=#ffcdd6f4, #ff1e2030, #ffa5adcb, #ff939ab7, #ff494d64, #ff6e738d, #ffcad3f5, #ffcad3f5, #ffcad3f5, #ff24273a, #ff1e2030, #ff8087a2, #ff8aadf4, #ffa5adcb, #ff8aadf4, #ffed8796, #ff24273a, #ffcad3f5, #ff181926, #ffcad3f5, #808087a2 diff --git a/core_lib/data/theme_palettes/Mocha.conf b/core_lib/data/theme_palettes/Mocha.conf new file mode 100644 index 0000000000..e566a63073 --- /dev/null +++ b/core_lib/data/theme_palettes/Mocha.conf @@ -0,0 +1,4 @@ +[ColorScheme] +active_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ff1e1e2e, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c +disabled_colors=#ffa6adc8, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffa6adc8, #ffa6adc8, #ffa6adc8, #ff1e1e2e, #ff11111b, #ff7f849c, #ff89b4fa, #ff45475a, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c +inactive_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ffa6adc8, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c From d8015ac3de6f1f13e9d62ef28f0e1091fc058c0a Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Mon, 4 Nov 2024 23:34:21 -0700 Subject: [PATCH 06/10] Refactor theme palette file parsing into it's own class Also disabled the remove palette button for built-in palettes, and improved the organization of the palettes combo box. --- app/src/generalpage.cpp | 34 +++-- app/src/pencil2d.cpp | 6 +- core_lib/data/core_lib.qrc | 24 ++-- .../{Arc_Dark.conf => arc-dark.conf} | 4 + .../{Arc_Light.conf => arc-light.conf} | 4 + .../{Darker.conf => darker.conf} | 4 + .../{Frappe.conf => frappe.conf} | 4 + .../{Gruvbox_Dark.conf => gruvbox-dark.conf} | 4 + ...{Gruvbox_Light.conf => gruvbox-light.conf} | 4 + .../{Ia_Ora.conf => ia-ora.conf} | 4 + .../theme_palettes/{Latte.conf => latte.conf} | 4 + .../{Macchiato.conf => macchiato.conf} | 4 + .../theme_palettes/{Mocha.conf => mocha.conf} | 4 + .../{Rose_Pine.conf => rose-pine.conf} | 4 + .../theme_palettes/{Waves.conf => waves.conf} | 4 + core_lib/src/util/theming.cpp | 124 +++++++++++++----- core_lib/src/util/theming.h | 32 ++++- 17 files changed, 207 insertions(+), 61 deletions(-) rename core_lib/data/theme_palettes/{Arc_Dark.conf => arc-dark.conf} (92%) rename core_lib/data/theme_palettes/{Arc_Light.conf => arc-light.conf} (92%) rename core_lib/data/theme_palettes/{Darker.conf => darker.conf} (94%) rename core_lib/data/theme_palettes/{Frappe.conf => frappe.conf} (94%) rename core_lib/data/theme_palettes/{Gruvbox_Dark.conf => gruvbox-dark.conf} (93%) rename core_lib/data/theme_palettes/{Gruvbox_Light.conf => gruvbox-light.conf} (93%) rename core_lib/data/theme_palettes/{Ia_Ora.conf => ia-ora.conf} (94%) rename core_lib/data/theme_palettes/{Latte.conf => latte.conf} (94%) rename core_lib/data/theme_palettes/{Macchiato.conf => macchiato.conf} (94%) rename core_lib/data/theme_palettes/{Mocha.conf => mocha.conf} (94%) rename core_lib/data/theme_palettes/{Rose_Pine.conf => rose-pine.conf} (93%) rename core_lib/data/theme_palettes/{Waves.conf => waves.conf} (94%) diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index d319a69879..06ea84c2c2 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -166,8 +166,10 @@ void GeneralPage::updateValues() int styleIndex = ui->styleCombo->findText(mManager->getString(SETTING::STYLE_ID), Qt::MatchFixedString); ui->styleCombo->setCurrentIndex(qMax(0, styleIndex)); QSignalBlocker b20(ui->styleCombo); - int paletteIndex = ui->paletteCombo->findData(mManager->getString(SETTING::PALETTE_ID), Qt::UserRole, Qt::MatchFixedString); + QString paletteKey = mManager->getString(SETTING::PALETTE_ID); + int paletteIndex = ui->paletteCombo->findData(paletteKey, Qt::UserRole, Qt::MatchFixedString); ui->paletteCombo->setCurrentIndex(qMax(0, paletteIndex)); + ui->removePaletteButton->setEnabled(!paletteKey.isEmpty() && !Theming::getPalette(paletteKey).isBuiltIn()); QSignalBlocker b3(ui->shadowsBox); ui->shadowsBox->setChecked(mManager->isOn(SETTING::SHADOW)); QSignalBlocker b4(ui->toolCursorsBox); @@ -274,7 +276,9 @@ void GeneralPage::styleChanged(int index) void GeneralPage::paletteChanged(int index) { - mManager->set(SETTING::PALETTE_ID, ui->paletteCombo->itemData(index).toString()); + QString paletteKey = ui->paletteCombo->itemData(index).toString(); + mManager->set(SETTING::PALETTE_ID, paletteKey); + ui->removePaletteButton->setEnabled(!paletteKey.isEmpty() && !Theming::getPalette(paletteKey).isBuiltIn()); } void GeneralPage::addPalette() @@ -463,15 +467,25 @@ void GeneralPage::undoRedoCancelButtonPressed() void GeneralPage::populatePaletteCombo(bool usePreference) { - QSignalBlocker b(ui->paletteCombo); - - ui->paletteCombo->clear(); - ui->paletteCombo->addItem("Default", ""); - for (const QString& palette : Theming::availablePalettes()) { - QString paletteName(palette); - paletteName.replace('_', ' '); - ui->paletteCombo->addItem(paletteName, palette); + QSignalBlocker b(ui->paletteCombo); + + ui->paletteCombo->clear(); + ui->paletteCombo->addItem("Default", ""); + ui->paletteCombo->insertSeparator(1); + QList palettes = Theming::availablePalettes(); + std::sort(palettes.begin(), palettes.end(), [](ThemeColorPalette a, ThemeColorPalette b) { return a.displayName().toLower() < b.displayName().toLower(); }); + for (const auto& palette : palettes) + { + if (palette.isDark()) continue; + ui->paletteCombo->addItem(palette.displayName(), palette.id()); + } + ui->paletteCombo->insertSeparator(ui->paletteCombo->count()); + for (const auto& palette : palettes) + { + if (!palette.isDark()) continue; + ui->paletteCombo->addItem(palette.displayName(), palette.id()); + } } if (usePreference) diff --git a/app/src/pencil2d.cpp b/app/src/pencil2d.cpp index cb8b052abc..259d5031e9 100644 --- a/app/src/pencil2d.cpp +++ b/app/src/pencil2d.cpp @@ -151,10 +151,10 @@ void Pencil2D::setTheme(const QString styleId, const QString paletteId) } // Palette should be set after style is set - std::unique_ptr palette(Theming::getPalette(paletteId)); - if (palette != nullptr) + ThemeColorPalette palette(Theming::getPalette(paletteId)); + if (palette.isValid()) { - setPalette(*palette); + setPalette(palette.palette()); } else { diff --git a/core_lib/data/core_lib.qrc b/core_lib/data/core_lib.qrc index 3f9aa2a1a1..4053207cb1 100644 --- a/core_lib/data/core_lib.qrc +++ b/core_lib/data/core_lib.qrc @@ -1,17 +1,17 @@ resources/kb.ini - theme_palettes/Darker.conf - theme_palettes/Ia_Ora.conf - theme_palettes/Waves.conf - theme_palettes/Rose_Pine.conf - theme_palettes/Arc_Dark.conf - theme_palettes/Arc_Light.conf - theme_palettes/Frappe.conf - theme_palettes/Gruvbox_Dark.conf - theme_palettes/Gruvbox_Light.conf - theme_palettes/Latte.conf - theme_palettes/Macchiato.conf - theme_palettes/Mocha.conf + theme_palettes/darker.conf + theme_palettes/ia-ora.conf + theme_palettes/waves.conf + theme_palettes/rose-pine.conf + theme_palettes/arc-dark.conf + theme_palettes/arc-light.conf + theme_palettes/frappe.conf + theme_palettes/gruvbox-dark.conf + theme_palettes/gruvbox-light.conf + theme_palettes/latte.conf + theme_palettes/macchiato.conf + theme_palettes/mocha.conf diff --git a/core_lib/data/theme_palettes/Arc_Dark.conf b/core_lib/data/theme_palettes/arc-dark.conf similarity index 92% rename from core_lib/data/theme_palettes/Arc_Dark.conf rename to core_lib/data/theme_palettes/arc-dark.conf index 3096780ce9..1e65dfdb0d 100644 --- a/core_lib/data/theme_palettes/Arc_Dark.conf +++ b/core_lib/data/theme_palettes/arc-dark.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Arc Dark +IsDark=true + [ColorScheme] active_colors=#ffffff, #383C4A, #979797, #5e5c5b, #302f2e, #4a4947, #ffffff, #ffffff, #ffffff, #3d3d3d, #2F343F, #e7e4e0, #5294e2, #f9f9f9, #5294e2, #a70b06, #5c5b5a, #ffffff, #3f3f36, #ffffff disabled_colors=#808080, #383C4A, #979797, #5e5c5b, #302f2e, #4a4947, #808080, #ffffff, #808080, #3d3d3d, #2F343F, #e7e4e0, #5294e2, #808080, #5294e2, #a70b06, #5c5b5a, #ffffff, #3f3f36, #ffffff diff --git a/core_lib/data/theme_palettes/Arc_Light.conf b/core_lib/data/theme_palettes/arc-light.conf similarity index 92% rename from core_lib/data/theme_palettes/Arc_Light.conf rename to core_lib/data/theme_palettes/arc-light.conf index f93ff03400..3047fc3f54 100644 --- a/core_lib/data/theme_palettes/Arc_Light.conf +++ b/core_lib/data/theme_palettes/arc-light.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Arc Light +IsDark=false + [ColorScheme] active_colors=#000000, #F5F6F7, #ffffff, #F3F3F3, #9f9d9a, #b8b5b2, #000000, #ffffff, #000000, #ffffff, #E7E8EB, #b1aeab, #5492DF, #ffffff, #0000ff, #ff0000, #f7f5f3, #000000, #ffffdc, #000000 disabled_colors=#bebebe, #F5F6F7, #ffffff, #F3F3F3, #9f9d9a, #b8b5b2, #bebebe, #ffffff, #bebebe, #efebe7, #E7E8EB, #b1aeab, #9f9d9a, #ffffff, #0000ff, #ff0000, #f7f5f3, #000000, #ffffdc, #000000 diff --git a/core_lib/data/theme_palettes/Darker.conf b/core_lib/data/theme_palettes/darker.conf similarity index 94% rename from core_lib/data/theme_palettes/Darker.conf rename to core_lib/data/theme_palettes/darker.conf index cf2f69f7f6..87fdc802bd 100644 --- a/core_lib/data/theme_palettes/Darker.conf +++ b/core_lib/data/theme_palettes/darker.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Darker +IsDark=true + [ColorScheme] active_colors=#ffffffff, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffffffff, #ffffffff, #ffffffff, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #fff9f9f9, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff disabled_colors=#ff808080, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ff808080, #ffffffff, #ff808080, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #ff808080, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff diff --git a/core_lib/data/theme_palettes/Frappe.conf b/core_lib/data/theme_palettes/frappe.conf similarity index 94% rename from core_lib/data/theme_palettes/Frappe.conf rename to core_lib/data/theme_palettes/frappe.conf index 48e41690b6..18601de758 100644 --- a/core_lib/data/theme_palettes/Frappe.conf +++ b/core_lib/data/theme_palettes/frappe.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Frappe +IsDark=true + [ColorScheme] active_colors=#ffc6d0f5, #ff292c3c, #ffa5adce, #ff949cbb, #ff51576d, #ff737994, #ffc6d0f5, #ffc6d0f5, #ffc6d0f5, #ff303446, #ff292c3c, #ff838ba7, #ff8caaee, #ff303446, #ff8caaee, #ffe78284, #ff303446, #ffc6d0f5, #ff232634, #ffc6d0f5, #80838ba7 disabled_colors=#ffa5adce, #ff292c3c, #ffa5adce, #ff949cbb, #ff51576d, #ff737994, #ffa5adce, #ffa5adce, #ffa5adce, #ff303446, #ff292c3c, #ff838ba7, #ff626880, #ffb5bfe2, #ff8caaee, #ffe78284, #ff303446, #ffc6d0f5, #ff232634, #ffc6d0f5, #80838ba7 diff --git a/core_lib/data/theme_palettes/Gruvbox_Dark.conf b/core_lib/data/theme_palettes/gruvbox-dark.conf similarity index 93% rename from core_lib/data/theme_palettes/Gruvbox_Dark.conf rename to core_lib/data/theme_palettes/gruvbox-dark.conf index dc6dbf7449..9570556d9d 100644 --- a/core_lib/data/theme_palettes/Gruvbox_Dark.conf +++ b/core_lib/data/theme_palettes/gruvbox-dark.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Gruvbox Dark +IsDark=true + [ColorScheme] active_colors=#ffebdbb2, #ff1d2021, #ffbdae93, #ffa89984, #ff3c3836, #ff504945, #ffebdbb2, #ffebdbb2, #ffebdbb2, #ff282828, #ff1d2021, #ff504945, #ff458588, #ff282828, #ff458588, #ffcc241d, #ff282828, #ffebdbb2, #ff1d2021, #ffebdbb2, #ffbdae93 disabled_colors=#ffbdae93, #ff1d2021, #ffbdae93, #ffa89984, #ff3c3836, #ff504945, #ffbdae93, #ffbdae93, #ffbdae93, #ff282828, #ff1d2021, #ff504945, #ff438184, #ff3c3836, #ff458588, #ffcc241d, #ff282828, #ffebdbb2, #ff1d2021, #ffebdbb2, #ffbdae93 diff --git a/core_lib/data/theme_palettes/Gruvbox_Light.conf b/core_lib/data/theme_palettes/gruvbox-light.conf similarity index 93% rename from core_lib/data/theme_palettes/Gruvbox_Light.conf rename to core_lib/data/theme_palettes/gruvbox-light.conf index a363a2ff88..5aa3a0a969 100644 --- a/core_lib/data/theme_palettes/Gruvbox_Light.conf +++ b/core_lib/data/theme_palettes/gruvbox-light.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Gruvbox Light +IsDark=false + [ColorScheme] active_colors=#ff504945, #ffebdbb2, #ff665c54, #ff7c6f64, #ffd5c4a1, #ffbdae93, #ff3c3836, #ff3c3836, #ff3c3836, #fffbf1c7, #fffbf1c7, #ffa89984, #ff458588, #fffbf1c7, #ff458588, #ffcc241d, #ffebdbb2, #ff3c3836, #ffebdbb2, #ff3c3836, #ff928374 disabled_colors=#ff665c54, #ffebdbb2, #ff665c54, #ff7c6f64, #ffd5c4a1, #ffbdae93, #ff665c54, #ff665c54, #ff665c54, #fffbf1c7, #fffbf1c7, #ffa79883, #ffbdae93, #ff504945, #ff458588, #ffbd211b, #ffebdbb2, #ff3c3836, #ffebdbb2, #ff3c3836, #ff928374 diff --git a/core_lib/data/theme_palettes/Ia_Ora.conf b/core_lib/data/theme_palettes/ia-ora.conf similarity index 94% rename from core_lib/data/theme_palettes/Ia_Ora.conf rename to core_lib/data/theme_palettes/ia-ora.conf index 7875fc4d05..80637286f4 100644 --- a/core_lib/data/theme_palettes/Ia_Ora.conf +++ b/core_lib/data/theme_palettes/ia-ora.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Ia Ora +IsDark=false + [ColorScheme] active_colors=#ff000000, #ffeff3f7, #ffffffff, #ffe9e7e3, #ffc7cbce, #ffa0a0a4, #ff000000, #ffffffff, #ff000000, #ffeff3f7, #ffeff3f7, #ffb8bbbe, #ff4965ae, #ffffffff, #ff0000ff, #ffff00ff, #ffeff3f7, #ff000000, #ffffffdc, #ff000000, #80000000 disabled_colors=#ff808080, #ffeff3f7, #ffffffff, #ffe9e7e3, #ffc7cbce, #ffa0a0a4, #ff808080, #ffffffff, #ff808080, #ffeff3f7, #ffeff3f7, #ffb8bbbe, #ff4965ae, #ff808080, #ff0000ff, #ffff00ff, #ffeff3f7, #ff000000, #ffffffdc, #ff000000, #80000000 diff --git a/core_lib/data/theme_palettes/Latte.conf b/core_lib/data/theme_palettes/latte.conf similarity index 94% rename from core_lib/data/theme_palettes/Latte.conf rename to core_lib/data/theme_palettes/latte.conf index 42db9c58f3..480a8b00b5 100644 --- a/core_lib/data/theme_palettes/Latte.conf +++ b/core_lib/data/theme_palettes/latte.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Latt\x0E9 +IsDark=false + [ColorScheme] active_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff1e66f5, #ffeff1f5, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1 disabled_colors=#ff6c6f85, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff6c6f85, #ff6c6f85, #ff6c6f85, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff9ca0b0, #ff5c5f77, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1 diff --git a/core_lib/data/theme_palettes/Macchiato.conf b/core_lib/data/theme_palettes/macchiato.conf similarity index 94% rename from core_lib/data/theme_palettes/Macchiato.conf rename to core_lib/data/theme_palettes/macchiato.conf index fdae012c1c..757bac28ee 100644 --- a/core_lib/data/theme_palettes/Macchiato.conf +++ b/core_lib/data/theme_palettes/macchiato.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Macchiato +IsDark=true + [ColorScheme] active_colors=#ffcad3f5, #ff1e2030, #ffa5adcb, #ff939ab7, #ff494d64, #ff6e738d, #ffcad3f5, #ffcad3f5, #ffcad3f5, #ff24273a, #ff1e2030, #ff8087a2, #ff8aadf4, #ff24273a, #ff8aadf4, #ffed8796, #ff24273a, #ffcad3f5, #ff181926, #ffcad3f5, #808087a2 disabled_colors=#ffa5adcb, #ff1e2030, #ffa5adcb, #ff939ab7, #ff494d64, #ff6e738d, #ffa5adcb, #ffa5adcb, #ffa5adcb, #ff24273a, #ff1e2030, #ff8087a2, #ff8aadf4, #ff494d64, #ff8aadf4, #ffed8796, #ff24273a, #ffcad3f5, #ff181926, #ffcad3f5, #808087a2 diff --git a/core_lib/data/theme_palettes/Mocha.conf b/core_lib/data/theme_palettes/mocha.conf similarity index 94% rename from core_lib/data/theme_palettes/Mocha.conf rename to core_lib/data/theme_palettes/mocha.conf index e566a63073..5f2b9a14ad 100644 --- a/core_lib/data/theme_palettes/Mocha.conf +++ b/core_lib/data/theme_palettes/mocha.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Mocha +IsDark=true + [ColorScheme] active_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ff1e1e2e, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c disabled_colors=#ffa6adc8, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffa6adc8, #ffa6adc8, #ffa6adc8, #ff1e1e2e, #ff11111b, #ff7f849c, #ff89b4fa, #ff45475a, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c diff --git a/core_lib/data/theme_palettes/Rose_Pine.conf b/core_lib/data/theme_palettes/rose-pine.conf similarity index 93% rename from core_lib/data/theme_palettes/Rose_Pine.conf rename to core_lib/data/theme_palettes/rose-pine.conf index 4c557492ed..e42cfc0b73 100644 --- a/core_lib/data/theme_palettes/Rose_Pine.conf +++ b/core_lib/data/theme_palettes/rose-pine.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Ros\x0E9 Pine +IsDark=true + [ColorScheme] active_colors=#ffe0def4, #ff26233a, #ff524f67, #ff403d52, #ff21202e, #ff26233a, #ff6e6a86, #ffeb6f92, #ffebbcba, #ff26233a, #ff191724, #ff26233a, #ff524f67, #fff6c177, #ff9ccfd8, #ffc4a7e7, #ff1a1c1e, #ff000000, #ff21202e, #ff908caa, #809e9e9e disabled_colors=#ffebbcba, #ff1f1d2e, #ff524f67, #ff403d52, #ff21202e, #ff26233a, #ff6e6a86, #ffeb6f92, #ffebbcba, #ff26233a, #ff191724, #ff26233a, #ff403d52, #ff524f67, #ff908caa, #ff524f67, #ff1a1c1e, #ff000000, #ff21202e, #ff9ccfd8, #809e9e9e diff --git a/core_lib/data/theme_palettes/Waves.conf b/core_lib/data/theme_palettes/waves.conf similarity index 94% rename from core_lib/data/theme_palettes/Waves.conf rename to core_lib/data/theme_palettes/waves.conf index e0de92fd6b..f4f1b49c88 100644 --- a/core_lib/data/theme_palettes/Waves.conf +++ b/core_lib/data/theme_palettes/waves.conf @@ -1,3 +1,7 @@ +[Metadata] +DisplayName=Waves +IsDark=true + [ColorScheme] active_colors=#ffb0b0b0, #ff010b2c, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffb0b0b0, #ffb0b0b0, #ffb0b0b0, #ff010b2c, #ff010b2c, #ffb0b0b0, #ff302f2e, #ffb0b0b0, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff0a0a0a, #ffffffff, #80b0b0b0 disabled_colors=#ff808080, #ff010b2c, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ff808080, #ff808080, #ff808080, #ff00071d, #ff00071d, #ffb0b0b0, #ff00071d, #ff808080, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff0a0a0a, #ffffffff, #80b0b0b0 diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index 4e9af0f582..823a317907 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -26,26 +26,29 @@ QStringList Theming::availableStyles() /** * Get a list of all valid keys that can be passed to Theming::getPalette(). * - * This list is generated by finding all palette configuration files in the - * standard search path and removing any that cannot be validated. + * This list is generated by finding all built-in palettes, and all .conf + * files in the user's palette directory. This may include invalid palettes. + * Filter using ThemeColorPalette::isValid if only valid palettes are required. * - * @return A list of string keys. + * @return A list of loaded palettes. * @see getPalette() */ -QStringList Theming::availablePalettes() +QList Theming::availablePalettes() { - QStringList palettes; + QList palettes; // Built-in palettes - for (const QString& palette : QDir(":/theme_palettes").entryList({"*.conf"}, QDir::Files)) + QDir builtinDir(":/theme_palettes"); + for (const QString& palettePath : builtinDir.entryList({"*.conf"}, QDir::Files)) { - palettes.append(palette.chopped(5)); + palettes.append(builtinDir.filePath(palettePath)); } // User palettes - for (const QString& palette : userPaletteDir().entryList({"*.conf"}, QDir::Files)) + QDir userDir = userPaletteDir(); + for (const QString& palettePath : userDir.entryList({"*.conf"}, QDir::Files)) { - palettes.append(palette.chopped(5)); + palettes.append(userDir.filePath(palettePath)); } return palettes; @@ -69,32 +72,43 @@ QStyle* Theming::getStyle(const QString& key) * Fetch a palette with a given key. * * @param key A palette identifier. - * @return A QPalette instance corresponding to the given key. If no palette with the key exists, - * or the conf file for the palette is invalid, a null pointer will be returned. + * @return A loaded palette corresponding to the given key. If no palette with the key exists, + * or the conf file for the palette is invalid, an invalid palette will be returned. * @see availablePalettes() */ -QPalette* Theming::getPalette(const QString& key) +ThemeColorPalette Theming::getPalette(const QString& key) { - QPalette* builtinPalette = loadPaletteConf(QString(":/theme_palettes/%1.conf").arg(key)); - if (builtinPalette != nullptr) return builtinPalette; - - return loadPaletteConf(userPaletteDir().filePath(QString("%1.conf").arg(key))); + if (key.startsWith("builtin-")) + { + return ThemeColorPalette(QString(":/theme_palettes/%1.conf").arg(key.mid(8))); + } + else if (key.startsWith("user-")) + { + return ThemeColorPalette(userPaletteDir().filePath(QString("%1.conf").arg(key.mid(5)))); + } + return ThemeColorPalette(); } /** * Saves a palette to the user's palette directory. * - * @param filepath The path to a .conf palette file to load. + * @param filePath The path to a .conf palette file to load. * @return A Status indicating if the palette was added successfully. */ -Status Theming::addPalette(const QString &filePath) +Status Theming::addPalette(const QString& filePath) { + // Perform some basic checks to provide more detailed errors if (!filePath.endsWith(".conf")) return Status::INVALID_ARGUMENT; QFileInfo fileInfo(filePath); if (fileInfo.baseName().isEmpty()) return Status::INVALID_ARGUMENT; if (!fileInfo.isFile()) return Status::FILE_NOT_FOUND; if (!fileInfo.isReadable()) return Status::ERROR_FILE_CANNOT_OPEN; + // Attempt to construct the palette and verify that it is valid + ThemeColorPalette palette(filePath); + if (!palette.isValid()) return Status::FAIL; + + // Copy to the user's palette directory QFile inFile(filePath); if (inFile.copy(userPaletteDir().filePath(fileInfo.fileName()))) { @@ -113,7 +127,9 @@ Status Theming::addPalette(const QString &filePath) */ Status Theming::removePalette(const QString& key) { - QFile paletteFile(userPaletteDir().filePath(QString("%1.conf").arg(key))); + if (!key.startsWith("user-")) return Status::FAIL; + + QFile paletteFile(userPaletteDir().filePath(QString("%1.conf").arg(key.mid(5)))); if (paletteFile.remove()) { return Status::OK; @@ -121,6 +137,24 @@ Status Theming::removePalette(const QString& key) return Status::FAIL; } +/** + * Convenience function to get the user palette dir. + * + * @return The path to the directory to write user added palettes to. + */ +const QDir Theming::userPaletteDir() +{ + QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + dir.cd("theme_palettes"); + + return dir; +} + +ThemeColorPalette::ThemeColorPalette(const QString& filePath) +{ + loadFromFile(filePath); +} + /** * Create a QPalette instance from a .conf palette file. * @@ -131,10 +165,41 @@ Status Theming::removePalette(const QString& key) * @param filename The path to the .conf file to load. * @return A QPalette instance with the color set from the .conf or nullptr if the file cannot be loaded or is not valid. */ -QPalette* Theming::loadPaletteConf(const QString& filename) +bool ThemeColorPalette::loadFromFile(const QString& filePath) { - QPalette palette; - QSettings conf(filename, QSettings::IniFormat); + m_valid = tryLoad(filePath); + return m_valid; +} + +QString ThemeColorPalette::id() const +{ + QFileInfo fileInfo(m_filePath); + return fileInfo.baseName().prepend(isBuiltIn() ? "builtin-" : "user-"); +} + +/** + * Private implementation of loadFromFile. + * + * @see ThemeColorPalette::loadFromFile + */ +bool ThemeColorPalette::tryLoad(const QString& filePath) +{ + m_valid = false; + m_filePath = filePath; + + if (!filePath.endsWith(".conf")) return false; + QFileInfo fileInfo(filePath); + if (fileInfo.baseName().isEmpty()) return false; + //if (!fileInfo.isFile()) return false; + if (!fileInfo.isReadable()) return false; + + QSettings conf(filePath, QSettings::IniFormat); + + conf.beginGroup("Metadata"); + m_displayName = conf.value("DisplayName", fileInfo.baseName()).toString(); + m_isDark = conf.value("IsDark", false).toBool(); + conf.endGroup(); + conf.beginGroup("ColorScheme"); QList> colorGroups = { { QPalette::Active, "active_colors" }, @@ -145,21 +210,14 @@ QPalette* Theming::loadPaletteConf(const QString& filename) { QStringList colors = conf.value(colorGroup.second).toStringList(); // 20 is QPalette::NColorRoles prior to Qt 5.12, and is the minimum number of colors required for this format. - if (colors.count() < 20) return nullptr; + if (colors.count() < 20) return false; for (int i = 0; i < qMin(colors.count(), static_cast(QPalette::NColorRoles)); i++) { - palette.setColor(colorGroup.first, QPalette::ColorRole(i), colors[i]); + m_palette.setColor(colorGroup.first, QPalette::ColorRole(i), colors[i]); } } + conf.endGroup(); - return new QPalette(palette); -} - -const QDir Theming::userPaletteDir() -{ - QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); - dir.cd("theme_palettes"); - - return dir; + return true; } diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h index a9293f177d..54ad2948f2 100644 --- a/core_lib/src/util/theming.h +++ b/core_lib/src/util/theming.h @@ -1,20 +1,22 @@ #ifndef THEMING_H #define THEMING_H +#include + class QDir; class QStyle; -class QPalette; class Status; +class ThemeColorPalette; class Theming { public: static QStringList availableStyles(); - static QStringList availablePalettes(); + static QList availablePalettes(); static QStyle* getStyle(const QString& key); - static QPalette* getPalette(const QString& key); + static ThemeColorPalette getPalette(const QString& key); static Status addPalette(const QString& filePath); static Status removePalette(const QString& key); @@ -24,4 +26,28 @@ class Theming static const QDir userPaletteDir(); }; +class ThemeColorPalette +{ +public: + ThemeColorPalette() {} + ThemeColorPalette(const QString& filePath); + + bool loadFromFile(const QString& filePath); + + bool isValid() const { return m_valid; } + QString id() const; + QString displayName() const { return m_displayName; } + QPalette palette() const { return m_valid ? m_palette : QPalette(); } + bool isDark() const { return m_valid ? m_isDark : false; } + bool isBuiltIn() const { return m_filePath.startsWith(':'); } +private: + bool tryLoad(const QString& filePath); + + bool m_valid = false; + QString m_filePath; + QString m_displayName; + QPalette m_palette; + bool m_isDark; +}; + #endif // THEMING_H From 31ba83c4014b3e9911d0609bf8f8813d45d71a4c Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Tue, 5 Nov 2024 00:34:22 -0700 Subject: [PATCH 07/10] Automatically detect if color palette is dark if not specified --- core_lib/data/theme_palettes/arc-dark.conf | 2 +- core_lib/data/theme_palettes/arc-light.conf | 2 +- core_lib/data/theme_palettes/darker.conf | 2 +- core_lib/data/theme_palettes/frappe.conf | 2 +- .../data/theme_palettes/gruvbox-dark.conf | 2 +- .../data/theme_palettes/gruvbox-light.conf | 2 +- core_lib/data/theme_palettes/ia-ora.conf | 2 +- core_lib/data/theme_palettes/latte.conf | 2 +- core_lib/data/theme_palettes/macchiato.conf | 2 +- core_lib/data/theme_palettes/mocha.conf | 2 +- core_lib/data/theme_palettes/rose-pine.conf | 2 +- core_lib/data/theme_palettes/waves.conf | 2 +- core_lib/src/util/theming.cpp | 20 ++++++++++++++++++- core_lib/src/util/theming.h | 10 ++++++++-- 14 files changed, 39 insertions(+), 15 deletions(-) diff --git a/core_lib/data/theme_palettes/arc-dark.conf b/core_lib/data/theme_palettes/arc-dark.conf index 1e65dfdb0d..26529d2dc0 100644 --- a/core_lib/data/theme_palettes/arc-dark.conf +++ b/core_lib/data/theme_palettes/arc-dark.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Arc Dark -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffffff, #383C4A, #979797, #5e5c5b, #302f2e, #4a4947, #ffffff, #ffffff, #ffffff, #3d3d3d, #2F343F, #e7e4e0, #5294e2, #f9f9f9, #5294e2, #a70b06, #5c5b5a, #ffffff, #3f3f36, #ffffff diff --git a/core_lib/data/theme_palettes/arc-light.conf b/core_lib/data/theme_palettes/arc-light.conf index 3047fc3f54..8231775c56 100644 --- a/core_lib/data/theme_palettes/arc-light.conf +++ b/core_lib/data/theme_palettes/arc-light.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Arc Light -IsDark=false +LightOrDark=light [ColorScheme] active_colors=#000000, #F5F6F7, #ffffff, #F3F3F3, #9f9d9a, #b8b5b2, #000000, #ffffff, #000000, #ffffff, #E7E8EB, #b1aeab, #5492DF, #ffffff, #0000ff, #ff0000, #f7f5f3, #000000, #ffffdc, #000000 diff --git a/core_lib/data/theme_palettes/darker.conf b/core_lib/data/theme_palettes/darker.conf index 87fdc802bd..a63d982180 100644 --- a/core_lib/data/theme_palettes/darker.conf +++ b/core_lib/data/theme_palettes/darker.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Darker -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffffffff, #ff424245, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffffffff, #ffffffff, #ffffffff, #ff3d3d3d, #ff222020, #ffe7e4e0, #ff12608a, #fff9f9f9, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff3f3f36, #ffffffff, #80ffffff diff --git a/core_lib/data/theme_palettes/frappe.conf b/core_lib/data/theme_palettes/frappe.conf index 18601de758..c2afafd5ac 100644 --- a/core_lib/data/theme_palettes/frappe.conf +++ b/core_lib/data/theme_palettes/frappe.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Frappe -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffc6d0f5, #ff292c3c, #ffa5adce, #ff949cbb, #ff51576d, #ff737994, #ffc6d0f5, #ffc6d0f5, #ffc6d0f5, #ff303446, #ff292c3c, #ff838ba7, #ff8caaee, #ff303446, #ff8caaee, #ffe78284, #ff303446, #ffc6d0f5, #ff232634, #ffc6d0f5, #80838ba7 diff --git a/core_lib/data/theme_palettes/gruvbox-dark.conf b/core_lib/data/theme_palettes/gruvbox-dark.conf index 9570556d9d..e39afdf8bb 100644 --- a/core_lib/data/theme_palettes/gruvbox-dark.conf +++ b/core_lib/data/theme_palettes/gruvbox-dark.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Gruvbox Dark -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffebdbb2, #ff1d2021, #ffbdae93, #ffa89984, #ff3c3836, #ff504945, #ffebdbb2, #ffebdbb2, #ffebdbb2, #ff282828, #ff1d2021, #ff504945, #ff458588, #ff282828, #ff458588, #ffcc241d, #ff282828, #ffebdbb2, #ff1d2021, #ffebdbb2, #ffbdae93 diff --git a/core_lib/data/theme_palettes/gruvbox-light.conf b/core_lib/data/theme_palettes/gruvbox-light.conf index 5aa3a0a969..363cfdcef3 100644 --- a/core_lib/data/theme_palettes/gruvbox-light.conf +++ b/core_lib/data/theme_palettes/gruvbox-light.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Gruvbox Light -IsDark=false +LightOrDark=light [ColorScheme] active_colors=#ff504945, #ffebdbb2, #ff665c54, #ff7c6f64, #ffd5c4a1, #ffbdae93, #ff3c3836, #ff3c3836, #ff3c3836, #fffbf1c7, #fffbf1c7, #ffa89984, #ff458588, #fffbf1c7, #ff458588, #ffcc241d, #ffebdbb2, #ff3c3836, #ffebdbb2, #ff3c3836, #ff928374 diff --git a/core_lib/data/theme_palettes/ia-ora.conf b/core_lib/data/theme_palettes/ia-ora.conf index 80637286f4..989164ee34 100644 --- a/core_lib/data/theme_palettes/ia-ora.conf +++ b/core_lib/data/theme_palettes/ia-ora.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Ia Ora -IsDark=false +LightOrDark=light [ColorScheme] active_colors=#ff000000, #ffeff3f7, #ffffffff, #ffe9e7e3, #ffc7cbce, #ffa0a0a4, #ff000000, #ffffffff, #ff000000, #ffeff3f7, #ffeff3f7, #ffb8bbbe, #ff4965ae, #ffffffff, #ff0000ff, #ffff00ff, #ffeff3f7, #ff000000, #ffffffdc, #ff000000, #80000000 diff --git a/core_lib/data/theme_palettes/latte.conf b/core_lib/data/theme_palettes/latte.conf index 480a8b00b5..e150585dcc 100644 --- a/core_lib/data/theme_palettes/latte.conf +++ b/core_lib/data/theme_palettes/latte.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Latt\x0E9 -IsDark=false +LightOrDark=light [ColorScheme] active_colors=#ff4c4f69, #ffe6e9ef, #ff6c6f85, #ff7c7f93, #ffbcc0cc, #ff9ca0b0, #ff4c4f69, #ff4c4f69, #ff4c4f69, #ffeff1f5, #ffe6e9ef, #ff8c8fa1, #ff1e66f5, #ffeff1f5, #ff7287fd, #ffe64553, #ffeff1f5, #ff4c4f69, #ffdce0e8, #ff4c4f69, #808c8fa1 diff --git a/core_lib/data/theme_palettes/macchiato.conf b/core_lib/data/theme_palettes/macchiato.conf index 757bac28ee..71bc51cadc 100644 --- a/core_lib/data/theme_palettes/macchiato.conf +++ b/core_lib/data/theme_palettes/macchiato.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Macchiato -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffcad3f5, #ff1e2030, #ffa5adcb, #ff939ab7, #ff494d64, #ff6e738d, #ffcad3f5, #ffcad3f5, #ffcad3f5, #ff24273a, #ff1e2030, #ff8087a2, #ff8aadf4, #ff24273a, #ff8aadf4, #ffed8796, #ff24273a, #ffcad3f5, #ff181926, #ffcad3f5, #808087a2 diff --git a/core_lib/data/theme_palettes/mocha.conf b/core_lib/data/theme_palettes/mocha.conf index 5f2b9a14ad..f895a0e9f6 100644 --- a/core_lib/data/theme_palettes/mocha.conf +++ b/core_lib/data/theme_palettes/mocha.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Mocha -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffcdd6f4, #ff1e1e2e, #ffa6adc8, #ff9399b2, #ff45475a, #ff6c7086, #ffcdd6f4, #ffcdd6f4, #ffcdd6f4, #ff1e1e2e, #ff181825, #ff7f849c, #ff89b4fa, #ff1e1e2e, #ff89b4fa, #fff38ba8, #ff1e1e2e, #ffcdd6f4, #ff11111b, #ffcdd6f4, #807f849c diff --git a/core_lib/data/theme_palettes/rose-pine.conf b/core_lib/data/theme_palettes/rose-pine.conf index e42cfc0b73..86e9dc2b90 100644 --- a/core_lib/data/theme_palettes/rose-pine.conf +++ b/core_lib/data/theme_palettes/rose-pine.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Ros\x0E9 Pine -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffe0def4, #ff26233a, #ff524f67, #ff403d52, #ff21202e, #ff26233a, #ff6e6a86, #ffeb6f92, #ffebbcba, #ff26233a, #ff191724, #ff26233a, #ff524f67, #fff6c177, #ff9ccfd8, #ffc4a7e7, #ff1a1c1e, #ff000000, #ff21202e, #ff908caa, #809e9e9e diff --git a/core_lib/data/theme_palettes/waves.conf b/core_lib/data/theme_palettes/waves.conf index f4f1b49c88..0d3adfce10 100644 --- a/core_lib/data/theme_palettes/waves.conf +++ b/core_lib/data/theme_palettes/waves.conf @@ -1,6 +1,6 @@ [Metadata] DisplayName=Waves -IsDark=true +LightOrDark=dark [ColorScheme] active_colors=#ffb0b0b0, #ff010b2c, #ff979797, #ff5e5c5b, #ff302f2e, #ff4a4947, #ffb0b0b0, #ffb0b0b0, #ffb0b0b0, #ff010b2c, #ff010b2c, #ffb0b0b0, #ff302f2e, #ffb0b0b0, #ff0986d3, #ffa70b06, #ff5c5b5a, #ffffffff, #ff0a0a0a, #ffffffff, #80b0b0b0 diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index 823a317907..ca842b0109 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -177,6 +177,19 @@ QString ThemeColorPalette::id() const return fileInfo.baseName().prepend(isBuiltIn() ? "builtin-" : "user-"); } +bool ThemeColorPalette::isDark() const +{ + if (!m_valid) return false; + + if (m_mode == Mode::Unknown) + { + // Guess the mode based on the lightness of the background color + QColor backgroundColor = m_palette.color(QPalette::Normal, QPalette::Window); + return backgroundColor.lightnessF() < 0.5; + } + return m_mode == Mode::Dark; +} + /** * Private implementation of loadFromFile. * @@ -197,7 +210,12 @@ bool ThemeColorPalette::tryLoad(const QString& filePath) conf.beginGroup("Metadata"); m_displayName = conf.value("DisplayName", fileInfo.baseName()).toString(); - m_isDark = conf.value("IsDark", false).toBool(); + + QString modeStr = conf.value("LightOrDark").toString().toLower(); + if (modeStr == "light") m_mode = Mode::Light; + else if (modeStr == "dark") m_mode = Mode::Dark; + else m_mode = Mode::Unknown; + conf.endGroup(); conf.beginGroup("ColorScheme"); diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h index 54ad2948f2..765f5563a7 100644 --- a/core_lib/src/util/theming.h +++ b/core_lib/src/util/theming.h @@ -38,16 +38,22 @@ class ThemeColorPalette QString id() const; QString displayName() const { return m_displayName; } QPalette palette() const { return m_valid ? m_palette : QPalette(); } - bool isDark() const { return m_valid ? m_isDark : false; } + bool isDark() const; bool isBuiltIn() const { return m_filePath.startsWith(':'); } private: + enum Mode { + Light, + Dark, + Unknown + }; + bool tryLoad(const QString& filePath); bool m_valid = false; QString m_filePath; QString m_displayName; QPalette m_palette; - bool m_isDark; + Mode m_mode; }; #endif // THEMING_H From 83abb027482288d32f856f26741b9536a9f183b5 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Tue, 5 Nov 2024 02:22:37 -0700 Subject: [PATCH 08/10] Show error dialogs when palette actions fail --- app/src/generalpage.cpp | 17 +++++++++++++++-- core_lib/src/util/theming.cpp | 32 ++++++++++++++++++++++---------- core_lib/src/util/theming.h | 2 ++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index 06ea84c2c2..37356ca9dd 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -23,6 +23,7 @@ GNU General Public License for more details. #include #include +#include "errordialog.h" #include "filedialog.h" #include "pencildef.h" #include "preferencemanager.h" @@ -287,22 +288,34 @@ void GeneralPage::addPalette() if (!filePath.isEmpty()) { QFileInfo fileInfo(filePath); - if (Theming::addPalette(filePath).ok()) + Status st = Theming::addPalette(filePath); + if (st.ok()) { mManager->set(SETTING::PALETTE_ID, fileInfo.baseName()); populatePaletteCombo(); } + else + { + ErrorDialog errorDialog(st.title(), st.description(), st.details().html()); + errorDialog.exec(); + } } } void GeneralPage::removePalette() { QString key = ui->paletteCombo->currentData().toString(); - if (Theming::removePalette(key).ok()) + Status st = Theming::removePalette(key); + if (st.ok()) { ui->paletteCombo->removeItem(ui->paletteCombo->currentIndex()); ui->paletteCombo->setCurrentIndex(0); } + else + { + ErrorDialog errorDialog(st.title(), st.description(), st.details().html()); + errorDialog.exec(); + } } void GeneralPage::shadowsCheckboxStateChanged(int b) diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index ca842b0109..6ba5edaab0 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -97,24 +97,30 @@ ThemeColorPalette Theming::getPalette(const QString& key) */ Status Theming::addPalette(const QString& filePath) { + DebugDetails dd; + dd << QString("Raw file path: %1").arg(filePath); + QString errorTitle = QCoreApplication::translate("Theming", "Unable to load color palette"); + // Perform some basic checks to provide more detailed errors - if (!filePath.endsWith(".conf")) return Status::INVALID_ARGUMENT; + if (!filePath.endsWith(".conf")) return Status(Status::INVALID_ARGUMENT, dd, errorTitle, QCoreApplication::translate("Theming", "Color palette file is the wrong format. Only .ini files are accepted.")); QFileInfo fileInfo(filePath); - if (fileInfo.baseName().isEmpty()) return Status::INVALID_ARGUMENT; - if (!fileInfo.isFile()) return Status::FILE_NOT_FOUND; - if (!fileInfo.isReadable()) return Status::ERROR_FILE_CANNOT_OPEN; + if (fileInfo.baseName().isEmpty()) return Status(Status::INVALID_ARGUMENT, dd, errorTitle, QCoreApplication::translate("Theming", "The filename cannot be empty.")); + if (!fileInfo.isFile()) return Status(Status::FILE_NOT_FOUND, dd, errorTitle, QCoreApplication::translate("Theming", "File not found or cannot be read.")); + if (!fileInfo.isReadable()) return Status(Status::ERROR_FILE_CANNOT_OPEN, dd, errorTitle, QCoreApplication::translate("Theming", "File not found or cannot be read.")); // Attempt to construct the palette and verify that it is valid ThemeColorPalette palette(filePath); - if (!palette.isValid()) return Status::FAIL; + if (!palette.isValid()) return Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "Cannot load color palette, the file is not in the correct format or contains errors.")); // Copy to the user's palette directory QFile inFile(filePath); - if (inFile.copy(userPaletteDir().filePath(fileInfo.fileName()))) + QString destPath = userPaletteDir().filePath(fileInfo.fileName()); + dd << QString("Palette save path: %1").arg(destPath); + if (inFile.copy(destPath)) { return Status::OK; } - return Status::FAIL; + return Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "An internal error occurred and the palette could not be saved.")); } /** @@ -127,14 +133,20 @@ Status Theming::addPalette(const QString& filePath) */ Status Theming::removePalette(const QString& key) { - if (!key.startsWith("user-")) return Status::FAIL; + DebugDetails dd; + dd << QString("Palette key: %1").arg(key); + QString errorTitle = QCoreApplication::translate("Theming", "Unable to delete color palette"); + + if (!key.startsWith("user-")) return Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "This palette is built-in and cannot be deleted.")); - QFile paletteFile(userPaletteDir().filePath(QString("%1.conf").arg(key.mid(5)))); + QString destPath = userPaletteDir().filePath(QString("%1.conf").arg(key.mid(5))); + dd << QString("Palette path: %1").arg(destPath); + QFile paletteFile(destPath); if (paletteFile.remove()) { return Status::OK; } - return Status::FAIL; + return Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "Unable to delete palette file.")); } /** diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h index 765f5563a7..45e62cbd1c 100644 --- a/core_lib/src/util/theming.h +++ b/core_lib/src/util/theming.h @@ -20,6 +20,7 @@ class Theming static Status addPalette(const QString& filePath); static Status removePalette(const QString& key); + private: static QPalette* loadPaletteConf(const QString& filename); @@ -40,6 +41,7 @@ class ThemeColorPalette QPalette palette() const { return m_valid ? m_palette : QPalette(); } bool isDark() const; bool isBuiltIn() const { return m_filePath.startsWith(':'); } + private: enum Mode { Light, From 8348d7451c27d7a08c05b4a28ef026fd11d606c7 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Tue, 5 Nov 2024 03:02:40 -0700 Subject: [PATCH 09/10] Add counter to filename to handle duplicate palette ids --- app/src/generalpage.cpp | 6 ++++-- core_lib/src/util/theming.cpp | 32 +++++++++++++++++++++----------- core_lib/src/util/theming.h | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index 37356ca9dd..dfbf31a618 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -288,10 +288,12 @@ void GeneralPage::addPalette() if (!filePath.isEmpty()) { QFileInfo fileInfo(filePath); - Status st = Theming::addPalette(filePath); + auto result = Theming::addPalette(filePath); + Status st = result.first; + ThemeColorPalette newPalette = result.second; if (st.ok()) { - mManager->set(SETTING::PALETTE_ID, fileInfo.baseName()); + mManager->set(SETTING::PALETTE_ID, newPalette.id()); populatePaletteCombo(); } else diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index 6ba5edaab0..10e6c76b82 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -93,34 +93,44 @@ ThemeColorPalette Theming::getPalette(const QString& key) * Saves a palette to the user's palette directory. * * @param filePath The path to a .conf palette file to load. - * @return A Status indicating if the palette was added successfully. + * @return A Status indicating if the palette was added successfully, and the new + * palette if successful. */ -Status Theming::addPalette(const QString& filePath) +std::pair Theming::addPalette(const QString& filePath) { + ThemeColorPalette palette; DebugDetails dd; dd << QString("Raw file path: %1").arg(filePath); QString errorTitle = QCoreApplication::translate("Theming", "Unable to load color palette"); // Perform some basic checks to provide more detailed errors - if (!filePath.endsWith(".conf")) return Status(Status::INVALID_ARGUMENT, dd, errorTitle, QCoreApplication::translate("Theming", "Color palette file is the wrong format. Only .ini files are accepted.")); + if (!filePath.endsWith(".conf")) return { Status(Status::INVALID_ARGUMENT, dd, errorTitle, QCoreApplication::translate("Theming", "Color palette file is the wrong format. Only .ini files are accepted.")), palette }; QFileInfo fileInfo(filePath); - if (fileInfo.baseName().isEmpty()) return Status(Status::INVALID_ARGUMENT, dd, errorTitle, QCoreApplication::translate("Theming", "The filename cannot be empty.")); - if (!fileInfo.isFile()) return Status(Status::FILE_NOT_FOUND, dd, errorTitle, QCoreApplication::translate("Theming", "File not found or cannot be read.")); - if (!fileInfo.isReadable()) return Status(Status::ERROR_FILE_CANNOT_OPEN, dd, errorTitle, QCoreApplication::translate("Theming", "File not found or cannot be read.")); + if (fileInfo.baseName().isEmpty()) return { Status(Status::INVALID_ARGUMENT, dd, errorTitle, QCoreApplication::translate("Theming", "The filename cannot be empty.")), palette }; + if (!fileInfo.isFile()) return { Status(Status::FILE_NOT_FOUND, dd, errorTitle, QCoreApplication::translate("Theming", "File not found or cannot be read.")), palette }; + if (!fileInfo.isReadable()) return { Status(Status::ERROR_FILE_CANNOT_OPEN, dd, errorTitle, QCoreApplication::translate("Theming", "File not found or cannot be read.")), palette }; // Attempt to construct the palette and verify that it is valid - ThemeColorPalette palette(filePath); - if (!palette.isValid()) return Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "Cannot load color palette, the file is not in the correct format or contains errors.")); + palette.loadFromFile(filePath); + if (!palette.isValid()) return { Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "Cannot load color palette, the file is not in the correct format or contains errors.")), palette }; // Copy to the user's palette directory QFile inFile(filePath); - QString destPath = userPaletteDir().filePath(fileInfo.fileName()); + QDir destDir = userPaletteDir(); + QString destPath = destDir.filePath(fileInfo.fileName()); + QFileInfo destFileInfo(destPath); + int offset = 0; + while (destFileInfo.exists()) + { + destFileInfo.setFile(destDir.filePath(QString("%1-%2.conf").arg(fileInfo.baseName()).arg(++offset))); + destPath = destFileInfo.absoluteFilePath(); + } dd << QString("Palette save path: %1").arg(destPath); if (inFile.copy(destPath)) { - return Status::OK; + return { Status::OK, ThemeColorPalette(destPath) }; } - return Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "An internal error occurred and the palette could not be saved.")); + return { Status(Status::FAIL, dd, errorTitle, QCoreApplication::translate("Theming", "An internal error occurred and the palette could not be saved.")), palette }; } /** diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h index 45e62cbd1c..a91d9898c9 100644 --- a/core_lib/src/util/theming.h +++ b/core_lib/src/util/theming.h @@ -18,7 +18,7 @@ class Theming static QStyle* getStyle(const QString& key); static ThemeColorPalette getPalette(const QString& key); - static Status addPalette(const QString& filePath); + static std::pair addPalette(const QString& filePath); static Status removePalette(const QString& key); private: From 283a7e75a9371f4b6b08641c90c63113db1caaa4 Mon Sep 17 00:00:00 2001 From: scribblemaniac Date: Thu, 7 Nov 2024 00:57:14 -0700 Subject: [PATCH 10/10] If current palette is missing, still show it in the combo box --- app/src/generalpage.cpp | 38 +++++++++++++++++++++++++++++++---- app/src/generalpage.h | 2 ++ app/ui/generalpage.ui | 10 +++++++++ core_lib/src/util/theming.cpp | 36 +++++++++++++++++++++++++++++---- core_lib/src/util/theming.h | 1 + 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/app/src/generalpage.cpp b/app/src/generalpage.cpp index dfbf31a618..4997014b7b 100644 --- a/app/src/generalpage.cpp +++ b/app/src/generalpage.cpp @@ -86,6 +86,10 @@ GeneralPage::GeneralPage() : ui(new Ui::GeneralPage) ui->languageCombo->addItem(itemText, localeCode); } + QIcon warningIcon = style()->standardIcon(QStyle::SP_MessageBoxWarning); + ui->paletteWarningLabel->setPixmap(warningIcon.pixmap(28, 28)); + ui->paletteWarningLabel->setVisible(false); + int value = settings.value("windowOpacity").toInt(); ui->windowOpacityLevel->setValue(100 - value); @@ -168,8 +172,7 @@ void GeneralPage::updateValues() ui->styleCombo->setCurrentIndex(qMax(0, styleIndex)); QSignalBlocker b20(ui->styleCombo); QString paletteKey = mManager->getString(SETTING::PALETTE_ID); - int paletteIndex = ui->paletteCombo->findData(paletteKey, Qt::UserRole, Qt::MatchFixedString); - ui->paletteCombo->setCurrentIndex(qMax(0, paletteIndex)); + setCurrentPalette(paletteKey); ui->removePaletteButton->setEnabled(!paletteKey.isEmpty() && !Theming::getPalette(paletteKey).isBuiltIn()); QSignalBlocker b3(ui->shadowsBox); ui->shadowsBox->setChecked(mManager->isOn(SETTING::SHADOW)); @@ -280,6 +283,10 @@ void GeneralPage::paletteChanged(int index) QString paletteKey = ui->paletteCombo->itemData(index).toString(); mManager->set(SETTING::PALETTE_ID, paletteKey); ui->removePaletteButton->setEnabled(!paletteKey.isEmpty() && !Theming::getPalette(paletteKey).isBuiltIn()); + if (m_showMissingPalette) + { + ui->paletteWarningLabel->setVisible(index == 1); + } } void GeneralPage::addPalette() @@ -486,6 +493,7 @@ void GeneralPage::populatePaletteCombo(bool usePreference) QSignalBlocker b(ui->paletteCombo); ui->paletteCombo->clear(); + m_showMissingPalette = false; ui->paletteCombo->addItem("Default", ""); ui->paletteCombo->insertSeparator(1); QList palettes = Theming::availablePalettes(); @@ -505,8 +513,30 @@ void GeneralPage::populatePaletteCombo(bool usePreference) if (usePreference) { + setCurrentPalette(mManager->getString(SETTING::PALETTE_ID)); QString paletteKey = mManager->getString(SETTING::PALETTE_ID); - int paletteIndex = ui->paletteCombo->findData(paletteKey, Qt::UserRole, Qt::MatchFixedString); - ui->paletteCombo->setCurrentIndex(qMax(0, paletteIndex)); + } +} + +void GeneralPage::setCurrentPalette(const QString& paletteKey) +{ + int paletteIndex = ui->paletteCombo->findData(paletteKey, Qt::UserRole, Qt::MatchFixedString); + ThemeColorPalette palette = Theming::getPalette(paletteKey); + if (paletteIndex >= 0) + { + ui->paletteCombo->setCurrentIndex(paletteIndex); + } + else if (palette.isValid()) + { + populatePaletteCombo(false); + paletteIndex = ui->paletteCombo->findData(paletteKey, Qt::UserRole, Qt::MatchFixedString); + ui->paletteCombo->setCurrentIndex(paletteIndex); + } + else + { + ui->paletteCombo->insertItem(1, palette.displayName(), paletteKey); + ui->paletteCombo->setCurrentIndex(1); + m_showMissingPalette = true; + ui->paletteWarningLabel->setVisible(true); } } diff --git a/app/src/generalpage.h b/app/src/generalpage.h index 0c04489c5a..dec48f598e 100644 --- a/app/src/generalpage.h +++ b/app/src/generalpage.h @@ -70,12 +70,14 @@ private slots: private: void populatePaletteCombo(bool usePreference = true); + void setCurrentPalette(const QString& paletteKey); bool canApplyOrCancelUndoRedoChanges() const; void updateSafeHelperTextEnabledState(); Ui::GeneralPage* ui = nullptr; PreferenceManager* mManager = nullptr; + bool m_showMissingPalette = false; }; #endif // GENERALPAGE_H diff --git a/app/ui/generalpage.ui b/app/ui/generalpage.ui index 1c2ffbcac6..a5c9630d1c 100644 --- a/app/ui/generalpage.ui +++ b/app/ui/generalpage.ui @@ -122,6 +122,16 @@ + + + + Palette is missing or could not be loaded + + + + + + diff --git a/core_lib/src/util/theming.cpp b/core_lib/src/util/theming.cpp index 10e6c76b82..63da214950 100644 --- a/core_lib/src/util/theming.cpp +++ b/core_lib/src/util/theming.cpp @@ -86,7 +86,9 @@ ThemeColorPalette Theming::getPalette(const QString& key) { return ThemeColorPalette(userPaletteDir().filePath(QString("%1.conf").arg(key.mid(5)))); } - return ThemeColorPalette(); + ThemeColorPalette invalidPalette; + invalidPalette.setInvalidWithId(key); + return invalidPalette; } /** @@ -152,7 +154,7 @@ Status Theming::removePalette(const QString& key) QString destPath = userPaletteDir().filePath(QString("%1.conf").arg(key.mid(5))); dd << QString("Palette path: %1").arg(destPath); QFile paletteFile(destPath); - if (paletteFile.remove()) + if (!paletteFile.exists() || paletteFile.remove()) { return Status::OK; } @@ -193,6 +195,30 @@ bool ThemeColorPalette::loadFromFile(const QString& filePath) return m_valid; } +/** + * Sets the id but marks it as invalid. + * + * This function can be used to create a palette with a desired id + * without a valid file path. + * + * @param id + */ +void ThemeColorPalette::setInvalidWithId(const QString& id) +{ + m_valid = false; + m_mode = Mode::Unknown; + if (id.contains('-')) + { + m_filePath = QString("%1.conf").arg(id); + m_displayName = id.mid(id.indexOf('-')); + } + else + { + m_filePath = QString("user-%1.conf").arg(id); + m_displayName = id; + } +} + QString ThemeColorPalette::id() const { QFileInfo fileInfo(m_filePath); @@ -222,8 +248,9 @@ bool ThemeColorPalette::tryLoad(const QString& filePath) m_valid = false; m_filePath = filePath; - if (!filePath.endsWith(".conf")) return false; QFileInfo fileInfo(filePath); + m_displayName = fileInfo.baseName(); + if (!filePath.endsWith(".conf")) return false; if (fileInfo.baseName().isEmpty()) return false; //if (!fileInfo.isFile()) return false; if (!fileInfo.isReadable()) return false; @@ -231,7 +258,7 @@ bool ThemeColorPalette::tryLoad(const QString& filePath) QSettings conf(filePath, QSettings::IniFormat); conf.beginGroup("Metadata"); - m_displayName = conf.value("DisplayName", fileInfo.baseName()).toString(); + m_displayName = conf.value("DisplayName", m_displayName).toString(); QString modeStr = conf.value("LightOrDark").toString().toLower(); if (modeStr == "light") m_mode = Mode::Light; @@ -246,6 +273,7 @@ bool ThemeColorPalette::tryLoad(const QString& filePath) { QPalette::Disabled, "disabled_colors" }, { QPalette::Inactive, "inactive_colors" } }; + m_palette = QPalette(); for (const auto& colorGroup : colorGroups) { QStringList colors = conf.value(colorGroup.second).toStringList(); diff --git a/core_lib/src/util/theming.h b/core_lib/src/util/theming.h index a91d9898c9..4af6ac8f2c 100644 --- a/core_lib/src/util/theming.h +++ b/core_lib/src/util/theming.h @@ -34,6 +34,7 @@ class ThemeColorPalette ThemeColorPalette(const QString& filePath); bool loadFromFile(const QString& filePath); + void setInvalidWithId(const QString& id); bool isValid() const { return m_valid; } QString id() const;