From 7ab7aaf09a41ae415ed3ebf5d77299194c14ccd5 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 26 Feb 2026 22:02:12 +0100 Subject: [PATCH 01/26] Minimum Qt version required is 6.7 --- common/themes/theme_manager.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/common/themes/theme_manager.cpp b/common/themes/theme_manager.cpp index e39554be..094000c2 100644 --- a/common/themes/theme_manager.cpp +++ b/common/themes/theme_manager.cpp @@ -21,8 +21,6 @@ ThemeManager &ThemeManager::instance() void ThemeManager::initialize() { - // QStyleHints::colorScheme is only 6.5+ -#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) auto *styleHints = qGuiApp->styleHints(); auto colorScheme = styleHints->colorScheme(); @@ -35,15 +33,6 @@ void ThemeManager::initialize() applyColorScheme(colorScheme); connect(styleHints, &QStyleHints::colorSchemeChanged, this, applyColorScheme, Qt::QueuedConnection); -#else - auto applyPalette = [this](const QPalette &palette) { - setTheme(palette.color(QPalette::Window).lightness() < 128 ? ThemeId::Dark : ThemeId::Light); - }; - - applyPalette(qGuiApp->palette()); - - connect(qGuiApp, &QGuiApplication::paletteChanged, this, applyPalette, Qt::QueuedConnection); -#endif } void ThemeManager::setTheme(ThemeId themeId) From 392e4a0643086bbbf19a76817dbfacbe46730a61 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Fri, 27 Feb 2026 13:26:25 +0100 Subject: [PATCH 02/26] Move check button svgs paths out from theme params --- YACReaderLibrary/themes/theme_factory.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 5f7c4969..f6fda6ca 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -33,10 +33,8 @@ struct ComicVineParams { QColor buttonTextColor; QColor buttonBorderColor; - QString radioUncheckedPath; QColor radioUncheckedColor; - QString radioCheckedPath; QColor radioCheckedBackgroundColor; QColor radioCheckedIndicatorColor; @@ -335,7 +333,7 @@ Theme makeTheme(const ThemeParams ¶ms) theme.comicVine.defaultLabelQSS = t.defaultLabelQSS.arg(cv.labelTextColor.name()); theme.comicVine.titleLabelQSS = t.titleLabelQSS.arg(cv.labelTextColor.name()); theme.comicVine.coverLabelQSS = t.coverLabelQSS.arg(cv.labelBackgroundColor.name(), cv.labelTextColor.name()); - theme.comicVine.radioButtonQSS = t.radioButtonQSS.arg(cv.buttonTextColor.name(), recolor(cv.radioUncheckedPath, cv.radioUncheckedColor), recoloredSvgToThemeFile(cv.radioCheckedPath, cv.radioCheckedBackgroundColor, cv.radioCheckedIndicatorColor, params.themeName)); + theme.comicVine.radioButtonQSS = t.radioButtonQSS.arg(cv.buttonTextColor.name(), recolor(":/images/comic_vine/radioUnchecked.svg", cv.radioUncheckedColor), recoloredSvgToThemeFile(":/images/comic_vine/radioChecked.svg", cv.radioCheckedBackgroundColor, cv.radioCheckedIndicatorColor, params.themeName)); theme.comicVine.checkBoxQSS = t.checkBoxQSS.arg(cv.buttonTextColor.name(), cv.buttonBorderColor.name(), cv.buttonBackgroundColor.name(), recolor(":/images/comic_vine/checkBoxTick.svg", cv.checkBoxTickColor)); theme.comicVine.scraperLineEditTitleLabelQSS = t.scraperLineEditTitleLabelQSS.arg(cv.contentTextColor.name()); @@ -885,10 +883,8 @@ ThemeParams classicThemeParams() cv.buttonTextColor = Qt::white; cv.buttonBorderColor = QColor(0x242424); - cv.radioUncheckedPath = ":/images/comic_vine/radioUnchecked.svg"; cv.radioUncheckedColor = QColor(0xE5E5E5); - cv.radioCheckedPath = ":/images/comic_vine/radioChecked.svg"; cv.radioCheckedBackgroundColor = QColor(0xE5E5E5); cv.radioCheckedIndicatorColor = QColor(0x5F5F5F); @@ -1140,10 +1136,8 @@ ThemeParams lightThemeParams() cv.buttonTextColor = Qt::black; cv.buttonBorderColor = QColor(0xCCCCCC); - cv.radioUncheckedPath = ":/images/comic_vine/radioUnchecked.svg"; cv.radioUncheckedColor = QColor(0xE0E0E0); - cv.radioCheckedPath = ":/images/comic_vine/radioChecked.svg"; cv.radioCheckedBackgroundColor = QColor(0xE0E0E0); cv.radioCheckedIndicatorColor = QColor(0x222222); @@ -1395,10 +1389,8 @@ ThemeParams darkThemeParams() cv.buttonTextColor = Qt::white; cv.buttonBorderColor = QColor(0x242424); - cv.radioUncheckedPath = ":/images/comic_vine/radioUnchecked.svg"; cv.radioUncheckedColor = QColor(0xE5E5E5); - cv.radioCheckedPath = ":/images/comic_vine/radioChecked.svg"; cv.radioCheckedBackgroundColor = QColor(0xE5E5E5); cv.radioCheckedIndicatorColor = QColor(0x5F5F5F); From 084146995b5eec2c32e1ed5a700970788976773a Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Fri, 27 Feb 2026 15:18:51 +0100 Subject: [PATCH 03/26] Replace the info shadow pngs with svg versions and make them themable --- YACReaderLibrary/folder_content_view.cpp | 3 -- YACReaderLibrary/grid_comics_view.cpp | 3 -- YACReaderLibrary/info_comics_view.cpp | 6 ++-- YACReaderLibrary/qml.qrc | 10 ++----- YACReaderLibrary/qml/info-indicator-light.png | Bin 361 -> 0 bytes .../qml/info-indicator-light@2x.png | Bin 526 -> 0 bytes YACReaderLibrary/qml/info-indicator.png | Bin 652 -> 0 bytes YACReaderLibrary/qml/info-indicator.svg | 24 ++++++++++++++++ YACReaderLibrary/qml/info-shadow-light.png | Bin 120 -> 0 bytes YACReaderLibrary/qml/info-shadow-light@2x.png | Bin 125 -> 0 bytes YACReaderLibrary/qml/info-shadow.png | Bin 135 -> 0 bytes YACReaderLibrary/qml/info-shadow.svg | 24 ++++++++++++++++ YACReaderLibrary/qml/info-top-shadow.png | Bin 121 -> 0 bytes YACReaderLibrary/qml/info-top-shadow.svg | 19 +++++++++++++ YACReaderLibrary/themes/theme.h | 6 ++-- YACReaderLibrary/themes/theme_factory.cpp | 26 ++++++++---------- 16 files changed, 87 insertions(+), 34 deletions(-) delete mode 100644 YACReaderLibrary/qml/info-indicator-light.png delete mode 100644 YACReaderLibrary/qml/info-indicator-light@2x.png delete mode 100644 YACReaderLibrary/qml/info-indicator.png create mode 100644 YACReaderLibrary/qml/info-indicator.svg delete mode 100644 YACReaderLibrary/qml/info-shadow-light.png delete mode 100644 YACReaderLibrary/qml/info-shadow-light@2x.png delete mode 100644 YACReaderLibrary/qml/info-shadow.png create mode 100644 YACReaderLibrary/qml/info-shadow.svg delete mode 100644 YACReaderLibrary/qml/info-top-shadow.png create mode 100644 YACReaderLibrary/qml/info-top-shadow.svg diff --git a/YACReaderLibrary/folder_content_view.cpp b/YACReaderLibrary/folder_content_view.cpp index 79d87fa3..485032bf 100644 --- a/YACReaderLibrary/folder_content_view.cpp +++ b/YACReaderLibrary/folder_content_view.cpp @@ -283,9 +283,6 @@ void FolderContentView::applyTheme(const Theme &theme) // Info panel colors ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("topShadow", qv.topShadow.isEmpty() ? QUrl() : QUrl(qv.topShadow)); - ctxt->setContextProperty("infoShadow", qv.infoShadow); - ctxt->setContextProperty("infoIndicator", qv.infoIndicator); ctxt->setContextProperty("infoTextColor", qv.infoTextColor); ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); diff --git a/YACReaderLibrary/grid_comics_view.cpp b/YACReaderLibrary/grid_comics_view.cpp index f30e4f90..262fb1cc 100644 --- a/YACReaderLibrary/grid_comics_view.cpp +++ b/YACReaderLibrary/grid_comics_view.cpp @@ -501,9 +501,6 @@ void GridComicsView::applyTheme(const Theme &theme) // Info panel colors ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("topShadow", qv.topShadow.isEmpty() ? QUrl() : QUrl(qv.topShadow)); - ctxt->setContextProperty("infoShadow", qv.infoShadow); - ctxt->setContextProperty("infoIndicator", qv.infoIndicator); ctxt->setContextProperty("infoTextColor", qv.infoTextColor); ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); diff --git a/YACReaderLibrary/info_comics_view.cpp b/YACReaderLibrary/info_comics_view.cpp index 87e35a53..ce442f1f 100644 --- a/YACReaderLibrary/info_comics_view.cpp +++ b/YACReaderLibrary/info_comics_view.cpp @@ -228,9 +228,9 @@ void InfoComicsView::applyTheme(const Theme &theme) // Info panel colors ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("topShadow", qv.topShadow.isEmpty() ? QUrl() : QUrl(qv.topShadow)); - ctxt->setContextProperty("infoShadow", qv.infoShadow); - ctxt->setContextProperty("infoIndicator", qv.infoIndicator); + ctxt->setContextProperty("topShadow", QUrl::fromLocalFile(qv.topShadow)); + ctxt->setContextProperty("infoShadow", QUrl::fromLocalFile(qv.infoShadow)); + ctxt->setContextProperty("infoIndicator", QUrl::fromLocalFile(qv.infoIndicator)); ctxt->setContextProperty("infoTextColor", qv.infoTextColor); ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); diff --git a/YACReaderLibrary/qml.qrc b/YACReaderLibrary/qml.qrc index d216b4f8..2d767d06 100644 --- a/YACReaderLibrary/qml.qrc +++ b/YACReaderLibrary/qml.qrc @@ -11,13 +11,9 @@ qml/reading.svg qml/star.svg qml/page.svg - qml/info-indicator.png - qml/info-shadow.png - qml/info-indicator-light.png - qml/info-shadow-light.png - qml/info-indicator-light@2x.png - qml/info-shadow-light@2x.png - qml/info-top-shadow.png + qml/info-indicator.svg + qml/info-shadow.svg + qml/info-top-shadow.svg qml/ComicInfoView.qml qml/info-favorites.svg qml/info-rating.svg diff --git a/YACReaderLibrary/qml/info-indicator-light.png b/YACReaderLibrary/qml/info-indicator-light.png deleted file mode 100644 index b08a8ead6088a2ecb22b8981ff0fa104a6f884e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361 zcmV-v0ha!WP)pzj>j+n0002s zkIky88W_W9dp*bXI~(=BoxYWf@M6GdZQBkySmhgG+{j+s%y}ipQ%cFT(*aX2gmD#y z;a2wIhCqHuk|c)j`v)B~=ZP>bf*@$(IA(AJayms(IF@A{9)!_xUAM`y%wb{#a#E&g z8hM_pOHsMYw(V`2rb^a=Ku*r{JUPD0dnHFoOcX_>tO0@iYRRF*JZC0Vn=wqIuIp3R zbxV2HCFZD)bN(CoLVmyG$VG|a3;7fJzQ6ukf6U|9y^y%(CiBST;w?>u# zKtKWrNB{u|ARqw*B!GYf5Rd=@5};omR;$&)GSC8V;kWp5kBP&)oA6kA1=vB-R?84n zHxH>W=c{n!><;n}SO)H`s;XqS+r{Bi2(9Wy;rJXLmUWt@ z`FuXN;0Q>%BZT8IB$F$ZHnEfmb1Y*x#<@U1(kbDXeLQXln-FM?T@co#%sL*c;~XF$ z>7=Gh8>I{al3r=5v{A|+AnB!sN*kpN0+RmuZ)u~HK|s=Le=Tj4G6+Zp;kTuYQU(FZ zpj=woC}j|k4AOoL?}&f|aKr|L!_ssyE?5Y2##^GTm} z?VW8te%?Q5rIZ0{u%rG+lSMBpWi5JbwW(F3Sf-lUv081_?wwrl0k}Y+I1EfK0rUwh z{+t1rP(NYL#(8!bcm-yMS`OykW{*I6;3D-4TfSBSauZ0tG9r8{@FRJ}tf_{>=rR{2 z`%NGZY1=jwPWI&rh%bX_!x)2?%rRw`uz6XoMcS1N^T8`n?iG+eLFq9l9qUXf+FT)R z7$3+HwVGB;hpmv9ZHcljQ|oPka&K2iJsb{GVQn`>QFJ?*OnyN3o;e~|SJrtQL9ApR z3#celoWQ9F=o{3_3ozA=}&8id9Z-=2*e}sCzx}Yrs+t2gXgzC(T-X! zm#R{!T(#Tnb9fBERf5iEtD#Tta4f)DoP%>k&(Dye_t~~ptJS)m&*$N6Hv2^%yGz@) zqU{>b>PJBkoMP=_v5??oh0GO7uhZ$=c%F9*kF{;aF|5H_Nlbvu_Zpt2DvsmN-EQ|A zJl4St%XJ*X8mtuwkhv>K66Lz?8GtvophOtQIEFPM0rEpHIn`?QYopQlk^$LlHqY># zTw(;se|E`%v*ML8rs@0s3FrdfiT*C#@Au^}lUKM}t5T^HuGeckTh`><_`2k8pZqU5 mwX81^ApeU?j_B?BEx-V$gtq!VC4%_?0000 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/YACReaderLibrary/qml/info-shadow-light.png b/YACReaderLibrary/qml/info-shadow-light.png deleted file mode 100644 index e52f2c7adc9c18c721468d254e5dfbf68d116418..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^j6f{N!3HE{4j&T&Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiljVU978H@B_$kSm6DSBXZ(kqNll<%g-PK6LsA3Vgs%q- R`hlt#JYD@<);T3K0RW_cAdUb4 diff --git a/YACReaderLibrary/qml/info-shadow-light@2x.png b/YACReaderLibrary/qml/info-shadow-light@2x.png deleted file mode 100644 index 3abb75afe4aa0de03b37b22e5c2bc9ccd3bac58b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^OhBx}!3HEtr8tCulw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6JlB6&|2$B>F!NeK%?6LK;#e()z59CZE1%-D4zAccWNg268U}fi7AzZCsS>JiZnf4978H@B_$*zJV;~`x})I4;L_2+!O6zX-u~a`{k^@( g427P`3`{%>Lfcq=>s0O!25MsPboFyt=akR{0L+Uei2wiq diff --git a/YACReaderLibrary/qml/info-shadow.svg b/YACReaderLibrary/qml/info-shadow.svg new file mode 100644 index 00000000..67957428 --- /dev/null +++ b/YACReaderLibrary/qml/info-shadow.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/YACReaderLibrary/qml/info-top-shadow.png b/YACReaderLibrary/qml/info-top-shadow.png deleted file mode 100644 index 1fd60281510ee5b3e065c60f6f2824a35cd796f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^j6lrF!3HE-TH59VDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9Mbe%wjv*Ddk`fXUIM|ZdvIQ3MDIIZS;df|YWZ=2Ya5Lb8 RZ#7UEgQu&X%Q~loCIH7%ARGVy diff --git a/YACReaderLibrary/qml/info-top-shadow.svg b/YACReaderLibrary/qml/info-top-shadow.svg new file mode 100644 index 00000000..f8092b2a --- /dev/null +++ b/YACReaderLibrary/qml/info-top-shadow.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index bf3b7a1d..11dd94ad 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -226,9 +226,9 @@ struct QmlViewTheme { // Info panel colors QColor infoBackgroundColor; - QString topShadow; // Image filename - QString infoShadow; // Image filename - QString infoIndicator; // Image filename + QString topShadow; // Recolored SVG path + QString infoShadow; // Recolored SVG path + QString infoIndicator; // Recolored SVG path QColor infoTextColor; QColor infoTitleColor; diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index f6fda6ca..75cb914a 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -149,9 +149,8 @@ struct QmlViewParams { // Info panel colors QColor infoBackgroundColor; - QString topShadow; // Image filename - QString infoShadow; // Image filename - QString infoIndicator; // Image filename + QColor infoBorderColor; + QColor infoShadowColor; QColor infoTextColor; QColor infoTitleColor; @@ -494,9 +493,9 @@ Theme makeTheme(const ThemeParams ¶ms) theme.qmlView.textColor = qv.textColor; theme.qmlView.showDropShadow = qv.showDropShadow; theme.qmlView.infoBackgroundColor = qv.infoBackgroundColor; - theme.qmlView.topShadow = qv.topShadow; - theme.qmlView.infoShadow = qv.infoShadow; - theme.qmlView.infoIndicator = qv.infoIndicator; + theme.qmlView.topShadow = recoloredSvgToThemeFile(":/qml/info-top-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.themeName); + theme.qmlView.infoShadow = recoloredSvgToThemeFile(":/qml/info-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.themeName); + theme.qmlView.infoIndicator = recoloredSvgToThemeFile(":/qml/info-indicator.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.themeName); theme.qmlView.infoTextColor = qv.infoTextColor; theme.qmlView.infoTitleColor = qv.infoTitleColor; theme.qmlView.ratingUnselectedColor = qv.ratingUnselectedColor; @@ -991,9 +990,8 @@ ThemeParams classicThemeParams() qv.textColor = QColor(0xA8A8A8); qv.showDropShadow = true; qv.infoBackgroundColor = QColor(0x2E2E2E); - qv.topShadow = "info-top-shadow.png"; - qv.infoShadow = "info-shadow.png"; - qv.infoIndicator = "info-indicator.png"; + qv.infoBorderColor = QColor(0x404040); + qv.infoShadowColor = Qt::black; qv.infoTextColor = QColor(0xB0B0B0); qv.infoTitleColor = QColor(0xFFFFFF); qv.ratingUnselectedColor = QColor(0x1C1C1C); @@ -1244,9 +1242,8 @@ ThemeParams lightThemeParams() qv.textColor = QColor(0x636363); qv.showDropShadow = true; qv.infoBackgroundColor = QColor(0xFFFFFF); - qv.topShadow = ""; - qv.infoShadow = "info-shadow-light.png"; - qv.infoIndicator = "info-indicator-light.png"; + qv.infoBorderColor = QColor(0x808080); + qv.infoShadowColor = QColor(0x444444); qv.infoTextColor = QColor(0x404040); qv.infoTitleColor = QColor(0x2E2E2E); qv.ratingUnselectedColor = QColor(0xDEDEDE); @@ -1497,9 +1494,8 @@ ThemeParams darkThemeParams() qv.textColor = QColor(0xA8A8A8); qv.showDropShadow = true; qv.infoBackgroundColor = QColor(0x2E2E2E); - qv.topShadow = "info-top-shadow.png"; - qv.infoShadow = "info-shadow.png"; - qv.infoIndicator = "info-indicator.png"; + qv.infoBorderColor = QColor(0x404040); + qv.infoShadowColor = Qt::black; qv.infoTextColor = QColor(0xB0B0B0); qv.infoTitleColor = QColor(0xFFFFFF); qv.ratingUnselectedColor = QColor(0x1C1C1C); From 0e9117620060bbc47af44223471901d2d0ead893 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Fri, 27 Feb 2026 16:12:59 +0100 Subject: [PATCH 04/26] Remove unused images and server v1 files --- YACReaderLibrary/images.qrc | 2 - YACReaderLibraryServer/CMakeLists.txt | 2 - images/f.png | Bin 710 -> 0 bytes images/f_overlayed.png | Bin 597 -> 0 bytes images/f_overlayed_retina.png | Bin 1224 -> 0 bytes release/server/docroot/css/reset.css | 46 -- release/server/docroot/css/styles_ipad.css | 466 ------------------ release/server/docroot/css/styles_iphone.css | 463 ----------------- release/server/docroot/images/browse.png | Bin 134 -> 0 bytes release/server/docroot/images/browse@2x.png | Bin 185 -> 0 bytes release/server/docroot/images/combo.png | Bin 120 -> 0 bytes release/server/docroot/images/combo@2x.png | Bin 167 -> 0 bytes release/server/docroot/images/download.png | Bin 155 -> 0 bytes release/server/docroot/images/download@2x.png | Bin 203 -> 0 bytes release/server/docroot/images/f.png | Bin 621 -> 0 bytes release/server/docroot/images/f@2x.png | Bin 1262 -> 0 bytes release/server/docroot/images/imported.png | Bin 158 -> 0 bytes release/server/docroot/images/imported@2x.png | Bin 214 -> 0 bytes release/server/docroot/images/indicator.png | Bin 118 -> 0 bytes .../server/docroot/images/indicator@2x.png | Bin 220 -> 0 bytes release/server/docroot/images/library.png | Bin 201 -> 0 bytes release/server/docroot/images/library@2x.png | Bin 284 -> 0 bytes release/server/docroot/images/next.png | Bin 137 -> 0 bytes release/server/docroot/images/next@2x.png | Bin 339 -> 0 bytes release/server/docroot/images/prev.png | Bin 154 -> 0 bytes release/server/docroot/images/prev@2x.png | Bin 345 -> 0 bytes release/server/docroot/images/read.png | Bin 152 -> 0 bytes release/server/docroot/images/read@2x.png | Bin 201 -> 0 bytes release/server/docroot/images/readMark.png | Bin 196 -> 0 bytes release/server/docroot/images/readMark@2x.png | Bin 296 -> 0 bytes release/server/docroot/images/readingMark.png | Bin 206 -> 0 bytes .../server/docroot/images/readingMark@2x.png | Bin 296 -> 0 bytes release/server/docroot/images/up.png | Bin 163 -> 0 bytes release/server/docroot/images/up@2x.png | Bin 271 -> 0 bytes release/server/docroot/login.html | 26 - release/server/templates/folder.tpl | 117 ----- release/server/templates/libraries.tpl | 27 - 37 files changed, 1149 deletions(-) delete mode 100644 images/f.png delete mode 100644 images/f_overlayed.png delete mode 100644 images/f_overlayed_retina.png delete mode 100644 release/server/docroot/css/reset.css delete mode 100644 release/server/docroot/css/styles_ipad.css delete mode 100644 release/server/docroot/css/styles_iphone.css delete mode 100644 release/server/docroot/images/browse.png delete mode 100644 release/server/docroot/images/browse@2x.png delete mode 100644 release/server/docroot/images/combo.png delete mode 100644 release/server/docroot/images/combo@2x.png delete mode 100644 release/server/docroot/images/download.png delete mode 100644 release/server/docroot/images/download@2x.png delete mode 100644 release/server/docroot/images/f.png delete mode 100644 release/server/docroot/images/f@2x.png delete mode 100644 release/server/docroot/images/imported.png delete mode 100644 release/server/docroot/images/imported@2x.png delete mode 100644 release/server/docroot/images/indicator.png delete mode 100644 release/server/docroot/images/indicator@2x.png delete mode 100644 release/server/docroot/images/library.png delete mode 100644 release/server/docroot/images/library@2x.png delete mode 100644 release/server/docroot/images/next.png delete mode 100644 release/server/docroot/images/next@2x.png delete mode 100644 release/server/docroot/images/prev.png delete mode 100644 release/server/docroot/images/prev@2x.png delete mode 100644 release/server/docroot/images/read.png delete mode 100644 release/server/docroot/images/read@2x.png delete mode 100644 release/server/docroot/images/readMark.png delete mode 100644 release/server/docroot/images/readMark@2x.png delete mode 100644 release/server/docroot/images/readingMark.png delete mode 100644 release/server/docroot/images/readingMark@2x.png delete mode 100644 release/server/docroot/images/up.png delete mode 100644 release/server/docroot/images/up@2x.png delete mode 100644 release/server/docroot/login.html delete mode 100644 release/server/templates/folder.tpl delete mode 100644 release/server/templates/libraries.tpl diff --git a/YACReaderLibrary/images.qrc b/YACReaderLibrary/images.qrc index d0749b7f..788d45d9 100644 --- a/YACReaderLibrary/images.qrc +++ b/YACReaderLibrary/images.qrc @@ -36,8 +36,6 @@ ../images/empty_container/empty_reading_list.svg ../images/library_dialogs/exportComicsInfo.svg ../images/library_dialogs/exportLibrary.svg - ../images/f_overlayed.png - ../images/f_overlayed_retina.png ../images/find_folder.svg ../images/flow1.png ../images/flow2.png diff --git a/YACReaderLibraryServer/CMakeLists.txt b/YACReaderLibraryServer/CMakeLists.txt index 619f10a8..fd70e77e 100644 --- a/YACReaderLibraryServer/CMakeLists.txt +++ b/YACReaderLibraryServer/CMakeLists.txt @@ -19,8 +19,6 @@ target_compile_definitions(YACReaderLibraryServer PRIVATE YACREADER_LIBRARY ) -# Resources -qt_add_resources(yacreaderlibraryserver_images_rcc "${CMAKE_CURRENT_SOURCE_DIR}/images.qrc") target_sources(YACReaderLibraryServer PRIVATE ${yacreaderlibraryserver_images_rcc}) # Translations diff --git a/images/f.png b/images/f.png deleted file mode 100644 index 232a785d75767e8fae82aae15cf36213ecec1598..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 710 zcmeAS@N?(olHy`uVBq!ia0vp^0YF^A!3HE#-<5s?Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07??6VT^vIyZoRp?F|Wx%=6In&AK%@WTIO07-ooXZUtUl* z=zZxkL;CU$mRgpXt6k(5?rU5v-CSLLea^|&5(Yl4@|t?i#EaQKf9x+RDEhkJ)h5W& zmV<#sz=46Yfq{ubff2}JQ~|LXSR5E~J@&ugUVnYHxa-DptGRR7B>RuY$++K3Fwpo? zwg1JEOIcrE+05(P5x4(pbfe`Smz>!qcV%N4xSM{4yqT87{omqR6+@{FI$`{63> zfOAt%wZ)##joXp&XA{5lsY`J>^X446{odYt|MD+e($;Nxs^T+e+3q8k_SY`7(hQS} zoYBX;_UPom{na(w8@HUTi0X^!oFVGSrf~fb*gY4HeR==2`Do|?k2iKl%+@B#eAj7H zets@w!GUUl-Ojuf^RgZ{QL&CicNKr?l_(xm9QL7*^%keCEkd%VK^x^JT5=>vb+yrXKE@%#ogm z5*nB>!^kp$0T@RN&lb=7vCV4P@r08U}fi7AzZCsS=07#P2Mx;TbZ+=nBHH#?)tcPPQU#n9&pQ?~$NilYd-YPszK%?ZVB=$&jOBv%7t6LY_$aga z>}FES<$mos$;94`XUDoI!MJs6?HE4HZ}k*+c8bs5{vO@8dfM3=I^4+` z)j?C788>sN#hI}fyey8h*u)k4Jm^^~>w){~k?{`Emeq+M`wplw<*nK#pZI?lf9+k> z?@{dQ4vS^2X?z}9z4lh7=IaCJC#IiO`?7O}WJF7(McS*I-)mk=R`4H4dvAHPWy93Z zVtHRft$nY&Pnu>JZ~XGIk=nKN1ltSSSIN4)crEbDN;i|uE^1HfUt>lE2SyG7e8i84 zhK({i-pyx~{~5o2UEiPWdtaq|nD}2J|NV=it0xl<+*s%Evg+!|2iC$zq9qg@8km5l lH88Lu5eH^Ib#Gu~kmFl)@v?G$8ZezOc)I$ztaD0e0swUy@gx8M diff --git a/images/f_overlayed_retina.png b/images/f_overlayed_retina.png deleted file mode 100644 index d613de82913baa10606c85d4c22e2bd45684f3ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1224 zcmeAS@N?(olHy`uVBq!ia0vp^3xN0o2OE%Vcg(*9q$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FtB8Kx;TbZ+gV-o|An$T-;E=8g(`TqCg+j1{ksvKi-pS9bhJyY+wk$1!Izi}1X+=gdg zDlz%k>pqH3Zz*2WqRwxids8iEuJYNpD@~W%X}^2(MyKcTk6ZQo`XB4{9sZL4s!-Bh z{P@=|@6#V?Nyy2|zuw33^Q?bBexLZ_`dqoy_nVGxf5!o&W-qJEyuH_Ge)pE&rPg*| zU+%NabGbkB_|aLl?}}I|4EnoGf8Tj}qe=Snj)+{D{^GoYOi%jFy{7$>Lh~}jBT)Zf zqppZQ*txuNqaLe==UpkLJ!bvgrF+{LE*ssOefsFj;+%thnGd%9*d%lL!2+pCWmRkM zwJwzpdAvf;z0`8eg&Xe@Tl=z0W3oRo$VR+9@G41Maed{(A8cCFG`Zii28X?5xcqlk z|HGFChmW1GTDRPsjKQ{kZ^}*om(P!Hd-nU#? zd?RMcou*i^>&f4O4Ovgfzu&WixB0e#f&&W&lS=~{b)bH-9do(#ae-5RUp+RkZ7W+n zdBfH7%=@|@d%FtHud{!q*0-Kj-g)AA<~+j#bzSS--gCQY9N^hy@l7T`kGPno7HC>>4Lu}8>)eoAFXL0MjTzy>Yz@&FJVT{wJ z+>6{1f8g;Re(7I_=i2oI+`qbuUwO?RrzguE9WUR!lzW0M+mFYr|9%Ht-+Rz-%3qxY zx;q-S@YZwq=l>~Z4S!N{@Z-uRd5-t2oA)yO4U>suR&o$fU}9k;k-`W&tN{ua{BdUK z^8HfNnNlV*njP0T{eMMf-QP` z=GM!_b-#mZ^v_(a>6`hbc7ENG9@ZX{@SQ2QoA}$EckI}~@z^4&J}XY@@vH6k-#cF~ zeSNFxviX+VZ$Ih1|5I9%*;jOQdMWq6M2WWd-Zg*Ha?7Xon22ZkUApsRS}u3nt#{0z mY)QJ;L16_?J(9J;2@I**cC54P%a;NcO$?r{elF{r5}E)%Z}4sa diff --git a/release/server/docroot/css/reset.css b/release/server/docroot/css/reset.css deleted file mode 100644 index b1f6c072..00000000 --- a/release/server/docroot/css/reset.css +++ /dev/null @@ -1,46 +0,0 @@ -html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td -{ - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-weight: inherit; - font-style: inherit; - font-size: 100%; - font-family: inherit; - vertical-align: baseline; -} -/* remember to define focus styles! */ -:focus -{ - outline: 0; -} -body -{ - line-height: 1; - color: black; -} -ol, ul -{ - list-style: none; -} -/* tables still need 'cellspacing="0"' in the markup */ -table, td, tr -{ - border: 0; - border-collapse: separate; - border-spacing: 0; -} -caption, th, td -{ - text-align: left; - font-weight: normal; -} -blockquote:before, blockquote:after, q:before, q:after -{ - content: ""; -} -blockquote, q -{ - quotes: "" ""; -} diff --git a/release/server/docroot/css/styles_ipad.css b/release/server/docroot/css/styles_ipad.css deleted file mode 100644 index d14b3cfb..00000000 --- a/release/server/docroot/css/styles_ipad.css +++ /dev/null @@ -1,466 +0,0 @@ -body{ - background-color: #F5F5F5; - font-family: Arial, Helvetica, sans-serif; -} - -/* libraries */ -#contentLibraries{ - width: 400px; - border: 1px solid #C6C6C6; - background-color: white; - margin-left: auto; - margin-right: auto; - margin-top: 9px; -} - -#contentLibraries .library-icon -{ - float: left; - background-color: white; - height: 18px; - padding: 11px 19px 10px 19px; - display:block; -} - -#contentLibraries li -{ - border-bottom: 1px solid #e2e2e2; - position: relative; - list-style: none; -} - -#contentLibraries li:last-child -{ - border: none; -} - -#contentLibraries .library-link -{ - width: 311px; - height: 28px; - border: none; - padding: 11px 0 0 0px; - background-color: white; - display: block; - float:left; - font-family: Arial; - font-size: 16px; - text-decoration: none; - color: #525252 ; - overflow: hidden; -} - - #contentLibraries a -{ - position: absolute; - height: 39px; - width: 100%; - z-index: 10; - display: block; - top 0; - text-decoration: none; -} - -#contentLibraries .library-indicator -{ - float: left; - background-color: white; - height: 8px; - padding: 16px 16px 15px 16px; - display:block; -} - - -#content h1 -{ - color: #292929; - text-align: center; - font-size: 21px; -} - -#contentLibraries h1{ - color: #292929; - text-align: center; - border-bottom: 1px solid #C6C6C6; - font-size: 21px; - padding: 15px 0 16px 0; -} - -#folder-header -{ - position: fixed; - width: 100%; - height: 88px; - background-color: rgba(255,255,255,0.9); - border-bottom: 1px solid #C6C6C6; - z-index: 999; -} - -#folder-subheader1 -{ - width: 100%; - height: 40px; - margin-top: 18px; - -} - -#folder-subheader2 -{ - width: 100%; - padding-left: 16px; -} - -#topIndex -{ - position: absolute; - left: 16px; - top: 19px; -} - -#topIndex a -{ - float: left; -} - -.indicator { - margin: 0 9px; -} - -.path { - text-decoration: none; - color: #5C5C5C; - font-family: Arial, Helvetica; - font-size: 15px; - -} - -#header-combos -{ - position: absolute; - right: 15px; - top: 15px; - color: #a3a3a3; - width: 160px; -} - -#topIndex .next{ - width: 25px; - height: 19px; - border: none; - margin: 0 21px 4px 0; - padding: 5px 0 0 0; - display: block; - background: url("/images/next.png") no-repeat scroll 0 0 transparent; - background-size: 25px 19px; - padding: 0; - text-indent: -99999px; -} - -#topIndex .previous{ - width: 25px; - height: 19px; - border: none; - margin: 0 14px 4px 0; - padding: 5px 0 0 0; - display: block; - background: url("/images/prev.png") no-repeat scroll 0 0 transparent; - background-size: 25px 19px; - padding: 0; - text-indent: -99999px; -} - -#topIndex .up{ - width: 15px; - height: 19px; - border: none; - background: url("/images/up.png") no-repeat scroll 0 0 transparent; - background-size: 15px 19px; - color: #FFF; - display: block; - text-indent: -99999px; -} - -#itemContainer li -{ -float: left; -width: 242px; -height: 120px; -border: 1px solid #E2E2E2; -margin: 9px 9px 0px 0; -background-color: white; -overflow: hidden; -position: relative; -} - -.folderContent -{ - padding-top: 90px; - padding-left: 9px; -} -/* hasta aquí */ - -.folder -{ -float: left; - -} - -.cover -{ -float: left; -overflow: hidden; -} - -.mark -{ - position: absolute; - top: 0px; - margin-left: 55px; -} - -.info -{ -padding: 8px 0px 0px 0px; -float: left; -position: relative; -height: 115px; -width: 158px; - -} - -.buttons -{ - position:absolute; - bottom:0px; - left:0px; - border-top: 1px solid #e2e2e2; - padding-top: 3px; - height: 25px; - width: 162px; - font-family: Arial; - color: #6e6e6e; - font-size: 10px; -} - -.elementInfo -{ - position:absolute; - bottom:24px; - padding-top: 3px; - height: 25px; - width: 162px; - font-family: Arial; - color: #adadad; - font-size: 10px; -} - -.numPages -{ - float: left; - padding-left:8px; -} - -.comicSize -{ - float: right; - padding-right: 9px; -} - - - -#itemContainer a -{ - text-decoration: none; - - -} - -.browseButton -{ - width: 60px; - background: url("/images/browse.png") no-repeat scroll 0 0 transparent; - background-position: 1px 6px; - background-size: 7px 7px; - border: none; - text-align:right; - display: block; - float: right; - padding: 4px 10px 0 0; - color: #6e6e6e; -} - -.importButton -{ - width: 60px; - background: url("/images/download.png") no-repeat scroll 0 0 transparent; - background-position: 3px 5px; - background-size: 7px 8px; - border: none; - text-align:left; - display: block; - float: left; - margin: 0 0 0 4px; - padding: 4px 0 0 16px; - color: #6e6e6e; -} - -.readButton -{ - width: 60px; - background: url("/images/read.png") no-repeat scroll 0 0 transparent; - background-position: 18px 5px; - background-size: 7px 9px; - border: none; - text-align:right; - display: block; - float: right; - padding: 4px 10px 0 0; - color: #6e6e6e; -} - -.importedButton -{ - width: 60px; - background: url("/images/imported.png") no-repeat scroll 0 0 transparent; - background-position: 2px 6px; - background-size: 8px 6px; - border: none; - text-align:left; - display: block; - float: left; - margin: 0 0 0 4px; - padding: 4px 0 0 16px; - color: #6e6e6e; -} - - -#indexes{ - border-top: 1px solid #C6C6C6; - background-color: white; - padding: 0px; - margin: 9px 0 0 0; -} - -.index{ - background-color: white; - margin: 9px 0 9px 0; -} - - -#alphaIndex a, #pageIndex a{ - width: 29px; - height: 24px; - border: none; - margin: 0 0 9px 9px; - padding: 5px 0 0 0px; - color: #5C5C5C; - font-size: 20px; - text-align: center; - display: block; - text-decoration: none; - font-family: Arial; - border: 1px solid #E2E2E2; - text-align:center; -} - -#alphaIndex li, #pageIndex li{ - float: left; -} - -#pageIndex .current{ - color: white; - background-color: #A2A2A2; - border: 1px solid #A2A2A2; - -} - - #content h2, #contentLibraries h2{ - color: #000; - font-weight: bold; - font-size: 12px; - margin: 0 0 16px 0; - } - - .inputs_login{ - width: 256px; - height: 64px; - background: url("/images/fnd_inputs.jpg") no-repeat scroll 0 0 #FFF; - margin: 0 0 18px 0; - } - .username{ - width: 200px; - height: 24px; - background: url("/images/fnd_input_username.jpg") no-repeat scroll 0 0 #2b2b2b; - border: none; - padding: 0 0 0 44px; - margin: 5px 0 6px 8px; - font-size: 14px; - color: #6e6e6e; - } - .pass{ - width: 200px; - height: 24px; - background: url("/images/fnd_input_pass.jpg") no-repeat scroll 0 0 #2b2b2b; - border: none; - padding: 0 0 0 44px; - margin: 0 0 0 8px; - font-size: 14px; - color: #6e6e6e; - } - .button_sign{ - width: 86px; - height: 30px; - background: url("/images/bt_login.jpg") no-repeat scroll 0 0 transparent; - border: none; - margin: 0; - padding: 0; - color: #FFF; - font-size: 14px; - float: left; - } - .infor{ - color: #666; - font-size: 8px; - float: left; - width: 112px; - margin: 0 0 0 8px; - line-height: 120%; - } - -.clear{ - height: 2px; - clear: both; -} - -.title{ - font-family: Arial; - font-size: 12px; - margin: 0 0 0 6px; - color: #555555 ; - overflow: hidden; - word-wrap: break-word; - height: 80px; - text-decoration: none; -} - -#indexalpha, #indexnumber{ - - -webkit-appearance: none; - background-color: rgba(255,255,255,0); - border-radius: 0px; - border: none; - color: #a3a3a3; - font-size: 16px; - font-family: Arial, Helvetica; - height: 30px; - margin: 0 0 0 10px; - padding:0; - float: right; -} - -.comboIndicator { - float: right; - padding: 14px 0 0 0; - margin: 0 0 0 4px; - width: 5px; -} \ No newline at end of file diff --git a/release/server/docroot/css/styles_iphone.css b/release/server/docroot/css/styles_iphone.css deleted file mode 100644 index 109b1155..00000000 --- a/release/server/docroot/css/styles_iphone.css +++ /dev/null @@ -1,463 +0,0 @@ -body{ - background-color: #F5F5F5; - font-family: Arial, Helvetica, sans-serif; -} - -/* libraries */ -#contentLibraries{ - border: 1px solid #C6C6C6; - background-color: white; - margin-left: 20px; - margin-right: 20px; - margin-top: 9px; -} - -#contentLibraries .library-icon -{ - float: left; - background-color: white; - height: 18px; - padding: 11px 19px 10px 19px; - display:block; -} - -#contentLibraries li -{ - border-bottom: 1px solid #e2e2e2; - position: relative; - list-style: none; -} - -#contentLibraries li:last-child -{ - border: none; -} - -#contentLibraries .library-link -{ - width: 65%; - height: 28px; - border: none; - padding: 11px 0 0 0px; - background-color: white; - display: block; - float:left; - font-family: Arial; - font-size: 16px; - text-decoration: none; - color: #525252 ; - overflow: hidden; -} - - #contentLibraries a -{ - position: absolute; - height: 39px; - width: 100%; - z-index: 10; - display: block; - top 0; - text-decoration: none; -} - -#contentLibraries .library-indicator -{ - float: right; - background-color: white; - height: 8px; - padding: 16px 16px 15px 16px; - display:block; -} - - -#content h1 -{ - color: #292929; - text-align: center; - font-size: 21px; -} - -#contentLibraries h1{ - color: #292929; - text-align: center; - border-bottom: 1px solid #C6C6C6; - font-size: 21px; - padding: 15px 0 16px 0; -} - -#folder-header -{ - position: fixed; - width: 100%; - height: 88px; - background-color: rgba(255,255,255,0.9); - border-bottom: 1px solid #C6C6C6; - z-index: 999; -} - -#folder-subheader1 -{ - width: 100%; - height: 40px; - margin-top: 18px; - -} - -#folder-subheader2 -{ - width: 100%; - padding-left: 16px; -} - -#topIndex -{ - position: absolute; - left: 16px; - top: 19px; -} - -#topIndex a -{ - float: left; -} - -.indicator { - margin: 0 5px; -} - -.path { - text-decoration: none; - color: #5C5C5C; - font-family: Arial, Helvetica; - font-size: 15px; - -} - -#header-combos -{ - position: absolute; - right: 10px; - top: 15px; - color: #a3a3a3; - width: 160px; -} - -#topIndex .next{ - width: 25px; - height: 19px; - border: none; - margin: 0 21px 4px 0; - padding: 5px 0 0 0; - display: block; - background: url("/images/next.png") no-repeat scroll 0 0 transparent; - background-size: 25px 19px; - padding: 0; - text-indent: -99999px; -} - -#topIndex .previous{ - width: 25px; - height: 19px; - border: none; - margin: 0 14px 4px 0; - padding: 5px 0 0 0; - display: block; - background: url("/images/prev.png") no-repeat scroll 0 0 transparent; - background-size: 25px 19px; - padding: 0; - text-indent: -99999px; -} - -#topIndex .up{ - width: 15px; - height: 19px; - border: none; - background: url("/images/up.png") no-repeat scroll 0 0 transparent; - background-size: 15px 19px; - color: #FFF; - display: block; - text-indent: -99999px; -} - -#itemContainer li -{ - -height: 120px; -border: 1px solid #E2E2E2; -margin: 9px 10px 0px 10px; -background-color: white; -overflow: hidden; -position: relative; -} - -.folderContent -{ - padding-top: 90px; -} -/* hasta aquí */ - -.folder -{ -float: left; - -} - -.cover -{ -float: left; -overflow: hidden; -} - -.mark -{ - position: absolute; - top: 0px; - margin-left: 55px; -} - -.info -{ -padding: 8px 0px 0px 0px; - -position: relative; -height: 115px; - -padding-left: 82px; -} - -.buttons -{ - position:absolute; - bottom:0px; - left:80px; - right: 0px; - border-top: 1px solid #e2e2e2; - padding-top: 3px; - height: 25px; - font-family: Arial; - color: #6e6e6e; - font-size: 10px; -} - -.elementInfo -{ - position:absolute; - bottom:24px; - padding-top: 3px; - height: 25px; - width: 100%; - font-family: Arial; - color: #adadad; - font-size: 10px; -} - -.numPages -{ - float: left; - padding-left:8px; -} - -.comicSize -{ - float: right; - padding-right: 9px; -} - - - -#itemContainer a -{ - text-decoration: none; - - -} - -.browseButton -{ - width: 60px; - background: url("/images/browse.png") no-repeat scroll 0 0 transparent; - background-position: 1px 6px; - background-size: 7px 7px; - border: none; - text-align:right; - display: block; - float: right; - padding: 4px 10px 0 0; - color: #6e6e6e; -} - -.importButton -{ - width: 60px; - background: url("/images/download.png") no-repeat scroll 0 0 transparent; - background-position: 3px 5px; - background-size: 7px 8px; - border: none; - text-align:left; - display: block; - float: left; - margin: 0 0 0 4px; - padding: 4px 0 0 16px; - color: #6e6e6e; -} - -.readButton -{ - width: 60px; - background: url("/images/read.png") no-repeat scroll 0 0 transparent; - background-position: 18px 5px; - background-size: 7px 9px; - border: none; - text-align:right; - display: block; - float: right; - padding: 4px 10px 0 0; - color: #6e6e6e; -} - -.importedButton -{ - width: 60px; - background: url("/images/imported.png") no-repeat scroll 0 0 transparent; - background-position: 2px 6px; - background-size: 8px 6px; - border: none; - text-align:left; - display: block; - float: left; - margin: 0 0 0 4px; - padding: 4px 0 0 16px; - color: #6e6e6e; -} - - -#indexes{ - border-top: 1px solid #C6C6C6; - background-color: white; - padding: 0px; - margin: 9px 0 0 0; -} - -.index{ - background-color: white; - margin: 9px 0 9px 0; -} - - -#alphaIndex a, #pageIndex a{ - width: 29px; - height: 24px; - border: none; - margin: 0 0 9px 9px; - padding: 5px 0 0 0px; - color: #5C5C5C; - font-size: 20px; - text-align: center; - display: block; - text-decoration: none; - font-family: Arial; - border: 1px solid #E2E2E2; - text-align:center; -} - -#alphaIndex li, #pageIndex li{ - float: left; -} - -#pageIndex .current{ - color: white; - background-color: #A2A2A2; - border: 1px solid #A2A2A2; - -} - - #content h2, #contentLibraries h2{ - color: #000; - font-weight: bold; - font-size: 12px; - margin: 0 0 16px 0; - } - - .inputs_login{ - width: 256px; - height: 64px; - background: url("/images/fnd_inputs.jpg") no-repeat scroll 0 0 #FFF; - margin: 0 0 18px 0; - } - .username{ - width: 200px; - height: 24px; - background: url("/images/fnd_input_username.jpg") no-repeat scroll 0 0 #2b2b2b; - border: none; - padding: 0 0 0 44px; - margin: 5px 0 6px 8px; - font-size: 14px; - color: #6e6e6e; - } - .pass{ - width: 200px; - height: 24px; - background: url("/images/fnd_input_pass.jpg") no-repeat scroll 0 0 #2b2b2b; - border: none; - padding: 0 0 0 44px; - margin: 0 0 0 8px; - font-size: 14px; - color: #6e6e6e; - } - .button_sign{ - width: 86px; - height: 30px; - background: url("/images/bt_login.jpg") no-repeat scroll 0 0 transparent; - border: none; - margin: 0; - padding: 0; - color: #FFF; - font-size: 14px; - float: left; - } - .infor{ - color: #666; - font-size: 8px; - float: left; - width: 112px; - margin: 0 0 0 8px; - line-height: 120%; - } - -.clear{ - height: 2px; - clear: both; -} - -.title{ - font-family: Arial; - font-size: 12px; - margin: 0 0 0 6px; - color: #555555 ; - overflow: hidden; - word-wrap: break-word; - height: 65px; - text-decoration: none; -} - -#indexalpha, #indexnumber{ - - -webkit-appearance: none; - background-color: rgba(255,255,255,0); - border-radius: 0px; - border: none; - color: #a3a3a3; - font-size: 16px; - font-family: Arial, Helvetica; - height: 30px; - margin: 0 0 0 10px; - padding:0; - float: right; -} - -.comboIndicator { - float: right; - padding: 14px 0 0 0; - margin: 0 0 0 4px; - width: 5px; -} \ No newline at end of file diff --git a/release/server/docroot/images/browse.png b/release/server/docroot/images/browse.png deleted file mode 100644 index 9043aa9d9858598d9af07bdc6c95e402680c6a0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1|*LJg}1oj85^_xT291H%W55|cF45{<>wj&+>(Tf?xN eErqjzftle=sQ{~F>Xc-l9tKZWKbLh*2~7Yv@h24k diff --git a/release/server/docroot/images/browse@2x.png b/release/server/docroot/images/browse@2x.png deleted file mode 100644 index 06d5f0580720bdc26a2e67ebe314626eabd6a77c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1G(Vi}jAr-fhPMkjdoBt4x3X>X}(LseP9ojq{+XPos+Ivc= z`_4MTv4oFdBlD)SE;l)@yy?g@R<tDnm{r-UW|^CCGT diff --git a/release/server/docroot/images/combo.png b/release/server/docroot/images/combo.png deleted file mode 100644 index 54edc9fafbde3c37c4dde5aeff80382e495eccbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1n!3HFw&5r&6Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiljVU978H@B}MG1_*l=T!tngC#0#zf76v9B29|ujPR>k* QEkIQap00i_>zopr0NbA+CjbBd diff --git a/release/server/docroot/images/combo@2x.png b/release/server/docroot/images/combo@2x.png deleted file mode 100644 index 39e5c700937a7e8ec1599760de64dc3bcc4e412c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^AT}EZ8<70WD#W6a5s#(4CSmdKI;Vst0A>O+1ONa4 diff --git a/release/server/docroot/images/download.png b/release/server/docroot/images/download.png deleted file mode 100644 index 10b43d66be328c5f946556e772f54a078d35d982..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PI@$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1Gww^AIAr-fh5*(N+D=Ys`{OQ9}!N5A{#W#i9{Fh#KtYbJ; zp3+hz({QCurSiDvWHs3YmmuC?hG`6)j4Toi#?7LC94^ZQ01aaBboFyt=akR{0Kum( AbpQYW diff --git a/release/server/docroot/images/download@2x.png b/release/server/docroot/images/download@2x.png deleted file mode 100644 index 98c6ae38f9d448b10db872feb999e0a3a341bcac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^d_XL~!3HGNrubO_DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MY*0Xjv*Ddk`fLue){z3U$cQ;r5c;j!4+;%87YlNuP*VN zEYW$9A^3cY%7*zIz6GW}0kioSHZt#x1XkcXcci*_{_;RZNpv4THu6{1-oD!M<1rbIJ diff --git a/release/server/docroot/images/f.png b/release/server/docroot/images/f.png deleted file mode 100644 index 32fb386772d76990a4c8c17858db498aa475f95f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 621 zcmeAS@N?(olHy`uVBq!ia0vp^0YF^A!3HE#-<5s?Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?}7yT^vIyZoRp?(eIFhOvA@!1EU>NuZnNjtt0V>`2&N| zX`V#Zur0>telXZDWWH&tu4QuHWw{~yf3L5B+LG%*x8nB4Uz#wX>dC$s=YJ_KD8||I#gLI<{#=ua956cEaTu ztBzYAm$Be~;xelNXa@(-vTMPsSFrOnIp|J5f9m^RpT{@0tzCAxbCb?$J8gqHclB%= z#pDwa?(%0%?H^=)UG&%SSa6Dtq#xZ~<8foCRa%s=OK=2Z4X z&lbJ$_Fh=hnM-Uky>eUk_ZN2cs3u=iTOgCy_gQ8xOS&r1L|55Et$T$ghV%7(J~El( z{2>LPhdmqwfF6c83oQ&l!O{ehV=R2v5V=n)UM%wYgm3QZ_oh_-pK+l0?%TUd!xm)P nH$Kwroo@w?vK6!C8QB=RUbpTEy|;TCC>A|k{an^LB{Ts5f)NB~ diff --git a/release/server/docroot/images/f@2x.png b/release/server/docroot/images/f@2x.png deleted file mode 100644 index e388d804f336a4d6c0f783ecbfc194d5e13f826c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1262 zcmeAS@N?(olHy`uVBq!ia0vp^3xN0o2OE%Vcg(*9q$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1FtAMUba4!+xb^1lMt_k=nFAjMHGOV0@p&Ek$9QLJwrfZB z>zgw*K3Z-4x*>L(Xl~=I>@6QNj!sy;;OmPV0q<>#7wn%cUv$#-p_7vF`?KesPxcAm zs@%Q*z1@MNBNKTZ-(>b`}!YApXR9F_ik>%qNY~9Bj(eVolmb`tEL_CVsH07 zOKa<39esPPs=aX+UzYS3J1<|p{OG@bbsM*StuCyw*_E?x|FeC}b=!ZJ?!KE;T)g;h<-Cg-~ z_rNQKY^Pk)($l-@_Q&7Z|KA%Jk8c`s1^2gn{_ybA&6oZwA8~)&n9RFz+LZkgDhH&F z_L)npNh|dTTBCaH$}x^;(FfP#o$s6}tIf_{f9{&b0YlN{#ZPN&V%Dt9RqxoUcEIBO zy9W;xewQAT(zl%L-{AZ0-`~EiTn2O1WT)L*)_gZwIN{X)Jjv%?%B#!z_YjF zWAwHA6OPfOgF8C)pz;*{4u=Dw|4-#)or#hz{N zh7C{MKe5gzyB--=S5o#c*nm(9!k)-jK%uPQKmrvZ)$8`|ug{V>uA3OHUpM!$6V^-* zOm9&C|M&F0dv%5qYi@B0zppWDo^ka5*;QVXP4C@%`>EvS3X{vmcgJ+ymv>AhWx7oR`=`SacFPvw`N&IYBkO0$Q1HP^GJ m*37>ni?vVy3L3=y6HH*(A!Ao{RJ*4Nq{`FP&t;ucLK6V+vM6`} diff --git a/release/server/docroot/images/imported.png b/release/server/docroot/images/imported.png deleted file mode 100644 index 1eaf45d4e2d320c021d077b173883b656a00a82d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^96-#*!3HG%vEKg;q$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c6*+jiIEGZ*N=i7u7+1k!-H_oXGl|n7%TB=BNO85>WS=QF zHhyDJ4k@ztU|7Ybwv!=`b&?)iiYJe|Vl*o=10x&5_h*t{U7hXufo3syy85}Sb4q9e E0R1m4egFUf diff --git a/release/server/docroot/images/imported@2x.png b/release/server/docroot/images/imported@2x.png deleted file mode 100644 index 41b9ad4e96532b047eac146c38c66e37dc9817ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~e!3HF=pW8M9DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MHQYdjv*Ddk`fe{_k7?GV|c_SFnglRS%)lp0cnOpWo6b` z`V1SDl~re{maX}FfMse3U6Ni2|d@-Vg$+o0KU z>haYcq236dM1>`i%CZY24>@=kUu$78UBYl`ZiByZD1$=-BSXwAkG2i#7iR+9z~JfX K=d#Wzp$Pyl_d)dl diff --git a/release/server/docroot/images/indicator.png b/release/server/docroot/images/indicator.png deleted file mode 100644 index 138c77a84bb3339a5c1092bd83b6104481688dfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1k!3HFMt$j8RNJ*BsMwA5SrbP0l+XkK8S^5> diff --git a/release/server/docroot/images/indicator@2x.png b/release/server/docroot/images/indicator@2x.png deleted file mode 100644 index 9f30e70415f7715ee848411d4ad9b6b5a82f3ee5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^Ahr+(8<0%e?(YqxBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrH1%)p@!&hE&{2I&=E;?(+u@EMPdot>!yx%83SM1I9uHfqI5V zEDM(X+#zDr#Ib;hSz)Vu2W!F1GaShRL1#M799%v_@Ge(Om*hrEnb}EhG5cJ?&$M_e zUYNq|a7s|D#6mQQyI|28wfn{{to(tDejy@4Q#CpQS-9tYZ4qf?aA;s;2#WA!+@DuD Q9q1AUPgg&ebxsLQ0BK`La{vGU diff --git a/release/server/docroot/images/library.png b/release/server/docroot/images/library.png deleted file mode 100644 index 1a185057a328c0aa1c1dc75cd86edc7c57fd4449..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^d_XM3!3HF=W8NDADajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_c!wVp1HAr-ftOmgIFFyLU(e7N_E?uSI)z{yz+LAF-Q#Ujcs zZ#l?moIhc~s3=UPDKl(yc`FJ7UWr@xi3r@U9dp;?^CGY#a--2Ix*DcPSV;QVE x>$v=)BoWiD-3w0*^-~1kIcOQ#E#f}N(&!?EHl96Qx+=389HzTS%zdO zichKTL#W}7xO~clq>vGWX>BPj;t;Q;EY!9LPnrN(`krP!#09A4Lqho$mQU&K!{Kis z(Q$}YR+1g3gV%?o)*d4_(Tt|j(NsEWA@x!zxp6w0O6liAQcISh<3nn-zG3ZCbn^zz ihcxI#4URYj2rvMR$xk-q0jcBw0000{( zJaZG%Q-e|yQz{EjrrH1%X?wajhE&{2N?5?KW!tuY=?mB;wq{&eB$yzmd^bmClcQPI i!4<5BPcStwFf(Md8T7mf@@N5SWAJqKb6Mw<&;$UgGbzdd diff --git a/release/server/docroot/images/next@2x.png b/release/server/docroot/images/next@2x.png deleted file mode 100644 index ec4feb220534dfd6107e93a2b65fb7ef17ad94b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmV-Z0j&OsP)MwIvpFaV2?%kdd*&=&vz002ovPDHLkV1i%%fOr4^ diff --git a/release/server/docroot/images/prev.png b/release/server/docroot/images/prev.png deleted file mode 100644 index 43e4805e3916fdecdebc1a9dc8fc3a31521c50b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoX!3HE#i{( zJaZG%Q-e|yQz{EjrrH1%*?77*hE&{2N>E^kijJ0T_+ihy_P`3(#bP~C3~W7HwlT0o zG~5vE_#Pe}ZhYyAS{2L96|RfLcoVxBn0Od&TlgCvd$uA8Xbyv?tDnm{r-UW|QRgn` diff --git a/release/server/docroot/images/prev@2x.png b/release/server/docroot/images/prev@2x.png deleted file mode 100644 index d505f4f51dff9bd246dd7948942d507848d9341e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345 zcmV-f0jBYnD$VQWAX zL68vH5Hv&<1QC%8K}94%kP*=kbVL+{0dWXnLF_`95StJ-L=eJ=SV3433kWk}hOi?h zNDT-djpm&l@tF~km#H8cQ%RgOd(CcMT8?vR`5Ae95q_Txy3|_AJu)4?5;(cYX6E-p zB*!eTD8!icrI8d9zQz+`wjWkxnEj_N5$3q~K!S-Y2N7W63v}R^w2~<>CcTIaipgs$ r0AlhRJz$u!)*BGUmJWb|c?&QABjnXf3&W2300000NkvXXu0mjf*A#>Z diff --git a/release/server/docroot/images/read.png b/release/server/docroot/images/read.png deleted file mode 100644 index 9465a7d5f4727667be0605a7591744bf0dcc14c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)P!3HG%MVKuHQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JimW_c978H@C7n5a`uF(;7B$~lM>w76b4UMKbLh*2~7aVH!tk~ diff --git a/release/server/docroot/images/read@2x.png b/release/server/docroot/images/read@2x.png deleted file mode 100644 index 68ed871530b0ffc5740ec6f6336ab2690ad2dbec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^d_XM3!3HF=W8NDADajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_c!wVp1HAr-fh&YV8|`+S3Z3`5d!&&g`F4q_=u3Oqaw74{dH z7*ibGX7oA;OHNds5L3jsO7du0Qcj7>C7$gw7r3q9m6+AJQE+vdnA5C+mR*d2W=YIC w6?2YvoM%nBZLw;im{cUk5`kB@IRp|IN*0AX-jET)X7KQ01>=#%OA)*d*Z(j?D)T5veqeAlU2&)F(Psyp2K@$y sPXVO~wme6&j-)X#Yf4?@W#BMiDDE)I+JE*$8qh`tPgg&ebxsLQ0Ful_p#T5? diff --git a/release/server/docroot/images/readMark@2x.png b/release/server/docroot/images/readMark@2x.png deleted file mode 100644 index 1d9d0d3e3a3dab8d7259402b47f02d5172ec407e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^azJdx!3HERoY(vbq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c6`k^QaSW-r_2$My&SnDv)(73fH+)}l+&v&@3tme#bd9y_{rM!qFj5E+OD_+S8&|VT6^}zU*3J!?nxxH n6qK4ADKy%4PbhI8s{}&@XA@`A!!uPtUom*P`njxgN@xNA$RK!! diff --git a/release/server/docroot/images/readingMark.png b/release/server/docroot/images/readingMark.png deleted file mode 100644 index e37f3c80cd812942ac988e20df154626baba7ae7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+t!3HE3PrP~@NJ*BsMwA5SrL11q z;e{rivmB*lBz+~s8Zu(o3?5#rU_8=zDT3GG`X7c!WgZ2|4-C`OCNMdd^k%S0I9*+s zv5#TvN9KJOT2EOY;$^rd@w_pjVTuORO7@q`90m+?jwnqyx_IMSpxq3fu6{1-oD!M< D)h9`8 diff --git a/release/server/docroot/images/readingMark@2x.png b/release/server/docroot/images/readingMark@2x.png deleted file mode 100644 index 589e2e9bf8474511263dd76023add1e2358d48e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^azJdx!3HERoY(vbq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~-c6`k^QaSW-r_2$M~&K3h6wg)$QS;PyPr4LFU>^v7J^PtY6 zNqL9kdP^mb9h>E^z3SgCpk?|*QA}scru?>Q?DRqy2wTV(w^AtCwe m3XxTXbrn2&x2 diff --git a/release/server/docroot/images/up.png b/release/server/docroot/images/up.png deleted file mode 100644 index b039b35f6f26beee4034541f13a226488f7d603a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+s!3HG#4~4G+Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jid;Qi978H@B_$kSj*5={|9En`id%ANsi`vaMuugAbJe1h z?aTt}RE`|icAO%iC(POP_%rv;A{Whsqy-E;S#no>1Q=K(7;f2_>xnB$^Z^ZI@O1Ta JS?83{1OPAQFaiJo diff --git a/release/server/docroot/images/up@2x.png b/release/server/docroot/images/up@2x.png deleted file mode 100644 index d990ce0d8fb2cf6386608432f9a5e8cf48161078..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 271 zcmV+q0r38bP)ug1}Ww%}+*tvEbT3l1+-i^CJu;P6JT z;)p=6;D|!ca73d2a73fOaMW)t6g|L4^C9w1pEcI~=x!>)gb5QSOqeiX!twPLU;r+0 Vp{p>?rG@|i002ovPDHLkV1h>9Zu - - - - - Login - - -
- -

LOGIN

-

YACREADER LIBRARY

- -
- - -

If you have forgotten your login information, please reset it on the YACReaderLibrary

-
 
-
-
-
 
- - \ No newline at end of file diff --git a/release/server/templates/folder.tpl b/release/server/templates/folder.tpl deleted file mode 100644 index cb13a164..00000000 --- a/release/server/templates/folder.tpl +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - Folder - - -
-
- -
-
{if pageIndex} {end pageIndex} up
- - -
- {if device.ipad} -

{folder.name}

- {end device.ipad} -
- -
- Libraries {library.name} {loop path} {path.name} {end path} -
-
- {if pageIndex} - - - {end pageIndex} - - {if alphaIndex} - - - {end alphaIndex} - -
-
- - -
-
    - {loop element} -
  • -
    - {element.cover.browse} {element.cover.browse.end} -
    -
    -

    {element.name}

    -
    -
    {element.pages} {element.size} -
    -
    {element.download} {element.read} {element.browse} -
    -
    - {element.status} -
  • - {end element} -
-
 
-
-
- - {if index} -
- {if alphaIndex} - -
- -
 
-
- - {end alphaIndex} - - - {if pageIndex} - -
- -
 
-
- {end pageIndex} -
- {end index} - - - - - diff --git a/release/server/templates/libraries.tpl b/release/server/templates/libraries.tpl deleted file mode 100644 index 0de6f4d9..00000000 --- a/release/server/templates/libraries.tpl +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - Libraries - - -
-

Libraries

-

-

    - {loop library} -
  • -
    - -
    -   -
     
    -
  • - {end library} -
-

-
- - From 4720705cf6b764fd45aec96fe5f0543e9242a7e4 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Fri, 27 Feb 2026 16:22:06 +0100 Subject: [PATCH 05/26] Remove useStyledTemplate --- YACReaderLibrary/themes/theme.h | 7 ------ YACReaderLibrary/themes/theme_factory.cpp | 29 +++++++---------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index 11dd94ad..42017d81 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -197,13 +197,6 @@ struct TreeViewThemeTemplates { "QTreeView::branch:has-children:selected:!has-siblings:closed,QTreeView::branch:closed:selected:has-children:has-siblings {border-image: none;image: url('%6');}" "QTreeView::branch:open:has-children:!has-siblings,QTreeView::branch:open:has-children:has-siblings {border-image: none;image: url('%7');}" "QTreeView::branch:open:has-children:selected:!has-siblings,QTreeView::branch:open:has-children:selected:has-siblings {border-image: none;image: url('%7');}"; - - // Native tree view template (uses system scroll bars) - for macOS - QString nativeTreeViewQSS = "QTreeView {background-color:transparent; border: none;}" - "QTreeView::item:selected {background-color:%1; border-top: 1px solid %1; border-left:none;border-right:none;border-bottom:1px solid %1;}" - "QTreeView::branch:selected {background-color:%1; border-top: 1px solid %1; border-left:none;border-right:none;border-bottom:1px solid %1;}" - "QTreeView::branch:open:selected:has-children {image: url(':/images/sidebar/expanded_branch_osx.png');}" - "QTreeView::branch:closed:selected:has-children {image: url(':/images/sidebar/collapsed_branch_osx.png');}"; }; struct TreeViewTheme { diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 75cb914a..0d8aaa37 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -101,18 +101,12 @@ struct ImportWidgetParams { struct TreeViewParams { TreeViewThemeTemplates t; - bool useStyledTemplate; // true for non-macOS themes, false for macOS themes - // For styled template: %1=text, %2=selection bg, %3=scroll bg, %4=scroll handle, %5=selected text QColor textColor; QColor selectionBackgroundColor; QColor scrollBackgroundColor; QColor scrollHandleColor; QColor selectedTextColor; - - // For native (macOS) template: %1=selection color - QColor nativeSelectionColor; - QColor folderIndicatorColor; }; @@ -642,18 +636,14 @@ Theme makeTheme(const ThemeParams ¶ms) // TreeView (must come after SidebarIcons for branch icon paths) const auto &tv = params.treeViewParams; - if (tv.useStyledTemplate) { - theme.treeView.treeViewQSS = tv.t.styledTreeViewQSS - .arg(tv.textColor.name(), - tv.selectionBackgroundColor.name(), - tv.scrollBackgroundColor.name(), - tv.scrollHandleColor.name(), - tv.selectedTextColor.name(), - theme.sidebarIcons.branchClosedIconPath, - theme.sidebarIcons.branchOpenIconPath); - } else { - theme.treeView.treeViewQSS = tv.t.nativeTreeViewQSS.arg(tv.nativeSelectionColor.name()); - } + theme.treeView.treeViewQSS = tv.t.styledTreeViewQSS + .arg(tv.textColor.name(), + tv.selectionBackgroundColor.name(), + tv.scrollBackgroundColor.name(), + tv.scrollHandleColor.name(), + tv.selectedTextColor.name(), + theme.sidebarIcons.branchClosedIconPath, + theme.sidebarIcons.branchOpenIconPath); theme.treeView.folderIndicatorColor = tv.folderIndicatorColor; // end TreeView @@ -953,7 +943,6 @@ ThemeParams classicThemeParams() params.importWidgetParams = iw; TreeViewParams tv; - tv.useStyledTemplate = true; tv.textColor = QColor(0xDDDFDF); tv.selectionBackgroundColor = QColor(0x2E2E2E); tv.scrollBackgroundColor = QColor(0x404040); @@ -1205,7 +1194,6 @@ ThemeParams lightThemeParams() params.importWidgetParams = iw; TreeViewParams tv; - tv.useStyledTemplate = true; tv.textColor = Qt::black; tv.selectionBackgroundColor = QColor(0xD0D0D0); tv.scrollBackgroundColor = QColor(0xE0E0E0); @@ -1457,7 +1445,6 @@ ThemeParams darkThemeParams() params.importWidgetParams = iw; TreeViewParams tv; - tv.useStyledTemplate = true; tv.textColor = QColor(0xDDDFDF); tv.selectionBackgroundColor = QColor(0x2E2E2E); tv.scrollBackgroundColor = QColor(0x404040); From d71048b15275899b70974421c536d50f647eb2b0 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Fri, 27 Feb 2026 18:35:39 +0100 Subject: [PATCH 06/26] Fully customize the content views toolbar --- YACReaderLibrary/themes/theme.h | 7 +++---- YACReaderLibrary/themes/theme_factory.cpp | 13 ++++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index 42017d81..f02f13b6 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -255,10 +255,9 @@ struct ContentSplitterThemeTemplates { }; struct ComicsViewToolbarThemeTemplates { - QString toolbarQSS = R"( - QToolBar { border: none; } - QToolButton:checked { background-color: %1; } - )"; + QString toolbarQSS = "QToolBar { border: none; background: %1; }\n" + "QToolBar::separator { background: %2; width: 1px; margin: 5px 4px; }\n" + "QToolButton:checked { background-color: %3; }\n"; }; struct SearchLineEditThemeTemplates { diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 0d8aaa37..80f2ee09 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -213,6 +213,8 @@ struct LibraryItemParams { struct ComicsViewToolbarParams { ComicsViewToolbarThemeTemplates t; + QColor backgroundColor; + QColor separatorColor; QColor checkedBackgroundColor; QColor iconColor; // Main icon color (replaces #f0f) }; @@ -669,7 +671,10 @@ Theme makeTheme(const ThemeParams ¶ms) return icon; }; - theme.comicsViewToolbar.toolbarQSS = cvt.t.toolbarQSS.arg(cvt.checkedBackgroundColor.name()); + theme.comicsViewToolbar.toolbarQSS = cvt.t.toolbarQSS + .arg(cvt.backgroundColor.name()) + .arg(cvt.separatorColor.name()) + .arg(cvt.checkedBackgroundColor.name()); theme.comicsViewToolbar.openInYACReaderIcon = makeComicsViewIcon(":/images/comics_view_toolbar/openInYACReader.svg"); theme.comicsViewToolbar.setAsReadIcon = makeComicsViewIcon(":/images/comics_view_toolbar/setReadButton.svg"); theme.comicsViewToolbar.setAsUnreadIcon = makeComicsViewIcon(":/images/comics_view_toolbar/setUnread.svg"); @@ -1024,6 +1029,8 @@ ThemeParams classicThemeParams() params.libraryItemParams = li; ComicsViewToolbarParams cvt; + cvt.backgroundColor = QColor(0xF0F0F0); + cvt.separatorColor = QColor(0xCCCCCC); cvt.checkedBackgroundColor = QColor(0xCCCCCC); cvt.iconColor = QColor(0x404040); params.comicsViewToolbarParams = cvt; @@ -1275,6 +1282,8 @@ ThemeParams lightThemeParams() params.libraryItemParams = li; ComicsViewToolbarParams cvt; + cvt.backgroundColor = QColor(0xF0F0F0); + cvt.separatorColor = QColor(0xCCCCCC); cvt.checkedBackgroundColor = QColor(0xCCCCCC); cvt.iconColor = QColor(0x404040); params.comicsViewToolbarParams = cvt; @@ -1526,6 +1535,8 @@ ThemeParams darkThemeParams() params.libraryItemParams = li; ComicsViewToolbarParams cvt; + cvt.backgroundColor = QColor(0x2A2A2A); + cvt.separatorColor = QColor(0x444444); cvt.checkedBackgroundColor = QColor(0x555555); cvt.iconColor = QColor(0xDDDDDD); params.comicsViewToolbarParams = cvt; From b62ce07b15efadbe695bd7efe71638f592b26283 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 09:13:20 +0100 Subject: [PATCH 07/26] Simplify the sidebar splitter theming --- YACReaderLibrary/themes/theme.h | 12 ++--------- YACReaderLibrary/themes/theme_factory.cpp | 25 ----------------------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index f02f13b6..403394d8 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -136,20 +136,12 @@ struct EmptyContainerTheme { QMap emptyLabelIcons; // Keyed by YACReader::LabelColors enum value }; -struct SidebarThemeTemplates { - // Non-macOS splitter template: %1 = background color, %2 = height - QString styledSplitterQSS = "QSplitter::handle { image: none; background-color: %1; }" - "QSplitter::handle:vertical { height: %2px;}"; - - // macOS splitter template: %1 = height, %2 = background color - QString nativeSplitterQSS = "QSplitter::handle:vertical { height: %1px; background-color: %2;}"; -}; - struct SidebarTheme { QColor backgroundColor; QColor separatorColor; QColor sectionSeparatorColor; // Horizontal separators between sidebar sections - QString splitterQSS; + QString splitterQSS = "QSplitter::handle { image: none; background-color: transparent; }" + "QSplitter::handle:vertical { height: 39px; }"; // When true, section title strings are uppercased after translation bool uppercaseLabels; diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 80f2ee09..1da37a49 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -64,17 +64,10 @@ struct EmptyContainerParams { }; struct SidebarParams { - SidebarThemeTemplates t; - bool useStyledSplitter; // true for non-macOS, false for macOS - QColor backgroundColor; QColor separatorColor; QColor sectionSeparatorColor; // Horizontal separators between sidebar sections - // Splitter parameters - QColor splitterBackgroundColor; - int splitterHeight; - bool uppercaseLabels; // Title bar colors @@ -420,15 +413,6 @@ Theme makeTheme(const ThemeParams ¶ms) theme.sidebar.backgroundColor = sb.backgroundColor; theme.sidebar.separatorColor = sb.separatorColor; theme.sidebar.sectionSeparatorColor = sb.sectionSeparatorColor; - if (sb.useStyledSplitter) { - theme.sidebar.splitterQSS = sb.t.styledSplitterQSS - .arg(sb.splitterBackgroundColor.name()) - .arg(sb.splitterHeight); - } else { - theme.sidebar.splitterQSS = sb.t.nativeSplitterQSS - .arg(sb.splitterHeight) - .arg(sb.splitterBackgroundColor.name()); - } theme.sidebar.uppercaseLabels = sb.uppercaseLabels; theme.sidebar.titleTextColor = sb.titleTextColor; theme.sidebar.titleDropShadowColor = sb.titleDropShadowColor; @@ -921,12 +905,9 @@ ThemeParams classicThemeParams() params.emptyContainerParams = ec; SidebarParams sb; - sb.useStyledSplitter = true; sb.backgroundColor = QColor(0x454545); sb.separatorColor = QColor(0xBDBFBF); sb.sectionSeparatorColor = QColor(0x575757); - sb.splitterBackgroundColor = QColor(0x454545); - sb.splitterHeight = 39; sb.uppercaseLabels = true; sb.titleTextColor = QColor(0xBDBFBF); sb.titleDropShadowColor = Qt::black; @@ -1174,12 +1155,9 @@ ThemeParams lightThemeParams() params.emptyContainerParams = ec; SidebarParams sb; - sb.useStyledSplitter = true; sb.backgroundColor = QColor(0xF1F1F1); sb.separatorColor = QColor(0x808080); sb.sectionSeparatorColor = QColor(0xD0D0D0); - sb.splitterBackgroundColor = QColor(0xF1F1F1); - sb.splitterHeight = 39; sb.uppercaseLabels = true; sb.titleTextColor = QColor(0x808080); sb.titleDropShadowColor = QColor(0xFFFFFF); @@ -1427,12 +1405,9 @@ ThemeParams darkThemeParams() params.emptyContainerParams = ec; SidebarParams sb; - sb.useStyledSplitter = true; sb.backgroundColor = QColor(0x454545); sb.separatorColor = QColor(0xBDBFBF); sb.sectionSeparatorColor = QColor(0x575757); - sb.splitterBackgroundColor = QColor(0x454545); - sb.splitterHeight = 39; sb.uppercaseLabels = true; sb.titleTextColor = QColor(0xBDBFBF); sb.titleDropShadowColor = Qt::black; From 61a0b590eddb61243f71c871e0ba3c8b1be289d0 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 09:53:48 +0100 Subject: [PATCH 08/26] Add more parameters to control library item style --- YACReaderLibrary/themes/theme_factory.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 1da37a49..989aaf8d 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -199,7 +199,9 @@ struct LibraryItemParams { QColor textColor; QColor selectedTextColor; QColor selectedBackgroundColor; - QColor libraryIconSelectedColor; // Color for the library icon when selected + QColor libraryIconColor; + QColor libraryIconShadowColor; + QColor libraryIconSelectedColor; QColor libraryOptionsIconColor; // Color for the options icon (shown only when selected) }; @@ -209,7 +211,7 @@ struct ComicsViewToolbarParams { QColor backgroundColor; QColor separatorColor; QColor checkedBackgroundColor; - QColor iconColor; // Main icon color (replaces #f0f) + QColor iconColor; }; struct SearchLineEditParams { @@ -586,8 +588,15 @@ Theme makeTheme(const ThemeParams ¶ms) theme.sidebarIcons.folderIcon = makeSidebarIcon(":/images/sidebar/folder.svg"); theme.sidebarIcons.folderFinishedIcon = makeSidebarIconWithExtra(":/images/sidebar/folder_finished.svg"); - // Library icon (unselected state uses sidebar colors) - theme.sidebarIcons.libraryIcon = makeSidebarIcon(":/images/sidebar/libraryIcon.svg"); + // Library icon (unselected state, two-color: #f0f main, #0ff shadow) + { + const auto &li = params.libraryItemParams; + const QString libraryIconPath = recoloredSvgToThemeFile(":/images/sidebar/libraryIcon.svg", li.libraryIconColor, li.libraryIconShadowColor, params.themeName); + QIcon icon; + icon.addFile(libraryIconPath, QSize(), QIcon::Normal, QIcon::Off); + icon.addFile(libraryIconPath, QSize(), QIcon::Selected, QIcon::Off); + theme.sidebarIcons.libraryIcon = icon; + } // Action icons theme.sidebarIcons.newLibraryIcon = makeSidebarIcon(":/images/sidebar/newLibraryIcon.svg"); @@ -1003,6 +1012,8 @@ ThemeParams classicThemeParams() LibraryItemParams li; li.textColor = QColor(0xDDDFDF); + li.libraryIconColor = QColor(0xDDDFDF); + li.libraryIconShadowColor = QColor(0xFF000000); li.selectedTextColor = Qt::white; li.selectedBackgroundColor = QColor(0x2E2E2E); li.libraryIconSelectedColor = Qt::white; @@ -1253,6 +1264,8 @@ ThemeParams lightThemeParams() LibraryItemParams li; li.textColor = QColor(0x404040); + li.libraryIconColor = QColor(0x404040); + li.libraryIconShadowColor = QColor(0xFFFFFF); li.selectedTextColor = QColor(0x1A1A1A); li.selectedBackgroundColor = QColor(0xD0D0D0); li.libraryIconSelectedColor = QColor(0x404040); @@ -1503,6 +1516,8 @@ ThemeParams darkThemeParams() LibraryItemParams li; li.textColor = QColor(0xDDDFDF); + li.libraryIconColor = QColor(0xDDDFDF); + li.libraryIconShadowColor = QColor(0xFF000000); li.selectedTextColor = Qt::white; li.selectedBackgroundColor = QColor(0x2E2E2E); li.libraryIconSelectedColor = Qt::white; From 7e7c6a979c472e86252259c8ea328624fb4d56f1 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 18:20:13 +0100 Subject: [PATCH 09/26] Add TODO to document bug in recolorSvgXML --- common/themes/icon_utils.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/themes/icon_utils.cpp b/common/themes/icon_utils.cpp index f0ca5f9d..680a78a8 100644 --- a/common/themes/icon_utils.cpp +++ b/common/themes/icon_utils.cpp @@ -66,6 +66,9 @@ QString recolorSvgXML(QString &svg, const QString &placeHolder, const QColor &color) { + // TODO: svg colors can work without ;, we need to update all the svg files to inlude ; + // Include the trailing ';' so e.g. "#ff0;" never accidentally matches + // inside a previously-substituted value like "#ff0000;". return svg.replace(placeHolder, color.name(QColor::HexRgb), Qt::CaseInsensitive); } From 2beb00c65f05474ff999aed53cce5c8e7e020634 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 18:30:51 +0100 Subject: [PATCH 10/26] Add more custom colors to the side bar elements so we can theme selected items --- YACReaderLibrary/db/folder_model.cpp | 4 +- YACReaderLibrary/db/reading_list_item.cpp | 2 +- YACReaderLibrary/themes/theme.h | 23 +-- YACReaderLibrary/themes/theme_factory.cpp | 168 +++++++++++++----- YACReaderLibrary/yacreader_folders_view.cpp | 12 +- .../yacreader_reading_lists_view.cpp | 8 +- 6 files changed, 156 insertions(+), 61 deletions(-) diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index d659a19c..8a71c9c2 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -144,8 +144,8 @@ void FolderModel::applyTheme(const Theme &theme) folderIcon = QFileIconProvider().icon(QFileIconProvider::Folder); folderFinishedIcon = drawFinishedFolderIcon(sidebarIcons.folderReadOverlay); } else { - folderIcon = sidebarIcons.folderIcon; - folderFinishedIcon = sidebarIcons.folderFinishedIcon; + folderIcon = theme.treeView.folderIcon; + folderFinishedIcon = theme.treeView.folderFinishedIcon; } } diff --git a/YACReaderLibrary/db/reading_list_item.cpp b/YACReaderLibrary/db/reading_list_item.cpp index 98e3bf57..e403f2ed 100644 --- a/YACReaderLibrary/db/reading_list_item.cpp +++ b/YACReaderLibrary/db/reading_list_item.cpp @@ -153,7 +153,7 @@ QIcon ReadingListItem::getIcon() const else if (theme.sidebarIcons.useSystemFolderIcons) return QFileIconProvider().icon(QFileIconProvider::Folder); else - return theme.sidebarIcons.folderIcon; // sublist + return theme.treeView.folderIcon; // sublist } int ReadingListItem::childCount() const diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index 403394d8..a755d386 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -186,14 +186,24 @@ struct TreeViewThemeTemplates { "QScrollBar::down-arrow:vertical {border:none;width: 9px;height: 6px;background: url(':/images/folders_view/line-down.png') center top no-repeat;}" "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {background: none; }" "QTreeView::branch:has-children:!has-siblings:closed,QTreeView::branch:closed:has-children:has-siblings {border-image: none;image: url('%6');}" - "QTreeView::branch:has-children:selected:!has-siblings:closed,QTreeView::branch:closed:selected:has-children:has-siblings {border-image: none;image: url('%6');}" + "QTreeView::branch:has-children:selected:!has-siblings:closed,QTreeView::branch:closed:selected:has-children:has-siblings {border-image: none;image: url('%8');}" "QTreeView::branch:open:has-children:!has-siblings,QTreeView::branch:open:has-children:has-siblings {border-image: none;image: url('%7');}" - "QTreeView::branch:open:has-children:selected:!has-siblings,QTreeView::branch:open:has-children:selected:has-siblings {border-image: none;image: url('%7');}"; + "QTreeView::branch:open:has-children:selected:!has-siblings,QTreeView::branch:open:has-children:selected:has-siblings {border-image: none;image: url('%9');}"; }; struct TreeViewTheme { QString treeViewQSS; QColor folderIndicatorColor; // For incomplete folders and recently updated folders + + // Branch indicator icon paths (used by QSS url()) + QString branchClosedIconPath; + QString branchOpenIconPath; + QString branchClosedIconSelectedPath; + QString branchOpenIconSelectedPath; + + // Folder icons (normal and selected states, including finished/read tick variant) + QIcon folderIcon; + QIcon folderFinishedIcon; }; // QML view theme colors (used by GridComicsView, FolderContentView, InfoComicsView) @@ -266,14 +276,10 @@ struct ContentSplitterTheme { struct SidebarIconsTheme { // When true, use QFileIconProvider for folder icons and overlay folderReadOverlay for finished folders - // When false, use the themed folderIcon and folderFinishedIcon SVGs + // When false, use the themed folderIcon and folderFinishedIcon from TreeViewTheme bool useSystemFolderIcons; QPixmap folderReadOverlay; // Tick overlay drawn on system folder icons when useSystemFolderIcons is true - // Folder icons (for FolderModel, ReadingListItem) - QIcon folderIcon; - QIcon folderFinishedIcon; - // Library icon (for YACReaderLibraryItemWidget - unselected state) QIcon libraryIcon; @@ -288,9 +294,6 @@ struct SidebarIconsTheme { QIcon addLabelIcon; QIcon renameListIcon; - // Branch icons (for TreeView QSS) - QString branchClosedIconPath; - QString branchOpenIconPath; }; struct LibraryItemTheme { diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 989aaf8d..1dc4c077 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -101,6 +101,18 @@ struct TreeViewParams { QColor scrollHandleColor; QColor selectedTextColor; QColor folderIndicatorColor; + + // Branch indicator icon colors (independent of sidebarIcons.iconColor) + QColor branchIndicatorColor; + QColor branchIndicatorSelectedColor; + + // Folder icon colors (own parameters, independent of sidebarIcons) + QColor folderIconColor; // Main color for unselected folder (#f0f) + QColor folderIconShadowColor; // Shadow color for unselected folder (#0ff) + QColor folderIconSelectedColor; // Main color for selected folder (#f0f) + QColor folderIconSelectedShadowColor; // Shadow color for selected folder (#0ff) + QColor folderReadOverlayColor; // Tick/checkmark color for unselected folder (#ff0 in folder_finished, #f0f in folder_read_overlay.svg) + QColor folderReadOverlaySelectedColor; // Tick/checkmark color for selected folder }; struct TableViewParams { @@ -179,11 +191,9 @@ struct SidebarIconsParams { // Icon colors - #f0f placeholder gets replaced with these QColor iconColor; // Main icon color (replaces #f0f) QColor shadowColor; // Shadow color (replaces #0ff) - QColor extraColor; // Extra info like ticks (replaces #ff0) // When true, use QFileIconProvider for folder icons and overlay a tick for finished folders bool useSystemFolderIcons; - QColor folderReadOverlayColor; // Color for the tick overlay (replaces #f0f in folder_read_overlay.svg) }; struct ServerConfigDialogThemeTemplates { @@ -225,18 +235,27 @@ struct SearchLineEditParams { struct ReadingListIconsParams { QMap labelColors; // Label colors by name (e.g., "red" -> #f67a7b) QColor labelShadowColor; // Shadow color for labels (replaces #0ff) + QColor labelShadowSelectedColor; // Shadow color for labels when selected/hovered // Special list icon colors QColor readingListMainColor; // default_0 main color (replaces #f0f) + QColor readingListMainSelectedColor; // default_0 main color when selected/hovered QColor favoritesMainColor; // default_1 main color (replaces #f0f) + QColor favoritesMainSelectedColor; // default_1 main color when selected/hovered QColor currentlyReadingMainColor; // default_2 main color (replaces #f0f) + QColor currentlyReadingMainSelectedColor; // default_2 main color when selected/hovered QColor currentlyReadingOuterColor; // default_2 outer circle (replaces #ff0) + QColor currentlyReadingOuterSelectedColor; // default_2 outer circle when selected/hovered QColor specialListShadowColor; // Shadow color for special lists (replaces #0ff) + QColor specialListShadowSelectedColor; // Shadow color for special lists when selected/hovered // List icon colors QColor listMainColor; // main color (replaces #f0f) + QColor listMainSelectedColor; // main color when selected/hovered QColor listShadowColor; // shadow color (replaces #0ff) + QColor listShadowSelectedColor; // shadow color when selected/hovered QColor listDetailColor; // detail/checkbox color (replaces #ff0) + QColor listDetailSelectedColor; // detail/checkbox color when selected/hovered }; struct DialogIconsParams { @@ -559,15 +578,6 @@ Theme makeTheme(const ThemeParams ¶ms) return icon; }; - // Helper for icons with extra color (three-color: #f0f main, #0ff shadow, #ff0 extra) - auto makeSidebarIconWithExtra = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, si.iconColor, si.shadowColor, si.extraColor, params.themeName); - QIcon icon; - icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); - icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); - return icon; - }; - // Helper for single-color icons (only #f0f main) auto makeSingleColorIcon = [&](const QString &basePath) { const QString path = recoloredSvgToThemeFile(basePath, si.iconColor, params.themeName); @@ -580,14 +590,10 @@ Theme makeTheme(const ThemeParams ¶ms) // System folder icons flag and overlay theme.sidebarIcons.useSystemFolderIcons = si.useSystemFolderIcons; if (si.useSystemFolderIcons) { - const QString overlayPath = recoloredSvgToThemeFile(":/images/sidebar/folder_read_overlay.svg", si.folderReadOverlayColor, params.themeName); + const QString overlayPath = recoloredSvgToThemeFile(":/images/sidebar/folder_read_overlay.svg", params.treeViewParams.folderReadOverlayColor, params.themeName); theme.sidebarIcons.folderReadOverlay = QPixmap(overlayPath); } - // Folder icons - theme.sidebarIcons.folderIcon = makeSidebarIcon(":/images/sidebar/folder.svg"); - theme.sidebarIcons.folderFinishedIcon = makeSidebarIconWithExtra(":/images/sidebar/folder_finished.svg"); - // Library icon (unselected state, two-color: #f0f main, #0ff shadow) { const auto &li = params.libraryItemParams; @@ -609,9 +615,6 @@ Theme makeTheme(const ThemeParams ¶ms) theme.sidebarIcons.addLabelIcon = makeSidebarIcon(":/images/sidebar/addLabelIcon.svg"); theme.sidebarIcons.renameListIcon = makeSidebarIcon(":/images/sidebar/renameListIcon.svg"); - // Branch icons (paths for QSS) - theme.sidebarIcons.branchClosedIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", si.iconColor, params.themeName); - theme.sidebarIcons.branchOpenIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", si.iconColor, params.themeName); // end SidebarIcons // LibraryItem @@ -629,17 +632,42 @@ Theme makeTheme(const ThemeParams ¶ms) theme.libraryItem.libraryOptionsIcon = QIcon(libraryOptionsPath); // end LibraryItem - // TreeView (must come after SidebarIcons for branch icon paths) + // TreeView const auto &tv = params.treeViewParams; + + // Branch indicator icons — own colors, independent of the sidebar icon color + theme.treeView.branchClosedIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorColor, params.themeName); + theme.treeView.branchOpenIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorColor, params.themeName); + theme.treeView.branchClosedIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorSelectedColor, params.themeName, { .suffix = "_selected" }); + theme.treeView.branchOpenIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorSelectedColor, params.themeName, { .suffix = "_selected" }); + theme.treeView.treeViewQSS = tv.t.styledTreeViewQSS .arg(tv.textColor.name(), tv.selectionBackgroundColor.name(), tv.scrollBackgroundColor.name(), tv.scrollHandleColor.name(), tv.selectedTextColor.name(), - theme.sidebarIcons.branchClosedIconPath, - theme.sidebarIcons.branchOpenIconPath); + theme.treeView.branchClosedIconPath, + theme.treeView.branchOpenIconPath, + theme.treeView.branchClosedIconSelectedPath, + theme.treeView.branchOpenIconSelectedPath); theme.treeView.folderIndicatorColor = tv.folderIndicatorColor; + + // Folder icon — normal and selected states with independent colors + { + const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconColor, tv.folderIconShadowColor, params.themeName); + const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, params.themeName, { .suffix = "_selected" }); + theme.treeView.folderIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + theme.treeView.folderIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); + } + + // Folder finished icon — same but with tick (#ff0) recolored independently for each state + { + const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconColor, tv.folderIconShadowColor, tv.folderReadOverlayColor, params.themeName); + const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, tv.folderReadOverlaySelectedColor, params.themeName, { .suffix = "_selected" }); + theme.treeView.folderFinishedIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + theme.treeView.folderFinishedIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); + } // end TreeView // ContentSplitter @@ -664,10 +692,10 @@ Theme makeTheme(const ThemeParams ¶ms) return icon; }; - theme.comicsViewToolbar.toolbarQSS = cvt.t.toolbarQSS - .arg(cvt.backgroundColor.name()) - .arg(cvt.separatorColor.name()) - .arg(cvt.checkedBackgroundColor.name()); + theme.comicsViewToolbar.toolbarQSS = cvt.t.toolbarQSS.arg( + cvt.backgroundColor.name(), + cvt.separatorColor.name(), + cvt.checkedBackgroundColor.name()); theme.comicsViewToolbar.openInYACReaderIcon = makeComicsViewIcon(":/images/comics_view_toolbar/openInYACReader.svg"); theme.comicsViewToolbar.setAsReadIcon = makeComicsViewIcon(":/images/comics_view_toolbar/setReadButton.svg"); theme.comicsViewToolbar.setAsUnreadIcon = makeComicsViewIcon(":/images/comics_view_toolbar/setUnread.svg"); @@ -705,10 +733,11 @@ Theme makeTheme(const ThemeParams ¶ms) // Helper to create label icons from template (uses color name to generate label_.svg files) auto makeLabelIcon = [&](const QString &colorName, const QColor &mainColor) { - const QString path = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowColor, params.themeName, { .fileName = "label_" + colorName }); + const QString normalPath = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowColor, params.themeName, { .fileName = "label_" + colorName }); + const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowSelectedColor, params.themeName, { .suffix = "_selected", .fileName = "label_" + colorName }); QIcon icon; - icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); - icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); + icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); return icon; }; @@ -717,32 +746,35 @@ Theme makeTheme(const ThemeParams ¶ms) } // Special list icons - auto makeSpecialIcon = [&](const QString &basePath, const QColor &mainColor) { - const QString path = recoloredSvgToThemeFile(basePath, mainColor, rli.specialListShadowColor, params.themeName); + auto makeSpecialIcon = [&](const QString &basePath, const QColor &mainColor, const QColor &mainSelectedColor) { + const QString normalPath = recoloredSvgToThemeFile(basePath, mainColor, rli.specialListShadowColor, params.themeName); + const QString selectedPath = recoloredSvgToThemeFile(basePath, mainSelectedColor, rli.specialListShadowSelectedColor, params.themeName, { .suffix = "_selected" }); QIcon icon; - icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); - icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); + icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); return icon; }; - theme.readingListIcons.readingListIcon = makeSpecialIcon(":/images/lists/default_0.svg", rli.readingListMainColor); - theme.readingListIcons.favoritesIcon = makeSpecialIcon(":/images/lists/default_1.svg", rli.favoritesMainColor); + theme.readingListIcons.readingListIcon = makeSpecialIcon(":/images/lists/default_0.svg", rli.readingListMainColor, rli.readingListMainSelectedColor); + theme.readingListIcons.favoritesIcon = makeSpecialIcon(":/images/lists/default_1.svg", rli.favoritesMainColor, rli.favoritesMainSelectedColor); // Currently reading has 3 colors { - const QString path = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainColor, rli.specialListShadowColor, rli.currentlyReadingOuterColor, params.themeName); + const QString normalPath = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainColor, rli.specialListShadowColor, rli.currentlyReadingOuterColor, params.themeName); + const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainSelectedColor, rli.specialListShadowSelectedColor, rli.currentlyReadingOuterSelectedColor, params.themeName, { .suffix = "_selected" }); QIcon icon; - icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); - icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); + icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); theme.readingListIcons.currentlyReadingIcon = icon; } // List icon (3 colors) { - const QString path = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainColor, rli.listShadowColor, rli.listDetailColor, params.themeName); + const QString normalPath = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainColor, rli.listShadowColor, rli.listDetailColor, params.themeName); + const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainSelectedColor, rli.listShadowSelectedColor, rli.listDetailSelectedColor, params.themeName, { .suffix = "_selected" }); QIcon icon; - icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); - icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); + icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); theme.readingListIcons.listIcon = icon; } // end ReadingListIcons @@ -944,6 +976,14 @@ ThemeParams classicThemeParams() tv.scrollHandleColor = QColor(0xDDDDDD); tv.selectedTextColor = Qt::white; tv.folderIndicatorColor = QColor(237, 197, 24); + tv.branchIndicatorColor = QColor(0xE0E0E0); + tv.branchIndicatorSelectedColor = QColor(0xFFFFFF); + tv.folderIconColor = QColor(0xE0E0E0); + tv.folderIconShadowColor = QColor(0xFF000000); + tv.folderIconSelectedColor = QColor(0xE0E0E0); + tv.folderIconSelectedShadowColor = QColor(0xFF000000); + tv.folderReadOverlayColor = QColor(0x464646); + tv.folderReadOverlaySelectedColor = QColor(0x464646); params.treeViewParams = tv; TableViewParams tav; @@ -1006,7 +1046,6 @@ ThemeParams classicThemeParams() SidebarIconsParams si; si.iconColor = QColor(0xE0E0E0); si.shadowColor = QColor(0xFF000000); - si.extraColor = QColor(0x464646); si.useSystemFolderIcons = false; params.sidebarIconsParams = si; @@ -1049,14 +1088,23 @@ ThemeParams classicThemeParams() { "dark", QColor(0xb7b7b7) } }; rli.labelShadowColor = Qt::black; + rli.labelShadowSelectedColor = Qt::black; rli.readingListMainColor = QColor(0xe7e7e7); + rli.readingListMainSelectedColor = QColor(0xe7e7e7); rli.favoritesMainColor = QColor(0xe15055); + rli.favoritesMainSelectedColor = QColor(0xe15055); rli.currentlyReadingMainColor = QColor(0xffcc00); + rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); rli.currentlyReadingOuterColor = Qt::black; + rli.currentlyReadingOuterSelectedColor = Qt::black; rli.specialListShadowColor = Qt::black; + rli.specialListShadowSelectedColor = Qt::black; rli.listMainColor = QColor(0xe7e7e7); + rli.listMainSelectedColor = QColor(0xe7e7e7); rli.listShadowColor = Qt::black; + rli.listShadowSelectedColor = Qt::black; rli.listDetailColor = QColor(0x464646); + rli.listDetailSelectedColor = QColor(0x464646); params.readingListIconsParams = rli; MenuIconsParams mi; @@ -1196,6 +1244,14 @@ ThemeParams lightThemeParams() tv.scrollHandleColor = QColor(0x888888); tv.selectedTextColor = QColor(0x1A1A1A); tv.folderIndicatorColor = QColor(85, 95, 127); + tv.branchIndicatorColor = QColor(0x606060); + tv.branchIndicatorSelectedColor = QColor(0x1A1A1A); + tv.folderIconColor = QColor(0x606060); + tv.folderIconShadowColor = QColor(0xFFFFFF); + tv.folderIconSelectedColor = QColor(0x606060); + tv.folderIconSelectedShadowColor = QColor(0xFFFFFF); + tv.folderReadOverlayColor = QColor(0xFFFFFF); + tv.folderReadOverlaySelectedColor = QColor(0xFFFFFF); params.treeViewParams = tv; TableViewParams tav; @@ -1258,7 +1314,6 @@ ThemeParams lightThemeParams() SidebarIconsParams si; si.iconColor = QColor(0x606060); si.shadowColor = QColor(0xFFFFFF); - si.extraColor = QColor(0xFFFFFF); si.useSystemFolderIcons = false; params.sidebarIconsParams = si; @@ -1301,14 +1356,23 @@ ThemeParams lightThemeParams() { "dark", QColor(0xb7b7b7) } }; rli.labelShadowColor = QColor(0xa0a0a0); + rli.labelShadowSelectedColor = QColor(0xa0a0a0); rli.readingListMainColor = QColor(0x808080); + rli.readingListMainSelectedColor = QColor(0x808080); rli.favoritesMainColor = QColor(0xe15055); + rli.favoritesMainSelectedColor = QColor(0xe15055); rli.currentlyReadingMainColor = QColor(0xffcc00); + rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); rli.currentlyReadingOuterColor = Qt::black; + rli.currentlyReadingOuterSelectedColor = Qt::black; rli.specialListShadowColor = QColor(0xa0a0a0); + rli.specialListShadowSelectedColor = QColor(0xa0a0a0); rli.listMainColor = QColor(0x808080); + rli.listMainSelectedColor = QColor(0x808080); rli.listShadowColor = QColor(0xc0c0c0); + rli.listShadowSelectedColor = QColor(0xc0c0c0); rli.listDetailColor = QColor(0xFFFFFF); + rli.listDetailSelectedColor = QColor(0xFFFFFF); params.readingListIconsParams = rli; MenuIconsParams mi; @@ -1448,6 +1512,14 @@ ThemeParams darkThemeParams() tv.scrollHandleColor = QColor(0xDDDDDD); tv.selectedTextColor = Qt::white; tv.folderIndicatorColor = QColor(237, 197, 24); + tv.branchIndicatorColor = QColor(0xE0E0E0); + tv.branchIndicatorSelectedColor = QColor(0xFFFFFF); + tv.folderIconColor = QColor(0xE0E0E0); + tv.folderIconShadowColor = QColor(0xFF000000); + tv.folderIconSelectedColor = QColor(0xE0E0E0); + tv.folderIconSelectedShadowColor = QColor(0xFF000000); + tv.folderReadOverlayColor = QColor(0x222222); + tv.folderReadOverlaySelectedColor = QColor(0x222222); params.treeViewParams = tv; TableViewParams tav; @@ -1510,7 +1582,6 @@ ThemeParams darkThemeParams() SidebarIconsParams si; si.iconColor = QColor(0xE0E0E0); si.shadowColor = QColor(0xFF000000); - si.extraColor = QColor(0x222222); si.useSystemFolderIcons = false; params.sidebarIconsParams = si; @@ -1553,14 +1624,23 @@ ThemeParams darkThemeParams() { "dark", QColor(0xb7b7b7) } }; rli.labelShadowColor = Qt::black; + rli.labelShadowSelectedColor = Qt::black; rli.readingListMainColor = QColor(0xe7e7e7); + rli.readingListMainSelectedColor = QColor(0xe7e7e7); rli.favoritesMainColor = QColor(0xe15055); + rli.favoritesMainSelectedColor = QColor(0xe15055); rli.currentlyReadingMainColor = QColor(0xffcc00); + rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); rli.currentlyReadingOuterColor = Qt::black; + rli.currentlyReadingOuterSelectedColor = Qt::black; rli.specialListShadowColor = Qt::black; + rli.specialListShadowSelectedColor = Qt::black; rli.listMainColor = QColor(0xe7e7e7); + rli.listMainSelectedColor = QColor(0xe7e7e7); rli.listShadowColor = Qt::black; + rli.listShadowSelectedColor = Qt::black; rli.listDetailColor = QColor(0x464646); + rli.listDetailSelectedColor = QColor(0x464646); params.readingListIconsParams = rli; MenuIconsParams mi; diff --git a/YACReaderLibrary/yacreader_folders_view.cpp b/YACReaderLibrary/yacreader_folders_view.cpp index 57f6f5b8..ce116bf6 100644 --- a/YACReaderLibrary/yacreader_folders_view.cpp +++ b/YACReaderLibrary/yacreader_folders_view.cpp @@ -81,6 +81,12 @@ YACReaderFoldersViewItemDeletegate::YACReaderFoldersViewItemDeletegate(QObject * void YACReaderFoldersViewItemDeletegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + // Promote hover to selected so QIcon::Selected mode activates on mouse-over, + // matching the QSS which already uses the same background for hover and selected. + QStyleOptionViewItem opt = option; + if (opt.state & QStyle::State_MouseOver) + opt.state |= QStyle::State_Selected; + // Get indicator color from parent tree view QColor indicatorColor(237, 197, 24); // Default fallback if (auto treeView = qobject_cast(parent())) { @@ -91,11 +97,11 @@ void YACReaderFoldersViewItemDeletegate::paint(QPainter *painter, const QStyleOp painter->save(); painter->setBrush(QBrush(indicatorColor)); painter->setPen(QPen(QBrush(), 0)); - painter->drawRect(0, option.rect.y(), 2, option.rect.height()); + painter->drawRect(0, opt.rect.y(), 2, opt.rect.height()); painter->restore(); } - QStyledItemDelegate::paint(painter, option, index); + QStyledItemDelegate::paint(painter, opt, index); auto showRecent = index.data(FolderModel::ShowRecentRole).toBool(); @@ -110,7 +116,7 @@ void YACReaderFoldersViewItemDeletegate::paint(QPainter *painter, const QStyleOp painter->setRenderHint(QPainter::Antialiasing); painter->setBrush(QBrush(indicatorColor)); painter->setPen(QPen(QBrush(), 0)); - painter->drawEllipse(option.rect.x() + 13, option.rect.y() + 2, 7, 7); + painter->drawEllipse(opt.rect.x() + 13, opt.rect.y() + 2, 7, 7); painter->restore(); } } diff --git a/YACReaderLibrary/yacreader_reading_lists_view.cpp b/YACReaderLibrary/yacreader_reading_lists_view.cpp index 6d3d3b40..62b4aea2 100644 --- a/YACReaderLibrary/yacreader_reading_lists_view.cpp +++ b/YACReaderLibrary/yacreader_reading_lists_view.cpp @@ -50,7 +50,13 @@ void YACReaderReadingListsViewItemDeletegate::paint(QPainter *painter, const QSt return; } - QStyledItemDelegate::paint(painter, option, index); + // Promote hover to selected so QIcon::Selected mode activates on mouse-over, + // matching the QSS which already uses the same background for hover and selected. + QStyleOptionViewItem opt = option; + if (opt.state & QStyle::State_MouseOver) + opt.state |= QStyle::State_Selected; + + QStyledItemDelegate::paint(painter, opt, index); } QSize YACReaderReadingListsViewItemDeletegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const From e10e6dcc88884d2f3faf647cd240ff803af58e79 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 19:05:42 +0100 Subject: [PATCH 11/26] Rename comics table view header parameters --- YACReaderLibrary/themes/theme_factory.cpp | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 1dc4c077..383b5485 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -120,9 +120,9 @@ struct TableViewParams { QColor alternateBackgroundColor; QColor backgroundColor; - QColor cornerButtonBackgroundColor; - QColor cornerButtonBorderColor; - QColor cornerButtonGradientColor; + QColor headerBackgroundColor; + QColor headerBorderColor; + QColor headerGradientColor; QColor itemBorderBottomColor; QColor itemBorderTopColor; QColor itemTextColor; @@ -469,9 +469,9 @@ Theme makeTheme(const ThemeParams ¶ms) theme.tableView.tableViewQSS = tavt.tableViewQSS .arg(tav.alternateBackgroundColor.name(), tav.backgroundColor.name(), - tav.cornerButtonBackgroundColor.name(), - tav.cornerButtonBorderColor.name(), - tav.cornerButtonGradientColor.name(), + tav.headerBackgroundColor.name(), + tav.headerBorderColor.name(), + tav.headerGradientColor.name(), tav.itemBorderBottomColor.name(), tav.itemBorderTopColor.name(), tav.itemTextColor.name(), @@ -989,9 +989,9 @@ ThemeParams classicThemeParams() TableViewParams tav; tav.alternateBackgroundColor = QColor(0xF2F2F2); tav.backgroundColor = QColor(0xFAFAFA); - tav.cornerButtonBackgroundColor = QColor(0xF5F5F5); - tav.cornerButtonBorderColor = QColor(0xB8BDC4); - tav.cornerButtonGradientColor = QColor(0xD1D1D1); + tav.headerBackgroundColor = QColor(0xF5F5F5); + tav.headerBorderColor = QColor(0xB8BDC4); + tav.headerGradientColor = QColor(0xD1D1D1); tav.itemBorderBottomColor = QColor(0xDFDFDF); tav.itemBorderTopColor = QColor(0xFEFEFE); tav.itemTextColor = QColor(0x252626); @@ -1257,9 +1257,9 @@ ThemeParams lightThemeParams() TableViewParams tav; tav.alternateBackgroundColor = QColor(0xF2F2F2); tav.backgroundColor = QColor(0xFAFAFA); - tav.cornerButtonBackgroundColor = QColor(0xF5F5F5); - tav.cornerButtonBorderColor = QColor(0xB8BDC4); - tav.cornerButtonGradientColor = QColor(0xD1D1D1); + tav.headerBackgroundColor = QColor(0xF5F5F5); + tav.headerBorderColor = QColor(0xB8BDC4); + tav.headerGradientColor = QColor(0xD1D1D1); tav.itemBorderBottomColor = QColor(0xDFDFDF); tav.itemBorderTopColor = QColor(0xFEFEFE); tav.itemTextColor = QColor(0x252626); @@ -1525,9 +1525,9 @@ ThemeParams darkThemeParams() TableViewParams tav; tav.alternateBackgroundColor = QColor(0x2E2E2E); tav.backgroundColor = QColor(0x2A2A2A); - tav.cornerButtonBackgroundColor = QColor(0x2A2A2A); - tav.cornerButtonBorderColor = QColor(0x1F1F1F); - tav.cornerButtonGradientColor = QColor(0x252525); + tav.headerBackgroundColor = QColor(0x2A2A2A); + tav.headerBorderColor = QColor(0x1F1F1F); + tav.headerGradientColor = QColor(0x252525); tav.itemBorderBottomColor = QColor(0x1F1F1F); tav.itemBorderTopColor = QColor(0x353535); tav.itemTextColor = QColor(0xDDDDDD); From 368b3bd35e56092fe43c3922627e8a7e9cfc414f Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 20:27:44 +0100 Subject: [PATCH 12/26] Add control over comics table view item top/bottom borders size --- YACReaderLibrary/themes/theme.h | 5 ++--- YACReaderLibrary/themes/theme_factory.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index a755d386..f5824c39 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -99,8 +99,8 @@ struct ComicFlowColors { struct TableViewThemeTemplates { QString tableViewQSS = "QTableView {alternate-background-color: %1; background-color: %2; outline: 0px; border: none;}" "QTableCornerButton::section {background-color:%3; border:none; border-bottom:1px solid %4; border-right:1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %5, stop: 1 %4);}" - "QTableView::item {outline: 0px; border-bottom: 1px solid %6; border-top: 1px solid %7; padding-bottom:1px; color:%8;}" - "QTableView::item:selected {outline: 0px; border-bottom: 1px solid %9; border-top: 1px solid %9; padding-bottom:1px; background-color: %9; color: %10; }" + "QTableView::item {outline: 0px; border-bottom: %12px solid %6; border-top: %13px solid %7; padding-bottom:1px; color:%8;}" + "QTableView::item:selected {outline: 0px; border-bottom: %12px solid %9; border-top: %13px solid %9; padding-bottom:1px; background-color: %9; color: %10; }" "QHeaderView::section:horizontal {background-color:%3; border-bottom:1px solid %4; border-right:1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %5, stop: 1 %4); border-left:none; border-top:none; padding:4px; color:%11;}" "QHeaderView::section:vertical {border-bottom: 1px solid %6; border-top: 1px solid %7;}"; }; @@ -293,7 +293,6 @@ struct SidebarIconsTheme { QIcon colapseIcon; QIcon addLabelIcon; QIcon renameListIcon; - }; struct LibraryItemTheme { diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 383b5485..30ca4e3f 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -125,6 +125,8 @@ struct TableViewParams { QColor headerGradientColor; QColor itemBorderBottomColor; QColor itemBorderTopColor; + int itemBorderBottomWidth; // px + int itemBorderTopWidth; // px QColor itemTextColor; QColor selectedColor; QColor selectedTextColor; @@ -477,7 +479,9 @@ Theme makeTheme(const ThemeParams ¶ms) tav.itemTextColor.name(), tav.selectedColor.name(), tav.selectedTextColor.name(), - tav.headerTextColor.name()); + tav.headerTextColor.name(), + QString::number(tav.itemBorderBottomWidth), + QString::number(tav.itemBorderTopWidth)); theme.tableView.starRatingColor = tav.starRatingColor; theme.tableView.starRatingSelectedColor = tav.starRatingSelectedColor; // end TableView @@ -994,6 +998,8 @@ ThemeParams classicThemeParams() tav.headerGradientColor = QColor(0xD1D1D1); tav.itemBorderBottomColor = QColor(0xDFDFDF); tav.itemBorderTopColor = QColor(0xFEFEFE); + tav.itemBorderBottomWidth = 1; + tav.itemBorderTopWidth = 1; tav.itemTextColor = QColor(0x252626); tav.selectedColor = QColor(0xD4D4D4); tav.selectedTextColor = QColor(0x252626); @@ -1262,6 +1268,8 @@ ThemeParams lightThemeParams() tav.headerGradientColor = QColor(0xD1D1D1); tav.itemBorderBottomColor = QColor(0xDFDFDF); tav.itemBorderTopColor = QColor(0xFEFEFE); + tav.itemBorderBottomWidth = 1; + tav.itemBorderTopWidth = 1; tav.itemTextColor = QColor(0x252626); tav.selectedColor = QColor(0x3875D7); tav.selectedTextColor = QColor(0xFFFFFF); @@ -1530,6 +1538,8 @@ ThemeParams darkThemeParams() tav.headerGradientColor = QColor(0x252525); tav.itemBorderBottomColor = QColor(0x1F1F1F); tav.itemBorderTopColor = QColor(0x353535); + tav.itemBorderBottomWidth = 1; + tav.itemBorderTopWidth = 1; tav.itemTextColor = QColor(0xDDDDDD); tav.selectedColor = QColor(0x555555); tav.selectedTextColor = QColor(0xFFFFFF); From 6466739fd75e96b9fb06fb44f2627814dc73010c Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sat, 28 Feb 2026 20:29:00 +0100 Subject: [PATCH 13/26] Add a explicit parameter to control the top gradient value in the comic vine table header --- YACReaderLibrary/themes/theme.h | 2 +- YACReaderLibrary/themes/theme_factory.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index f5824c39..55771d83 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -63,7 +63,7 @@ struct ComicVineThemeTemplates { QString scraperTableViewQSS = "QTableView {color:%1; border:0px;alternate-background-color: %2;background-color: %3; outline: 0px;}" "QTableView::item {outline: 0px; border: 0px; color:%1;}" "QTableView::item:selected {outline: 0px; background-color: %4; }" - "QHeaderView::section:horizontal {background-color:%5; border-bottom:1px solid %6; border-right:1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %5, stop: 1 %6); border-left:none; border-top:none; padding:4px; color:%7;}" + "QHeaderView::section:horizontal {background-color:%5; border-bottom:1px solid %6; border-right:1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %14, stop: 1 %6); border-left:none; border-top:none; padding:4px; color:%7;}" "QHeaderView::section:vertical {border-bottom: 1px solid %8;border-top: 1px solid %9;}" "QHeaderView::down-arrow {image: url('%12');width: 8px;height: 7px;padding-right: 10px;}" "QHeaderView::up-arrow {image: url('%13');width: 8px;height: 7px; padding-right: 10px;}" diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 30ca4e3f..6696cdfa 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -18,6 +18,7 @@ struct ComicVineParams { QColor tableBorderColor; QColor tableSelectedColor; QColor tableHeaderBackgroundColor; + QColor tableHeaderGradientColor; QColor tableHeaderBorderColor; QColor tableHeaderTextColor; QColor tableScrollHandleColor; @@ -370,7 +371,8 @@ Theme makeTheme(const ThemeParams ¶ms) cv.tableScrollHandleColor.name(), cv.tableScrollBackgroundColor.name(), recolor(":/images/comic_vine/downArrow.svg", cv.downArrowColor), - recolor(":/images/comic_vine/upArrow.svg", cv.upArrowColor)); + recolor(":/images/comic_vine/upArrow.svg", cv.upArrowColor), + cv.tableHeaderGradientColor.name()); theme.comicVine.dialogQSS = t.dialogQSS.arg(cv.dialogBackgroundColor.name()); theme.comicVine.dialogButtonsQSS = t.dialogButtonsQSS.arg(cv.buttonBorderColor.name(), cv.buttonBackgroundColor.name(), cv.buttonTextColor.name()); @@ -891,6 +893,7 @@ ThemeParams classicThemeParams() cv.tableBorderColor = QColor(0x242424); cv.tableSelectedColor = QColor(0x555555); cv.tableHeaderBackgroundColor = QColor(0x292929); + cv.tableHeaderGradientColor = QColor(0x292929); cv.tableHeaderBorderColor = QColor(0x1F1F1F); cv.tableHeaderTextColor = QColor(0xEBEBEB); cv.tableScrollHandleColor = QColor(0xDDDDDD); @@ -1161,6 +1164,7 @@ ThemeParams lightThemeParams() cv.tableBorderColor = QColor(0xCCCCCC); cv.tableSelectedColor = QColor(0xDDDDDD); cv.tableHeaderBackgroundColor = QColor(0xE0E0E0); + cv.tableHeaderGradientColor = QColor(0xE0E0E0); cv.tableHeaderBorderColor = QColor(0xC0C0C0); cv.tableHeaderTextColor = QColor(0x333333); cv.tableScrollHandleColor = QColor(0x888888); @@ -1431,6 +1435,7 @@ ThemeParams darkThemeParams() cv.tableBorderColor = QColor(0x242424); cv.tableSelectedColor = QColor(0x555555); cv.tableHeaderBackgroundColor = QColor(0x292929); + cv.tableHeaderGradientColor = QColor(0x292929); cv.tableHeaderBorderColor = QColor(0x1F1F1F); cv.tableHeaderTextColor = QColor(0xEBEBEB); cv.tableScrollHandleColor = QColor(0xDDDDDD); From 66c9047be4377ba7a5bae07120df2819098d9e17 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 1 Mar 2026 14:13:51 +0100 Subject: [PATCH 14/26] Update some of the light theme values --- YACReaderLibrary/themes/theme_factory.cpp | 74 +++++++++++------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 6696cdfa..99009d75 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -1150,8 +1150,8 @@ ThemeParams lightThemeParams() params.defaultContentBackgroundColor = QColor(0xFFFFFF); ComicFlowColors cf; - cf.backgroundColor = Qt::white; - cf.textColor = Qt::black; + cf.backgroundColor = QColor(0xDCDCDC); + cf.textColor = QColor(0x303030); ComicVineParams cv; cv.contentTextColor = Qt::black; @@ -1224,11 +1224,11 @@ ThemeParams lightThemeParams() params.emptyContainerParams = ec; SidebarParams sb; - sb.backgroundColor = QColor(0xF1F1F1); + sb.backgroundColor = QColor(0xFBFBFB); sb.separatorColor = QColor(0x808080); - sb.sectionSeparatorColor = QColor(0xD0D0D0); + sb.sectionSeparatorColor = QColor(0xE0E0E0); sb.uppercaseLabels = true; - sb.titleTextColor = QColor(0x808080); + sb.titleTextColor = QColor(0x4A494A); sb.titleDropShadowColor = QColor(0xFFFFFF); sb.busyIndicatorColor = QColor(0x808080); params.sidebarParams = sb; @@ -1249,19 +1249,19 @@ ThemeParams lightThemeParams() TreeViewParams tv; tv.textColor = Qt::black; - tv.selectionBackgroundColor = QColor(0xD0D0D0); + tv.selectionBackgroundColor = QColor(0x333133); tv.scrollBackgroundColor = QColor(0xE0E0E0); tv.scrollHandleColor = QColor(0x888888); - tv.selectedTextColor = QColor(0x1A1A1A); + tv.selectedTextColor = QColor(0xFFFFFF); tv.folderIndicatorColor = QColor(85, 95, 127); tv.branchIndicatorColor = QColor(0x606060); - tv.branchIndicatorSelectedColor = QColor(0x1A1A1A); + tv.branchIndicatorSelectedColor = QColor(0xFFFFFF); tv.folderIconColor = QColor(0x606060); tv.folderIconShadowColor = QColor(0xFFFFFF); - tv.folderIconSelectedColor = QColor(0x606060); - tv.folderIconSelectedShadowColor = QColor(0xFFFFFF); + tv.folderIconSelectedColor = QColor(0xFFFFFF); + tv.folderIconSelectedShadowColor = QColor(0x161616); tv.folderReadOverlayColor = QColor(0xFFFFFF); - tv.folderReadOverlaySelectedColor = QColor(0xFFFFFF); + tv.folderReadOverlaySelectedColor = QColor(0x161616); params.treeViewParams = tv; TableViewParams tav; @@ -1269,13 +1269,13 @@ ThemeParams lightThemeParams() tav.backgroundColor = QColor(0xFAFAFA); tav.headerBackgroundColor = QColor(0xF5F5F5); tav.headerBorderColor = QColor(0xB8BDC4); - tav.headerGradientColor = QColor(0xD1D1D1); + tav.headerGradientColor = QColor(0xF5F5F5); tav.itemBorderBottomColor = QColor(0xDFDFDF); tav.itemBorderTopColor = QColor(0xFEFEFE); - tav.itemBorderBottomWidth = 1; - tav.itemBorderTopWidth = 1; + tav.itemBorderBottomWidth = 0; + tav.itemBorderTopWidth = 0; tav.itemTextColor = QColor(0x252626); - tav.selectedColor = QColor(0x3875D7); + tav.selectedColor = QColor(0x595959); tav.selectedTextColor = QColor(0xFFFFFF); tav.headerTextColor = QColor(0x313232); tav.starRatingColor = QColor(0xE9BE0F); @@ -1311,32 +1311,32 @@ ThemeParams lightThemeParams() MainToolbarParams mt; mt.backgroundColor = QColor(0xF0F0F0); - mt.folderNameColor = QColor(0x404040); + mt.folderNameColor = QColor(0x333133); mt.dividerColor = QColor(0xB8BDC4); - mt.iconColor = QColor(0x404040); + mt.iconColor = QColor(0x333133); mt.iconDisabledColor = QColor(0xB0B0B0); params.mainToolbarParams = mt; ContentSplitterParams cs; - cs.handleColor = QColor(0xB8B8B8); + cs.handleColor = QColor(0xF0F0F0); cs.horizontalHandleHeight = 4; cs.verticalHandleWidth = 4; params.contentSplitterParams = cs; SidebarIconsParams si; - si.iconColor = QColor(0x606060); - si.shadowColor = QColor(0xFFFFFF); + si.iconColor = QColor(0x4F4E4F); + si.shadowColor = QColor(0xFBFBFB); si.useSystemFolderIcons = false; params.sidebarIconsParams = si; LibraryItemParams li; - li.textColor = QColor(0x404040); - li.libraryIconColor = QColor(0x404040); + li.textColor = Qt::black; + li.libraryIconColor = QColor(0x606060); li.libraryIconShadowColor = QColor(0xFFFFFF); - li.selectedTextColor = QColor(0x1A1A1A); - li.selectedBackgroundColor = QColor(0xD0D0D0); - li.libraryIconSelectedColor = QColor(0x404040); - li.libraryOptionsIconColor = QColor(0x404040); + li.selectedTextColor = QColor(0xFFFFFF); + li.selectedBackgroundColor = QColor(0x333133); + li.libraryIconSelectedColor = QColor(0xFFFFFF); + li.libraryOptionsIconColor = QColor(0xFFFFFF); params.libraryItemParams = li; ComicsViewToolbarParams cvt; @@ -1347,9 +1347,9 @@ ThemeParams lightThemeParams() params.comicsViewToolbarParams = cvt; SearchLineEditParams sle; - sle.textColor = QColor(0x606060); - sle.backgroundColor = QColor(0xE0E0E0); - sle.iconColor = QColor(0x808080); + sle.textColor = QColor(0xFFFFFF); + sle.backgroundColor = QColor(0x333133); + sle.iconColor = QColor(0xEFEFEF); params.searchLineEditParams = sle; ReadingListIconsParams rli; @@ -1367,8 +1367,8 @@ ThemeParams lightThemeParams() { "light", QColor(0xcbcbcb) }, { "dark", QColor(0xb7b7b7) } }; - rli.labelShadowColor = QColor(0xa0a0a0); - rli.labelShadowSelectedColor = QColor(0xa0a0a0); + rli.labelShadowColor = QColor(0x8F8F8F); + rli.labelShadowSelectedColor = QColor(0x161616); rli.readingListMainColor = QColor(0x808080); rli.readingListMainSelectedColor = QColor(0x808080); rli.favoritesMainColor = QColor(0xe15055); @@ -1377,14 +1377,14 @@ ThemeParams lightThemeParams() rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); rli.currentlyReadingOuterColor = Qt::black; rli.currentlyReadingOuterSelectedColor = Qt::black; - rli.specialListShadowColor = QColor(0xa0a0a0); - rli.specialListShadowSelectedColor = QColor(0xa0a0a0); + rli.specialListShadowColor = QColor(0x8F8F8F); + rli.specialListShadowSelectedColor = QColor(0x161616); rli.listMainColor = QColor(0x808080); - rli.listMainSelectedColor = QColor(0x808080); - rli.listShadowColor = QColor(0xc0c0c0); - rli.listShadowSelectedColor = QColor(0xc0c0c0); + rli.listMainSelectedColor = QColor(0xFFFFFF); + rli.listShadowColor = QColor(0x8F8F8F); + rli.listShadowSelectedColor = QColor(0x161616); rli.listDetailColor = QColor(0xFFFFFF); - rli.listDetailSelectedColor = QColor(0xFFFFFF); + rli.listDetailSelectedColor = QColor(0x161616); params.readingListIconsParams = rli; MenuIconsParams mi; From 52e43192c4b9acae7df0374356d52990acfb6261 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 1 Mar 2026 15:17:45 +0100 Subject: [PATCH 15/26] Fix blur background setting FastBlur -> MultiEffect broke it. --- YACReaderLibrary/qml/FlowView.qml | 2 +- YACReaderLibrary/qml/GridComicsView.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/YACReaderLibrary/qml/FlowView.qml b/YACReaderLibrary/qml/FlowView.qml index 9ece421a..b2796158 100644 --- a/YACReaderLibrary/qml/FlowView.qml +++ b/YACReaderLibrary/qml/FlowView.qml @@ -48,7 +48,7 @@ Rectangle { source: backgroundImg blurEnabled: true blur: 1.0 - blurMax: 64 + blurMax: Math.max(2, mainFlowContainer.backgroundBlurRadius) opacity: backgroundBlurOpacity visible: backgroundBlurVisible } diff --git a/YACReaderLibrary/qml/GridComicsView.qml b/YACReaderLibrary/qml/GridComicsView.qml index 1c5edc01..95ef165a 100644 --- a/YACReaderLibrary/qml/GridComicsView.qml +++ b/YACReaderLibrary/qml/GridComicsView.qml @@ -43,7 +43,7 @@ SplitView { source: backgroundImg blurEnabled: true blur: 1.0 - blurMax: 64 + blurMax: Math.max(2, backgroundBlurRadius) opacity: backgroundBlurOpacity visible: backgroundBlurVisible } From 87fada611d7da01166e3312fed1cc34128107640 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 1 Mar 2026 15:22:54 +0100 Subject: [PATCH 16/26] Make the blur backgroud color overlay themable This also fixes the hardcoded color in FlowView.qml --- YACReaderLibrary/grid_comics_view.cpp | 2 ++ YACReaderLibrary/info_comics_view.cpp | 1 + YACReaderLibrary/qml/FlowView.qml | 2 +- YACReaderLibrary/themes/theme.h | 3 +++ YACReaderLibrary/themes/theme_factory.cpp | 7 +++++++ 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/YACReaderLibrary/grid_comics_view.cpp b/YACReaderLibrary/grid_comics_view.cpp index 262fb1cc..39b67f01 100644 --- a/YACReaderLibrary/grid_comics_view.cpp +++ b/YACReaderLibrary/grid_comics_view.cpp @@ -220,6 +220,7 @@ void GridComicsView::updateBackgroundConfig() // Use theme colors for cell and selected colors const auto &qv = theme.qmlView; + ctxt->setContextProperty("backgroundColor", useBackgroundImage ? qv.backgroundBlurOverlayColor : qv.backgroundColor); ctxt->setContextProperty("cellColor", useBackgroundImage ? qv.cellColorWithBackground : qv.cellColor); ctxt->setContextProperty("selectedColor", qv.selectedColor); } @@ -491,6 +492,7 @@ void GridComicsView::applyTheme(const Theme &theme) // Grid colors ctxt->setContextProperty("backgroundColor", qv.backgroundColor); + ctxt->setContextProperty("backgroundBlurOverlayColor", qv.backgroundBlurOverlayColor); ctxt->setContextProperty("cellColor", qv.cellColor); ctxt->setContextProperty("selectedColor", qv.selectedColor); ctxt->setContextProperty("selectedBorderColor", qv.selectedBorderColor); diff --git a/YACReaderLibrary/info_comics_view.cpp b/YACReaderLibrary/info_comics_view.cpp index ce442f1f..a93aeb16 100644 --- a/YACReaderLibrary/info_comics_view.cpp +++ b/YACReaderLibrary/info_comics_view.cpp @@ -243,4 +243,5 @@ void InfoComicsView::applyTheme(const Theme &theme) ctxt->setContextProperty("readTickCheckedColor", qv.readTickCheckedColor); ctxt->setContextProperty("showDropShadow", QVariant(qv.showDropShadow)); + ctxt->setContextProperty("backgroundBlurOverlayColor", qv.backgroundBlurOverlayColor); } diff --git a/YACReaderLibrary/qml/FlowView.qml b/YACReaderLibrary/qml/FlowView.qml index b2796158..6ebc35a7 100644 --- a/YACReaderLibrary/qml/FlowView.qml +++ b/YACReaderLibrary/qml/FlowView.qml @@ -25,7 +25,7 @@ Rectangle { Rectangle { id: background - color: "#2A2A2A" + color: backgroundBlurOverlayColor anchors.fill: backgroundImg } diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index 55771d83..0d98c0ad 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -241,6 +241,9 @@ struct QmlViewTheme { // Continue reading section (FolderContentView) QColor continueReadingBackgroundColor; QColor continueReadingColor; + + // Blur overlay background (FlowView always, GridView when background image enabled) + QColor backgroundBlurOverlayColor; }; struct MainToolbarThemeTemplates { diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 99009d75..b9e103e2 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -170,6 +170,9 @@ struct QmlViewParams { // Continue reading section (FolderContentView) QColor continueReadingBackgroundColor; QColor continueReadingColor; + + // Blur overlay background (FlowView always, GridView when background image enabled) + QColor backgroundBlurOverlayColor; }; struct MainToolbarParams { @@ -514,6 +517,7 @@ Theme makeTheme(const ThemeParams ¶ms) theme.qmlView.currentComicBackgroundColor = qv.currentComicBackgroundColor; theme.qmlView.continueReadingBackgroundColor = qv.continueReadingBackgroundColor; theme.qmlView.continueReadingColor = qv.continueReadingColor; + theme.qmlView.backgroundBlurOverlayColor = qv.backgroundBlurOverlayColor; // end QmlView // MainToolbar @@ -1036,6 +1040,7 @@ ThemeParams classicThemeParams() qv.currentComicBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); qv.continueReadingBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); qv.continueReadingColor = QColor(0xFFFFFF); + qv.backgroundBlurOverlayColor = QColor(0x2A2A2A); params.qmlViewParams = qv; MainToolbarParams mt; @@ -1307,6 +1312,7 @@ ThemeParams lightThemeParams() qv.currentComicBackgroundColor = QColor(0xFF, 0xFF, 0xFF, 0x88); qv.continueReadingBackgroundColor = QColor(0xE8E8E8); qv.continueReadingColor = QColor::fromRgb(0x000000); + qv.backgroundBlurOverlayColor = QColor(0x9E9E9E); params.qmlViewParams = qv; MainToolbarParams mt; @@ -1578,6 +1584,7 @@ ThemeParams darkThemeParams() qv.currentComicBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); qv.continueReadingBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); qv.continueReadingColor = QColor(0xFFFFFF); + qv.backgroundBlurOverlayColor = QColor(0x2A2A2A); params.qmlViewParams = qv; MainToolbarParams mt; From 547e48cc049e677dc30bda6e11ff527673344a06 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Mon, 2 Mar 2026 21:23:39 +0100 Subject: [PATCH 17/26] Use json file based themes instead of code to create them (theme editor + theme mode settings) --- YACReader/CMakeLists.txt | 4 + YACReader/main.cpp | 9 +- YACReader/options_dialog.cpp | 14 + YACReader/options_dialog.h | 2 + YACReader/render.cpp | 2 +- YACReader/themes/builtin_classic.json | 51 + YACReader/themes/builtin_dark.json | 51 + YACReader/themes/builtin_light.json | 51 + YACReader/themes/theme.h | 5 + YACReader/themes/theme_factory.cpp | 317 ++--- YACReader/themes/theme_factory.h | 5 +- YACReader/themes/themes.qrc | 7 + YACReaderLibrary/CMakeLists.txt | 4 + YACReaderLibrary/info_comics_view.cpp | 14 +- YACReaderLibrary/main.cpp | 8 +- YACReaderLibrary/options_dialog.cpp | 17 + YACReaderLibrary/options_dialog.h | 1 + YACReaderLibrary/themes/builtin_classic.json | 238 ++++ YACReaderLibrary/themes/builtin_dark.json | 238 ++++ YACReaderLibrary/themes/builtin_light.json | 238 ++++ YACReaderLibrary/themes/theme.h | 5 + YACReaderLibrary/themes/theme_factory.cpp | 1254 +++++------------ YACReaderLibrary/themes/theme_factory.h | 5 +- YACReaderLibrary/themes/themes.qrc | 7 + common/CMakeLists.txt | 12 +- common/themes/appearance_config_images.qrc | 7 + common/themes/appearance_configuration.cpp | 96 ++ common/themes/appearance_configuration.h | 48 + common/themes/appearance_tab_widget.cpp | 98 ++ common/themes/appearance_tab_widget.h | 29 + common/themes/theme_editor_dialog.cpp | 477 +++++++ common/themes/theme_editor_dialog.h | 63 + common/themes/theme_id.h | 10 - common/themes/theme_manager.cpp | 115 +- common/themes/theme_manager.h | 20 +- common/themes/theme_meta.h | 14 + common/themes/theme_repository.cpp | 206 +++ common/themes/theme_repository.h | 57 + common/themes/theme_variant.h | 9 + images/appearance_config/theme-mode-dark.svg | 29 + images/appearance_config/theme-mode-light.svg | 29 + .../appearance_config/theme-mode-system.svg | 55 + 42 files changed, 2776 insertions(+), 1145 deletions(-) create mode 100644 YACReader/themes/builtin_classic.json create mode 100644 YACReader/themes/builtin_dark.json create mode 100644 YACReader/themes/builtin_light.json create mode 100644 YACReader/themes/themes.qrc create mode 100644 YACReaderLibrary/themes/builtin_classic.json create mode 100644 YACReaderLibrary/themes/builtin_dark.json create mode 100644 YACReaderLibrary/themes/builtin_light.json create mode 100644 YACReaderLibrary/themes/themes.qrc create mode 100644 common/themes/appearance_config_images.qrc create mode 100644 common/themes/appearance_configuration.cpp create mode 100644 common/themes/appearance_configuration.h create mode 100644 common/themes/appearance_tab_widget.cpp create mode 100644 common/themes/appearance_tab_widget.h create mode 100644 common/themes/theme_editor_dialog.cpp create mode 100644 common/themes/theme_editor_dialog.h delete mode 100644 common/themes/theme_id.h create mode 100644 common/themes/theme_meta.h create mode 100644 common/themes/theme_repository.cpp create mode 100644 common/themes/theme_repository.h create mode 100644 common/themes/theme_variant.h create mode 100644 images/appearance_config/theme-mode-dark.svg create mode 100644 images/appearance_config/theme-mode-light.svg create mode 100644 images/appearance_config/theme-mode-system.svg diff --git a/YACReader/CMakeLists.txt b/YACReader/CMakeLists.txt index 51c55b61..62cf5864 100644 --- a/YACReader/CMakeLists.txt +++ b/YACReader/CMakeLists.txt @@ -56,9 +56,13 @@ target_compile_definitions(YACReader PRIVATE YACREADER) # Resources qt_add_resources(yacreader_images_rcc "${CMAKE_CURRENT_SOURCE_DIR}/yacreader_images.qrc") qt_add_resources(yacreader_files_rcc "${CMAKE_CURRENT_SOURCE_DIR}/yacreader_files.qrc") +qt_add_resources(yacreader_themes_rcc "${CMAKE_CURRENT_SOURCE_DIR}/themes/themes.qrc") +qt_add_resources(yacreader_common_images_rcc "${CMAKE_SOURCE_DIR}/common/themes/appearance_config_images.qrc") target_sources(YACReader PRIVATE ${yacreader_images_rcc} ${yacreader_files_rcc} + ${yacreader_themes_rcc} + ${yacreader_common_images_rcc} ) # Translations diff --git a/YACReader/main.cpp b/YACReader/main.cpp index e71f6791..d1c98e22 100644 --- a/YACReader/main.cpp +++ b/YACReader/main.cpp @@ -7,7 +7,10 @@ #include "main_window_viewer.h" #include "configuration.h" #include "exit_check.h" +#include "appearance_configuration.h" #include "theme_manager.h" +#include "theme_repository.h" +#include "yacreader_global.h" #include "QsLog.h" #include "QsLogDest.h" @@ -114,7 +117,11 @@ int main(int argc, char *argv[]) app.setApplicationName("YACReader"); app.setOrganizationName("YACReader"); - ThemeManager::instance().initialize(); + auto *appearanceConfig = new AppearanceConfiguration( + YACReader::getSettingsPath() + "/YACReader.ini", qApp); + auto *themeRepo = new ThemeRepository( + ":/themes", YACReader::getSettingsPath() + "/themes/user"); + ThemeManager::instance().initialize(appearanceConfig, themeRepo); if (QIcon::hasThemeIcon("YACReader")) { app.setWindowIcon(QIcon::fromTheme("YACReader")); diff --git a/YACReader/options_dialog.cpp b/YACReader/options_dialog.cpp index 4df071c3..c39e7115 100644 --- a/YACReader/options_dialog.cpp +++ b/YACReader/options_dialog.cpp @@ -12,7 +12,10 @@ #include #include #include +#include #include "theme_manager.h" +#include "theme_factory.h" +#include "appearance_tab_widget.h" #include "yacreader_spin_slider_widget.h" #include "yacreader_3d_flow_config_widget.h" @@ -203,9 +206,20 @@ OptionsDialog::OptionsDialog(QWidget *parent) pageFlow->setLayout(layoutFlow); pageImage->setLayout(layoutImageV); + // APPEARANCE ---------------------------------------- + + auto *pageAppearance = new AppearanceTabWidget( + ThemeManager::instance().getAppearanceConfiguration(), + []() { return ThemeManager::instance().getCurrentTheme().sourceJson; }, + [](const QJsonObject &json) { ThemeManager::instance().setTheme(makeTheme(json)); }, + this); + + // APPEARANCE END ------------------------------------ + tabWidget->addTab(pageGeneral, tr("General")); tabWidget->addTab(pageFlow, tr("Page Flow")); tabWidget->addTab(pageImage, tr("Image adjustment")); + tabWidget->addTab(pageAppearance, tr("Appearance")); layout->addWidget(tabWidget); diff --git a/YACReader/options_dialog.h b/YACReader/options_dialog.h index 7c2ef6cc..20467f77 100644 --- a/YACReader/options_dialog.h +++ b/YACReader/options_dialog.h @@ -4,6 +4,8 @@ #include "yacreader_options_dialog.h" #include "themable.h" +#include + class QDialog; class QLabel; class QLineEdit; diff --git a/YACReader/render.cpp b/YACReader/render.cpp index 595df27c..59996fea 100644 --- a/YACReader/render.cpp +++ b/YACReader/render.cpp @@ -1000,7 +1000,7 @@ void Render::fillBuffer() pageRenders[currentPageBufferedIndex + i]->start(); } - if ((currentIndex - i > 0) && + if ((currentIndex - i >= 0) && buffer[currentPageBufferedIndex - i]->isNull() && i <= numLeftPages && pageRenders[currentPageBufferedIndex - i] == 0 && diff --git a/YACReader/themes/builtin_classic.json b/YACReader/themes/builtin_classic.json new file mode 100644 index 00000000..74dff6b4 --- /dev/null +++ b/YACReader/themes/builtin_classic.json @@ -0,0 +1,51 @@ +{ + "meta": { + "id": "builtin/classic", + "displayName": "Default Classic", + "variant": "dark" + }, + "toolbar": { + "iconColor": "#404040", + "iconDisabledColor": "#858585", + "iconCheckedColor": "#5a5a5a", + "backgroundColor": "#f3f3f3", + "separatorColor": "#cccccc", + "checkedButtonColor": "#cccccc", + "menuIndicatorColor": "#404040" + }, + "viewer": { + "defaultBackgroundColor": "#282828", + "defaultTextColor": "#ffffff", + "infoBackgroundColor": "#bb000000", + "infoTextColor": "#ffffff" + }, + "goToFlowWidget": { + "flowBackgroundColor": "#282828", + "flowTextColor": "#ffffff", + "toolbarBackgroundColor": "#99000000", + "sliderBorderColor": "#22ffffff", + "sliderGrooveColor": "#77000000", + "sliderHandleColor": "#55ffffff", + "editBorderColor": "#77000000", + "editBackgroundColor": "#55000000", + "editTextColor": "#ffffff", + "labelTextColor": "#ffffff", + "iconColor": "#ffffff" + }, + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, + "whatsNewDialog": { + "backgroundColor": "#ffffff", + "headerTextColor": "#0a0a0a", + "versionTextColor": "#858585", + "contentTextColor": "#0a0a0a", + "linkColor": "#e8b800", + "closeButtonColor": "#444444", + "headerDecorationColor": "#e8b800" + }, + "shortcutsIcons": { + "iconColor": "#404040" + } +} diff --git a/YACReader/themes/builtin_dark.json b/YACReader/themes/builtin_dark.json new file mode 100644 index 00000000..01085ca9 --- /dev/null +++ b/YACReader/themes/builtin_dark.json @@ -0,0 +1,51 @@ +{ + "meta": { + "id": "builtin/dark", + "displayName": "Default Dark", + "variant": "dark" + }, + "toolbar": { + "iconColor": "#cccccc", + "iconDisabledColor": "#444444", + "iconCheckedColor": "#dadada", + "backgroundColor": "#202020", + "separatorColor": "#444444", + "checkedButtonColor": "#3a3a3a", + "menuIndicatorColor": "#cccccc" + }, + "viewer": { + "defaultBackgroundColor": "#282828", + "defaultTextColor": "#ffffff", + "infoBackgroundColor": "#bb000000", + "infoTextColor": "#b0b0b0" + }, + "goToFlowWidget": { + "flowBackgroundColor": "#282828", + "flowTextColor": "#ffffff", + "toolbarBackgroundColor": "#99000000", + "sliderBorderColor": "#22ffffff", + "sliderGrooveColor": "#77000000", + "sliderHandleColor": "#55ffffff", + "editBorderColor": "#77000000", + "editBackgroundColor": "#55000000", + "editTextColor": "#ffffff", + "labelTextColor": "#ffffff", + "iconColor": "#cccccc" + }, + "helpAboutDialog": { + "headingColor": "#e0e0e0", + "linkColor": "#d4a84b" + }, + "whatsNewDialog": { + "backgroundColor": "#2a2a2a", + "headerTextColor": "#e0e0e0", + "versionTextColor": "#858585", + "contentTextColor": "#e0e0e0", + "linkColor": "#e8b800", + "closeButtonColor": "#dddddd", + "headerDecorationColor": "#e8b800" + }, + "shortcutsIcons": { + "iconColor": "#d0d0d0" + } +} diff --git a/YACReader/themes/builtin_light.json b/YACReader/themes/builtin_light.json new file mode 100644 index 00000000..97905791 --- /dev/null +++ b/YACReader/themes/builtin_light.json @@ -0,0 +1,51 @@ +{ + "meta": { + "id": "builtin/light", + "displayName": "Default Light", + "variant": "light" + }, + "toolbar": { + "iconColor": "#404040", + "iconDisabledColor": "#b0b0b0", + "iconCheckedColor": "#5a5a5a", + "backgroundColor": "#f3f3f3", + "separatorColor": "#cccccc", + "checkedButtonColor": "#cccccc", + "menuIndicatorColor": "#404040" + }, + "viewer": { + "defaultBackgroundColor": "#f6f6f6", + "defaultTextColor": "#202020", + "infoBackgroundColor": "#bbffffff", + "infoTextColor": "#404040" + }, + "goToFlowWidget": { + "flowBackgroundColor": "#f6f6f6", + "flowTextColor": "#202020", + "toolbarBackgroundColor": "#bbffffff", + "sliderBorderColor": "#22000000", + "sliderGrooveColor": "#33000000", + "sliderHandleColor": "#55000000", + "editBorderColor": "#33000000", + "editBackgroundColor": "#22000000", + "editTextColor": "#202020", + "labelTextColor": "#202020", + "iconColor": "#404040" + }, + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, + "whatsNewDialog": { + "backgroundColor": "#ffffff", + "headerTextColor": "#0a0a0a", + "versionTextColor": "#858585", + "contentTextColor": "#0a0a0a", + "linkColor": "#e8b800", + "closeButtonColor": "#444444", + "headerDecorationColor": "#e8b800" + }, + "shortcutsIcons": { + "iconColor": "#606060" + } +} diff --git a/YACReader/themes/theme.h b/YACReader/themes/theme.h index 2cc5e8cf..964e619f 100644 --- a/YACReader/themes/theme.h +++ b/YACReader/themes/theme.h @@ -2,9 +2,11 @@ #define THEME_H #include +#include #include "help_about_dialog_theme.h" #include "whats_new_dialog_theme.h" +#include "theme_meta.h" struct ToolbarThemeTemplates { QString toolbarQSS = "QToolBar { border: none; background: %1; }\n" @@ -142,6 +144,9 @@ struct DialogIconsTheme { }; struct Theme { + ThemeMeta meta; + QJsonObject sourceJson; + ToolbarTheme toolbar; ViewerTheme viewer; GoToFlowWidgetTheme goToFlowWidget; diff --git a/YACReader/themes/theme_factory.cpp b/YACReader/themes/theme_factory.cpp index d798a5a4..7a19d4f8 100644 --- a/YACReader/themes/theme_factory.cpp +++ b/YACReader/themes/theme_factory.cpp @@ -3,6 +3,7 @@ #include #include "icon_utils.h" +#include "theme_meta.h" struct ToolbarParams { ToolbarThemeTemplates t; @@ -56,7 +57,7 @@ struct ShortcutsIconsParams { }; struct ThemeParams { - QString themeName; + ThemeMeta meta; ToolbarParams toolbarParams; ViewerParams viewerParams; @@ -72,7 +73,7 @@ void setToolbarIconPair(QIcon &icon, const QColor &iconColor, const QColor &disabledColor, const QColor &checkedColor, - const QString &themeName) + const QString &themeId) { QString path18 = basePath; if (path18.endsWith(".svg")) @@ -81,14 +82,14 @@ void setToolbarIconPair(QIcon &icon, path18.append("_18x18"); // Normal - const QString normalPath = recoloredSvgToThemeFile(basePath, iconColor, themeName); - const QString normalPath18 = recoloredSvgToThemeFile(path18, iconColor, themeName); + const QString normalPath = recoloredSvgToThemeFile(basePath, iconColor, themeId); + const QString normalPath18 = recoloredSvgToThemeFile(path18, iconColor, themeId); // Disabled - const QString disabledPath = recoloredSvgToThemeFile(basePath, disabledColor, themeName, { .suffix = "_disabled" }); - const QString disabledPath18 = recoloredSvgToThemeFile(path18, disabledColor, themeName, { .suffix = "_disabled" }); + const QString disabledPath = recoloredSvgToThemeFile(basePath, disabledColor, themeId, { .suffix = "_disabled" }); + const QString disabledPath18 = recoloredSvgToThemeFile(path18, disabledColor, themeId, { .suffix = "_disabled" }); // Checked (On state) - const QString checkedPath = recoloredSvgToThemeFile(basePath, checkedColor, themeName, { .suffix = "_checked" }); - const QString checkedPath18 = recoloredSvgToThemeFile(path18, checkedColor, themeName, { .suffix = "_checked" }); + const QString checkedPath = recoloredSvgToThemeFile(basePath, checkedColor, themeId, { .suffix = "_checked" }); + const QString checkedPath18 = recoloredSvgToThemeFile(path18, checkedColor, themeId, { .suffix = "_checked" }); icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(disabledPath, QSize(), QIcon::Disabled, QIcon::Off); @@ -105,11 +106,13 @@ Theme makeTheme(const ThemeParams ¶ms) { Theme theme; + theme.meta = params.meta; + // Toolbar & actions - theme.toolbar.toolbarQSS = params.toolbarParams.t.toolbarQSS.arg(params.toolbarParams.backgroundColor.name(), params.toolbarParams.separatorColor.name(), params.toolbarParams.checkedButtonColor.name(), recoloredSvgToThemeFile(params.toolbarParams.t.menuArrowPath, params.toolbarParams.menuIndicatorColor, params.themeName)); + theme.toolbar.toolbarQSS = params.toolbarParams.t.toolbarQSS.arg(params.toolbarParams.backgroundColor.name(), params.toolbarParams.separatorColor.name(), params.toolbarParams.checkedButtonColor.name(), recoloredSvgToThemeFile(params.toolbarParams.t.menuArrowPath, params.toolbarParams.menuIndicatorColor, params.meta.id)); auto setToolbarIconPairT = [&](QIcon &icon, QIcon &icon18, const QString &basePath) { - setToolbarIconPair(icon, icon18, basePath, params.toolbarParams.iconColor, params.toolbarParams.iconDisabledColor, params.toolbarParams.iconCheckedColor, params.themeName); + setToolbarIconPair(icon, icon18, basePath, params.toolbarParams.iconColor, params.toolbarParams.iconDisabledColor, params.toolbarParams.iconCheckedColor, params.meta.id); }; setToolbarIconPairT(theme.toolbar.openAction, theme.toolbar.openAction18x18, ":/images/viewer_toolbar/open.svg"); @@ -166,8 +169,8 @@ Theme makeTheme(const ThemeParams ¶ms) theme.goToFlowWidget.buttonQSS = gotoParams.t.buttonQSS; theme.goToFlowWidget.labelQSS = gotoParams.t.labelQSS.arg(gotoParams.labelTextColor.name()); - const QString centerIconPath = recoloredSvgToThemeFile(":/images/centerFlow.svg", gotoParams.iconColor, params.themeName); - const QString goToIconPath = recoloredSvgToThemeFile(":/images/gotoFlow.svg", gotoParams.iconColor, params.themeName); + const QString centerIconPath = recoloredSvgToThemeFile(":/images/centerFlow.svg", gotoParams.iconColor, params.meta.id); + const QString goToIconPath = recoloredSvgToThemeFile(":/images/gotoFlow.svg", gotoParams.iconColor, params.meta.id); theme.goToFlowWidget.centerIcon = QIcon(centerIconPath); theme.goToFlowWidget.goToIcon = QIcon(goToIconPath); // end GoToFlowWidget @@ -183,14 +186,14 @@ Theme makeTheme(const ThemeParams ¶ms) theme.whatsNewDialog.versionTextColor = wn.versionTextColor; theme.whatsNewDialog.contentTextColor = wn.contentTextColor; theme.whatsNewDialog.linkColor = wn.linkColor; - theme.whatsNewDialog.closeButtonIcon = QPixmap(recoloredSvgToThemeFile(":/images/custom_dialog/custom_close_button.svg", wn.closeButtonColor, params.themeName)); - theme.whatsNewDialog.headerDecoration = QPixmap(recoloredSvgToThemeFile(":/images/whats_new/whatsnew_header.svg", wn.headerDecorationColor, params.themeName)); + theme.whatsNewDialog.closeButtonIcon = QPixmap(recoloredSvgToThemeFile(":/images/custom_dialog/custom_close_button.svg", wn.closeButtonColor, params.meta.id)); + theme.whatsNewDialog.headerDecoration = QPixmap(recoloredSvgToThemeFile(":/images/whats_new/whatsnew_header.svg", wn.headerDecorationColor, params.meta.id)); // end WhatsNewDialog // ShortcutsIcons const auto &sci = params.shortcutsIconsParams; auto makeShortcutsIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, sci.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, sci.iconColor, params.meta.id); return QIcon(path); }; @@ -203,7 +206,7 @@ Theme makeTheme(const ThemeParams ¶ms) // FindFolder icon (used in OptionsDialog) { - const QString path = recoloredSvgToThemeFile(":/images/find_folder.svg", params.toolbarParams.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(":/images/find_folder.svg", params.toolbarParams.iconColor, params.meta.id); const qreal dpr = qApp->devicePixelRatio(); theme.dialogIcons.findFolderIcon = QIcon(renderSvgToPixmap(path, 13, 13, dpr)); } @@ -211,204 +214,92 @@ Theme makeTheme(const ThemeParams ¶ms) return theme; } -ThemeParams classicThemeParams(); -ThemeParams lightThemeParams(); -ThemeParams darkThemeParams(); +// JSON helpers --------------------------------------------------------------- -Theme makeTheme(ThemeId themeId) +static QColor colorFromJson(const QJsonObject &obj, const QString &key, const QColor &fallback) { - switch (themeId) { - case ThemeId::Classic: - return makeTheme(classicThemeParams()); - case ThemeId::Light: - return makeTheme(lightThemeParams()); - case ThemeId::Dark: - return makeTheme(darkThemeParams()); + if (!obj.contains(key)) + return fallback; + QColor c(obj[key].toString()); + return c.isValid() ? c : fallback; +} + +Theme makeTheme(const QJsonObject &json) +{ + ThemeParams p; + + if (json.contains("toolbar")) { + const auto t = json["toolbar"].toObject(); + auto &tp = p.toolbarParams; + tp.iconColor = colorFromJson(t, "iconColor", tp.iconColor); + tp.iconDisabledColor = colorFromJson(t, "iconDisabledColor", tp.iconDisabledColor); + tp.iconCheckedColor = colorFromJson(t, "iconCheckedColor", tp.iconCheckedColor); + tp.backgroundColor = colorFromJson(t, "backgroundColor", tp.backgroundColor); + tp.separatorColor = colorFromJson(t, "separatorColor", tp.separatorColor); + tp.checkedButtonColor = colorFromJson(t, "checkedButtonColor", tp.checkedButtonColor); + tp.menuIndicatorColor = colorFromJson(t, "menuIndicatorColor", tp.menuIndicatorColor); } -} - -ThemeParams classicThemeParams() -{ - ThemeParams params; - params.themeName = "classic"; - - ToolbarParams toolbarParams; - toolbarParams.iconColor = QColor(0x404040); - toolbarParams.iconDisabledColor = QColor(0x858585); - toolbarParams.iconCheckedColor = QColor(0x5A5A5A); - toolbarParams.backgroundColor = QColor(0xF3F3F3); - toolbarParams.separatorColor = QColor(0xCCCCCC); - toolbarParams.checkedButtonColor = QColor(0xCCCCCC); - toolbarParams.menuIndicatorColor = QColor(0x404040); - - params.toolbarParams = toolbarParams; - - ViewerParams viewerParams; - viewerParams.defaultBackgroundColor = QColor(0x282828); - viewerParams.defaultTextColor = Qt::white; - viewerParams.infoBackgroundColor = QColor::fromRgba(0xBB000000); - viewerParams.infoTextColor = Qt::white; - viewerParams.t = ViewerThemeTemplates(); - - params.viewerParams = viewerParams; - - GoToFlowWidgetParams goToFlowWidgetParams; - goToFlowWidgetParams.flowBackgroundColor = QColor(0x282828); - goToFlowWidgetParams.flowTextColor = Qt::white; - goToFlowWidgetParams.toolbarBackgroundColor = QColor::fromRgba(0x99000000); - goToFlowWidgetParams.sliderBorderColor = QColor::fromRgba(0x22FFFFFF); - goToFlowWidgetParams.sliderGrooveColor = QColor::fromRgba(0x77000000); - goToFlowWidgetParams.sliderHandleColor = QColor::fromRgba(0x55FFFFFF); - goToFlowWidgetParams.editBorderColor = QColor::fromRgba(0x77000000); - goToFlowWidgetParams.editBackgroundColor = QColor::fromRgba(0x55000000); - goToFlowWidgetParams.editTextColor = Qt::white; - goToFlowWidgetParams.labelTextColor = Qt::white; - goToFlowWidgetParams.iconColor = Qt::white; - goToFlowWidgetParams.t = GoToFlowWidgetThemeTemplates(); - - params.goToFlowWidgetParams = goToFlowWidgetParams; - - params.helpAboutDialogParams.headingColor = QColor(0x302f2d); - params.helpAboutDialogParams.linkColor = QColor(0xC19441); - - params.whatsNewDialogParams.backgroundColor = QColor(0xFFFFFF); - params.whatsNewDialogParams.headerTextColor = QColor(0x0A0A0A); - params.whatsNewDialogParams.versionTextColor = QColor(0x858585); - params.whatsNewDialogParams.contentTextColor = QColor(0x0A0A0A); - params.whatsNewDialogParams.linkColor = QColor(0xE8B800); - params.whatsNewDialogParams.closeButtonColor = QColor(0x444444); - params.whatsNewDialogParams.headerDecorationColor = QColor(0xE8B800); - - // ShortcutsIcons - ShortcutsIconsParams sci; - sci.iconColor = QColor(0x404040); // Dark icons for light background - params.shortcutsIconsParams = sci; - - return params; -} - -ThemeParams lightThemeParams() -{ - ThemeParams params; - params.themeName = "light"; - - ToolbarParams toolbarParams; - toolbarParams.iconColor = QColor(0x404040); - toolbarParams.iconDisabledColor = QColor(0xB0B0B0); - toolbarParams.iconCheckedColor = QColor(0x5A5A5A); - toolbarParams.backgroundColor = QColor(0xF3F3F3); - toolbarParams.separatorColor = QColor(0xCCCCCC); - toolbarParams.checkedButtonColor = QColor(0xCCCCCC); - toolbarParams.menuIndicatorColor = QColor(0x404040); - - params.toolbarParams = toolbarParams; - - ViewerParams viewerParams; - viewerParams.defaultBackgroundColor = QColor(0xF6F6F6); - viewerParams.defaultTextColor = QColor(0x202020); - viewerParams.infoBackgroundColor = QColor::fromRgba(0xBBFFFFFF); - viewerParams.infoTextColor = QColor(0x404040); - viewerParams.t = ViewerThemeTemplates(); - - params.viewerParams = viewerParams; - - GoToFlowWidgetParams goToFlowWidgetParams; - goToFlowWidgetParams.flowBackgroundColor = QColor(0xF6F6F6); - goToFlowWidgetParams.flowTextColor = QColor(0x202020); - goToFlowWidgetParams.toolbarBackgroundColor = QColor::fromRgba(0xBBFFFFFF); - goToFlowWidgetParams.sliderBorderColor = QColor::fromRgba(0x22000000); - goToFlowWidgetParams.sliderGrooveColor = QColor::fromRgba(0x33000000); - goToFlowWidgetParams.sliderHandleColor = QColor::fromRgba(0x55000000); - goToFlowWidgetParams.editBorderColor = QColor::fromRgba(0x33000000); - goToFlowWidgetParams.editBackgroundColor = QColor::fromRgba(0x22000000); - goToFlowWidgetParams.editTextColor = QColor(0x202020); - goToFlowWidgetParams.labelTextColor = QColor(0x202020); - goToFlowWidgetParams.iconColor = QColor(0x404040); - goToFlowWidgetParams.t = GoToFlowWidgetThemeTemplates(); - - params.goToFlowWidgetParams = goToFlowWidgetParams; - - params.helpAboutDialogParams.headingColor = QColor(0x302f2d); - params.helpAboutDialogParams.linkColor = QColor(0xC19441); - - params.whatsNewDialogParams.backgroundColor = QColor(0xFFFFFF); - params.whatsNewDialogParams.headerTextColor = QColor(0x0A0A0A); - params.whatsNewDialogParams.versionTextColor = QColor(0x858585); - params.whatsNewDialogParams.contentTextColor = QColor(0x0A0A0A); - params.whatsNewDialogParams.linkColor = QColor(0xE8B800); - params.whatsNewDialogParams.closeButtonColor = QColor(0x444444); - params.whatsNewDialogParams.headerDecorationColor = QColor(0xE8B800); - - // ShortcutsIcons - ShortcutsIconsParams sci; - sci.iconColor = QColor(0x606060); // Dark icons for light background - params.shortcutsIconsParams = sci; - - return params; -} - -ThemeParams darkThemeParams() -{ - ThemeParams params; - params.themeName = "dark"; - - ToolbarParams toolbarParams; - toolbarParams.iconColor = QColor(0xCCCCCC); - toolbarParams.iconDisabledColor = QColor(0x444444); - toolbarParams.iconCheckedColor = QColor(0xDADADA); - toolbarParams.backgroundColor = QColor(0x202020); - toolbarParams.separatorColor = QColor(0x444444); - toolbarParams.checkedButtonColor = QColor(0x3A3A3A); - toolbarParams.menuIndicatorColor = QColor(0xCCCCCC); - - params.toolbarParams = toolbarParams; - - ViewerParams viewerParams; - viewerParams.defaultBackgroundColor = QColor(40, 40, 40); - viewerParams.defaultTextColor = Qt::white; - viewerParams.infoBackgroundColor = QColor::fromRgba(0xBB000000); - viewerParams.infoTextColor = QColor(0xB0B0B0); - viewerParams.t = ViewerThemeTemplates(); - - params.viewerParams = viewerParams; - - GoToFlowWidgetParams goToFlowWidgetParams; - goToFlowWidgetParams.flowBackgroundColor = QColor(40, 40, 40); - goToFlowWidgetParams.flowTextColor = Qt::white; - goToFlowWidgetParams.toolbarBackgroundColor = QColor::fromRgba(0x99000000); - goToFlowWidgetParams.sliderBorderColor = QColor::fromRgba(0x22FFFFFF); - goToFlowWidgetParams.sliderGrooveColor = QColor::fromRgba(0x77000000); - goToFlowWidgetParams.sliderHandleColor = QColor::fromRgba(0x55FFFFFF); - goToFlowWidgetParams.editBorderColor = QColor::fromRgba(0x77000000); - goToFlowWidgetParams.editBackgroundColor = QColor::fromRgba(0x55000000); - goToFlowWidgetParams.editTextColor = Qt::white; - goToFlowWidgetParams.labelTextColor = Qt::white; - goToFlowWidgetParams.iconColor = QColor(0xCCCCCC); - goToFlowWidgetParams.t = GoToFlowWidgetThemeTemplates(); - - params.goToFlowWidgetParams = goToFlowWidgetParams; - - params.helpAboutDialogParams.headingColor = QColor(0xE0E0E0); - params.helpAboutDialogParams.linkColor = QColor(0xD4A84B); - - params.whatsNewDialogParams.backgroundColor = QColor(0x2A2A2A); - params.whatsNewDialogParams.headerTextColor = QColor(0xE0E0E0); - params.whatsNewDialogParams.versionTextColor = QColor(0x858585); - params.whatsNewDialogParams.contentTextColor = QColor(0xE0E0E0); - params.whatsNewDialogParams.linkColor = QColor(0xE8B800); - params.whatsNewDialogParams.closeButtonColor = QColor(0xDDDDDD); - params.whatsNewDialogParams.headerDecorationColor = QColor(0xE8B800); - - // ShortcutsIcons - ShortcutsIconsParams sci; - sci.iconColor = QColor(0xD0D0D0); // Light icons for dark background - params.shortcutsIconsParams = sci; - - return params; -} - -// TODO -ThemeParams paramsFromFile(const QString &filePath) -{ - return {}; + + if (json.contains("viewer")) { + const auto v = json["viewer"].toObject(); + auto &vp = p.viewerParams; + vp.defaultBackgroundColor = colorFromJson(v, "defaultBackgroundColor", vp.defaultBackgroundColor); + vp.defaultTextColor = colorFromJson(v, "defaultTextColor", vp.defaultTextColor); + vp.infoBackgroundColor = colorFromJson(v, "infoBackgroundColor", vp.infoBackgroundColor); + vp.infoTextColor = colorFromJson(v, "infoTextColor", vp.infoTextColor); + } + + if (json.contains("goToFlowWidget")) { + const auto g = json["goToFlowWidget"].toObject(); + auto &gp = p.goToFlowWidgetParams; + gp.flowBackgroundColor = colorFromJson(g, "flowBackgroundColor", gp.flowBackgroundColor); + gp.flowTextColor = colorFromJson(g, "flowTextColor", gp.flowTextColor); + gp.toolbarBackgroundColor = colorFromJson(g, "toolbarBackgroundColor", gp.toolbarBackgroundColor); + gp.sliderBorderColor = colorFromJson(g, "sliderBorderColor", gp.sliderBorderColor); + gp.sliderGrooveColor = colorFromJson(g, "sliderGrooveColor", gp.sliderGrooveColor); + gp.sliderHandleColor = colorFromJson(g, "sliderHandleColor", gp.sliderHandleColor); + gp.editBorderColor = colorFromJson(g, "editBorderColor", gp.editBorderColor); + gp.editBackgroundColor = colorFromJson(g, "editBackgroundColor", gp.editBackgroundColor); + gp.editTextColor = colorFromJson(g, "editTextColor", gp.editTextColor); + gp.labelTextColor = colorFromJson(g, "labelTextColor", gp.labelTextColor); + gp.iconColor = colorFromJson(g, "iconColor", gp.iconColor); + } + + if (json.contains("helpAboutDialog")) { + const auto h = json["helpAboutDialog"].toObject(); + p.helpAboutDialogParams.headingColor = colorFromJson(h, "headingColor", p.helpAboutDialogParams.headingColor); + p.helpAboutDialogParams.linkColor = colorFromJson(h, "linkColor", p.helpAboutDialogParams.linkColor); + } + + if (json.contains("whatsNewDialog")) { + const auto w = json["whatsNewDialog"].toObject(); + auto &wn = p.whatsNewDialogParams; + wn.backgroundColor = colorFromJson(w, "backgroundColor", wn.backgroundColor); + wn.headerTextColor = colorFromJson(w, "headerTextColor", wn.headerTextColor); + wn.versionTextColor = colorFromJson(w, "versionTextColor", wn.versionTextColor); + wn.contentTextColor = colorFromJson(w, "contentTextColor", wn.contentTextColor); + wn.linkColor = colorFromJson(w, "linkColor", wn.linkColor); + wn.closeButtonColor = colorFromJson(w, "closeButtonColor", wn.closeButtonColor); + wn.headerDecorationColor = colorFromJson(w, "headerDecorationColor",wn.headerDecorationColor); + } + + if (json.contains("shortcutsIcons")) { + const auto s = json["shortcutsIcons"].toObject(); + p.shortcutsIconsParams.iconColor = colorFromJson(s, "iconColor", p.shortcutsIconsParams.iconColor); + } + + if (json.contains("meta")) { + const auto o = json["meta"].toObject(); + p.meta.id = o["id"].toString(p.meta.id); + p.meta.displayName = o["displayName"].toString(p.meta.displayName); + const QString variantStr = o["variant"].toString(); + if (variantStr == "light") + p.meta.variant = ThemeVariant::Light; + else if (variantStr == "dark") + p.meta.variant = ThemeVariant::Dark; + } + + Theme theme = makeTheme(p); + theme.sourceJson = json; + return theme; } diff --git a/YACReader/themes/theme_factory.h b/YACReader/themes/theme_factory.h index 72cb4ca2..ebed9bbb 100644 --- a/YACReader/themes/theme_factory.h +++ b/YACReader/themes/theme_factory.h @@ -2,8 +2,9 @@ #define THEME_FACTORY_H #include "theme.h" -#include "theme_id.h" -Theme makeTheme(ThemeId themeId); +#include + +Theme makeTheme(const QJsonObject &json); #endif // THEME_FACTORY_H diff --git a/YACReader/themes/themes.qrc b/YACReader/themes/themes.qrc new file mode 100644 index 00000000..62ec21fe --- /dev/null +++ b/YACReader/themes/themes.qrc @@ -0,0 +1,7 @@ + + + builtin_classic.json + builtin_light.json + builtin_dark.json + + diff --git a/YACReaderLibrary/CMakeLists.txt b/YACReaderLibrary/CMakeLists.txt index cae71e34..485c1191 100644 --- a/YACReaderLibrary/CMakeLists.txt +++ b/YACReaderLibrary/CMakeLists.txt @@ -203,10 +203,14 @@ target_compile_definitions(YACReaderLibrary PRIVATE qt_add_resources(yacreaderlibrary_images_rcc "${CMAKE_CURRENT_SOURCE_DIR}/images.qrc") qt_add_resources(yacreaderlibrary_files_rcc "${CMAKE_CURRENT_SOURCE_DIR}/files.qrc") qt_add_resources(yacreaderlibrary_qml_rcc "${CMAKE_CURRENT_SOURCE_DIR}/qml.qrc") +qt_add_resources(yacreaderlibrary_themes_rcc "${CMAKE_CURRENT_SOURCE_DIR}/themes/themes.qrc") +qt_add_resources(yacreaderlibrary_common_images_rcc "${CMAKE_SOURCE_DIR}/common/themes/appearance_config_images.qrc") target_sources(YACReaderLibrary PRIVATE ${yacreaderlibrary_images_rcc} ${yacreaderlibrary_files_rcc} ${yacreaderlibrary_qml_rcc} + ${yacreaderlibrary_themes_rcc} + ${yacreaderlibrary_common_images_rcc} ) if(WIN32 OR (UNIX AND NOT APPLE)) qt_add_resources(yacreaderlibrary_images_win_rcc "${CMAKE_CURRENT_SOURCE_DIR}/images_win.qrc") diff --git a/YACReaderLibrary/info_comics_view.cpp b/YACReaderLibrary/info_comics_view.cpp index a93aeb16..bb58b5bf 100644 --- a/YACReaderLibrary/info_comics_view.cpp +++ b/YACReaderLibrary/info_comics_view.cpp @@ -227,10 +227,18 @@ void InfoComicsView::applyTheme(const Theme &theme) const auto &qv = theme.qmlView; // Info panel colors + // Cache-bust the SVG file URLs so QML's image cache doesn't serve stale + // files when the theme is updated (the same file path is rewritten each time). + const QString bust = QString::number(QDateTime::currentMSecsSinceEpoch()); + auto svgUrl = [&bust](const QString &path) { + QUrl url = QUrl::fromLocalFile(path); + url.setQuery(bust); + return url; + }; ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("topShadow", QUrl::fromLocalFile(qv.topShadow)); - ctxt->setContextProperty("infoShadow", QUrl::fromLocalFile(qv.infoShadow)); - ctxt->setContextProperty("infoIndicator", QUrl::fromLocalFile(qv.infoIndicator)); + ctxt->setContextProperty("topShadow", svgUrl(qv.topShadow)); + ctxt->setContextProperty("infoShadow", svgUrl(qv.infoShadow)); + ctxt->setContextProperty("infoIndicator", svgUrl(qv.infoIndicator)); ctxt->setContextProperty("infoTextColor", qv.infoTextColor); ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); diff --git a/YACReaderLibrary/main.cpp b/YACReaderLibrary/main.cpp index 5507e25e..4d82ea86 100644 --- a/YACReaderLibrary/main.cpp +++ b/YACReaderLibrary/main.cpp @@ -21,7 +21,9 @@ #include "db_helper.h" #include "yacreader_libraries.h" #include "exit_check.h" +#include "appearance_configuration.h" #include "theme_manager.h" +#include "theme_repository.h" #ifdef Q_OS_MACOS #include "trayhandler.h" #endif @@ -140,7 +142,11 @@ int main(int argc, char **argv) app.setApplicationVersion(VERSION); // Theme initialization - ThemeManager::instance().initialize(); + auto *appearanceConfig = new AppearanceConfiguration( + YACReader::getSettingsPath() + "/YACReaderLibrary.ini", qApp); + auto *themeRepo = new ThemeRepository( + ":/themes", YACReader::getSettingsPath() + "/themes/user"); + ThemeManager::instance().initialize(appearanceConfig, themeRepo); // Set window icon according to Freedesktop icon specification // This is mostly relevant for Linux and other Unix systems diff --git a/YACReaderLibrary/options_dialog.cpp b/YACReaderLibrary/options_dialog.cpp index 53210ac8..1087d8ad 100644 --- a/YACReaderLibrary/options_dialog.cpp +++ b/YACReaderLibrary/options_dialog.cpp @@ -4,6 +4,11 @@ #include "api_key_dialog.h" #include "yacreader_global_gui.h" +#include "theme_manager.h" +#include "theme_factory.h" +#include "appearance_tab_widget.h" + +#include FlowType flowType = Strip; @@ -15,11 +20,14 @@ OptionsDialog::OptionsDialog(QWidget *parent) auto comicFlowW = createFlowTab(); auto gridViewW = createGridTab(); + auto appearanceW = createAppearanceTab(); + auto tabWidget = new QTabWidget(); tabWidget->addTab(generalW, tr("General")); tabWidget->addTab(librariesW, tr("Libraries")); tabWidget->addTab(comicFlowW, tr("Comic Flow")); tabWidget->addTab(gridViewW, tr("Grid view")); + tabWidget->addTab(appearanceW, tr("Appearance")); auto buttons = new QHBoxLayout(); buttons->addStretch(); @@ -406,3 +414,12 @@ QWidget *OptionsDialog::createGridTab() return gridViewW; } + +QWidget *OptionsDialog::createAppearanceTab() +{ + return new AppearanceTabWidget( + ThemeManager::instance().getAppearanceConfiguration(), + []() { return ThemeManager::instance().getCurrentTheme().sourceJson; }, + [](const QJsonObject &json) { ThemeManager::instance().setTheme(makeTheme(json)); }, + this); +} diff --git a/YACReaderLibrary/options_dialog.h b/YACReaderLibrary/options_dialog.h index ccf8a2ff..84caae53 100644 --- a/YACReaderLibrary/options_dialog.h +++ b/YACReaderLibrary/options_dialog.h @@ -61,6 +61,7 @@ private: QWidget *createLibrariesTab(); QWidget *createFlowTab(); QWidget *createGridTab(); + QWidget *createAppearanceTab(); }; #endif diff --git a/YACReaderLibrary/themes/builtin_classic.json b/YACReaderLibrary/themes/builtin_classic.json new file mode 100644 index 00000000..a365fbb8 --- /dev/null +++ b/YACReaderLibrary/themes/builtin_classic.json @@ -0,0 +1,238 @@ +{ + "meta": { + "id": "builtin/classic", + "displayName": "Default Classic", + "variant": "dark" + }, + "defaultContentBackgroundColor": "#2a2a2a", + "comicFlow": { + "backgroundColor": "#000000", + "textColor": "#4c4c4c" + }, + "comicVine": { + "contentTextColor": "#ffffff", + "contentBackgroundColor": "#2b2b2b", + "contentAltBackgroundColor": "#2b2b2b", + "dialogBackgroundColor": "#404040", + "tableBackgroundColor": "#2b2b2b", + "tableAltBackgroundColor": "#2e2e2e", + "tableBorderColor": "#242424", + "tableSelectedColor": "#555555", + "tableHeaderBackgroundColor": "#292929", + "tableHeaderGradientColor": "#292929", + "tableHeaderBorderColor": "#1f1f1f", + "tableHeaderTextColor": "#ebebeb", + "tableScrollHandleColor": "#dddddd", + "tableScrollBackgroundColor": "#404040", + "tableSectionBorderLight": "#fefefe", + "tableSectionBorderDark": "#dfdfdf", + "labelTextColor": "#ffffff", + "labelBackgroundColor": "#2b2b2b", + "hyperlinkColor": "#ffcc00", + "buttonBackgroundColor": "#2e2e2e", + "buttonTextColor": "#ffffff", + "buttonBorderColor": "#242424", + "radioUncheckedColor": "#e5e5e5", + "radioCheckedBackgroundColor": "#e5e5e5", + "radioCheckedIndicatorColor": "#5f5f5f", + "checkBoxTickColor": "#ffffff", + "toolButtonAccentColor": "#282828", + "downArrowColor": "#9f9f9f", + "upArrowColor": "#9f9f9f", + "busyIndicatorColor": "#ffffff", + "navIconColor": "#ffffff", + "rowIconColor": "#e5e5e5" + }, + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, + "whatsNewDialog": { + "backgroundColor": "#2a2a2a", + "headerTextColor": "#e0e0e0", + "versionTextColor": "#858585", + "contentTextColor": "#e0e0e0", + "linkColor": "#e8b800", + "closeButtonColor": "#dddddd", + "headerDecorationColor": "#e8b800" + }, + "emptyContainer": { + "backgroundColor": "#2a2a2a", + "titleTextColor": "#cccccc", + "textColor": "#cccccc", + "descriptionTextColor": "#aaaaaa", + "searchIconColor": "#4c4c4c" + }, + "sidebar": { + "backgroundColor": "#454545", + "separatorColor": "#bdbfbf", + "sectionSeparatorColor": "#575757", + "uppercaseLabels": true, + "titleTextColor": "#bdbfbf", + "titleDropShadowColor": "#000000", + "busyIndicatorColor": "#ffffff" + }, + "sidebarIcons": { + "iconColor": "#e0e0e0", + "shadowColor": "#000000", + "useSystemFolderIcons": false + }, + "libraryItem": { + "textColor": "#dddfdf", + "libraryIconColor": "#dddfdf", + "libraryIconShadowColor": "#000000", + "selectedTextColor": "#ffffff", + "selectedBackgroundColor": "#2e2e2e", + "libraryIconSelectedColor": "#ffffff", + "libraryOptionsIconColor": "#ffffff" + }, + "importWidget": { + "backgroundColor": "#2a2a2a", + "titleTextColor": "#cccccc", + "descriptionTextColor": "#aaaaaa", + "currentComicTextColor": "#aaaaaa", + "coversViewBackgroundColor": "#3a3a3a", + "coversLabelColor": "#aaaaaa", + "coversDecorationBgColor": "#3a3a3a", + "coversDecorationShadowColor": "#1a1a1a", + "modeIconColor": "#4a4a4a", + "iconColor": "#cccccc", + "iconCheckedColor": "#aaaaaa" + }, + "serverConfigDialog": { + "backgroundColor": "#2a2a2a", + "titleTextColor": "#474747", + "qrMessageTextColor": "#a3a3a3", + "propagandaTextColor": "#4d4d4d", + "labelTextColor": "#575757", + "checkBoxTextColor": "#262626", + "qrBackgroundColor": "#2a2a2a", + "qrForegroundColor": "#ffffff", + "decorationColor": "#f7f7f7" + }, + "mainToolbar": { + "backgroundColor": "#f0f0f0", + "folderNameColor": "#404040", + "dividerColor": "#b8bdc4", + "iconColor": "#404040", + "iconDisabledColor": "#b0b0b0" + }, + "contentSplitter": { + "handleColor": "#b8b8b8", + "horizontalHandleHeight": 4, + "verticalHandleWidth": 4 + }, + "treeView": { + "textColor": "#dddfdf", + "selectionBackgroundColor": "#2e2e2e", + "scrollBackgroundColor": "#404040", + "scrollHandleColor": "#dddddd", + "selectedTextColor": "#ffffff", + "folderIndicatorColor": "#edc518", + "branchIndicatorColor": "#e0e0e0", + "branchIndicatorSelectedColor": "#ffffff", + "folderIconColor": "#e0e0e0", + "folderIconShadowColor": "#000000", + "folderIconSelectedColor": "#e0e0e0", + "folderIconSelectedShadowColor": "#000000", + "folderReadOverlayColor": "#464646", + "folderReadOverlaySelectedColor": "#464646" + }, + "tableView": { + "alternateBackgroundColor": "#f2f2f2", + "backgroundColor": "#fafafa", + "headerBackgroundColor": "#f5f5f5", + "headerBorderColor": "#b8bdc4", + "headerGradientColor": "#d1d1d1", + "itemBorderBottomColor": "#dfdfdf", + "itemBorderTopColor": "#fefefe", + "itemBorderBottomWidth": 1, + "itemBorderTopWidth": 1, + "itemTextColor": "#252626", + "selectedColor": "#d4d4d4", + "selectedTextColor": "#252626", + "headerTextColor": "#313232", + "starRatingColor": "#e9be0f", + "starRatingSelectedColor": "#ffffff" + }, + "qmlView": { + "backgroundColor": "#2a2a2a", + "cellColor": "#212121", + "cellColorWithBackground": "#99212121", + "selectedColor": "#121212", + "selectedBorderColor": "#ffcc00", + "borderColor": "#121212", + "titleColor": "#ffffff", + "textColor": "#a8a8a8", + "showDropShadow": true, + "infoBackgroundColor": "#2e2e2e", + "infoBorderColor": "#404040", + "infoShadowColor": "#000000", + "infoTextColor": "#b0b0b0", + "infoTitleColor": "#ffffff", + "ratingUnselectedColor": "#1c1c1c", + "ratingSelectedColor": "#ffffff", + "favUncheckedColor": "#1c1c1c", + "favCheckedColor": "#e84852", + "readTickUncheckedColor": "#1c1c1c", + "readTickCheckedColor": "#e84852", + "currentComicBackgroundColor": "#88000000", + "continueReadingBackgroundColor": "#88000000", + "continueReadingColor": "#ffffff", + "backgroundBlurOverlayColor": "#2a2a2a" + }, + "comicsViewToolbar": { + "backgroundColor": "#f0f0f0", + "separatorColor": "#cccccc", + "checkedBackgroundColor": "#cccccc", + "iconColor": "#404040" + }, + "searchLineEdit": { + "textColor": "#ababab", + "backgroundColor": "#404040", + "iconColor": "#f7f7f7" + }, + "readingListIcons": { + "labelColors": { + "red": "#f67a7b", + "orange": "#f5c240", + "yellow": "#f2e446", + "green": "#ade738", + "cyan": "#a0fddb", + "blue": "#82c7ff", + "violet": "#8f95ff", + "purple": "#d692fc", + "pink": "#fd9cda", + "white": "#fcfcfc", + "light": "#cbcbcb", + "dark": "#b7b7b7" + }, + "labelShadowColor": "#000000", + "labelShadowSelectedColor": "#000000", + "readingListMainColor": "#e7e7e7", + "readingListMainSelectedColor": "#e7e7e7", + "favoritesMainColor": "#e15055", + "favoritesMainSelectedColor": "#e15055", + "currentlyReadingMainColor": "#ffcc00", + "currentlyReadingMainSelectedColor": "#ffcc00", + "currentlyReadingOuterColor": "#000000", + "currentlyReadingOuterSelectedColor": "#000000", + "specialListShadowColor": "#000000", + "specialListShadowSelectedColor": "#000000", + "listMainColor": "#e7e7e7", + "listMainSelectedColor": "#e7e7e7", + "listShadowColor": "#000000", + "listShadowSelectedColor": "#000000", + "listDetailColor": "#464646", + "listDetailSelectedColor": "#464646" + }, + "dialogIcons": { + "iconColor": "#f7f7f7" + }, + "menuIcons": { + "iconColor": "#f7f7f7" + }, + "shortcutsIcons": { + "iconColor": "#f7f7f7" + } +} diff --git a/YACReaderLibrary/themes/builtin_dark.json b/YACReaderLibrary/themes/builtin_dark.json new file mode 100644 index 00000000..21855aca --- /dev/null +++ b/YACReaderLibrary/themes/builtin_dark.json @@ -0,0 +1,238 @@ +{ + "meta": { + "id": "builtin/dark", + "displayName": "Default Dark", + "variant": "dark" + }, + "defaultContentBackgroundColor": "#2a2a2a", + "comicFlow": { + "backgroundColor": "#111111", + "textColor": "#888888" + }, + "comicVine": { + "contentTextColor": "#ffffff", + "contentBackgroundColor": "#2b2b2b", + "contentAltBackgroundColor": "#2e2e2e", + "dialogBackgroundColor": "#404040", + "tableBackgroundColor": "#2b2b2b", + "tableAltBackgroundColor": "#2e2e2e", + "tableBorderColor": "#242424", + "tableSelectedColor": "#555555", + "tableHeaderBackgroundColor": "#292929", + "tableHeaderGradientColor": "#292929", + "tableHeaderBorderColor": "#1f1f1f", + "tableHeaderTextColor": "#ebebeb", + "tableScrollHandleColor": "#dddddd", + "tableScrollBackgroundColor": "#404040", + "tableSectionBorderLight": "#fefefe", + "tableSectionBorderDark": "#dfdfdf", + "labelTextColor": "#ffffff", + "labelBackgroundColor": "#2b2b2b", + "hyperlinkColor": "#ffcc00", + "buttonBackgroundColor": "#2e2e2e", + "buttonTextColor": "#ffffff", + "buttonBorderColor": "#242424", + "radioUncheckedColor": "#e5e5e5", + "radioCheckedBackgroundColor": "#e5e5e5", + "radioCheckedIndicatorColor": "#5f5f5f", + "checkBoxTickColor": "#ffffff", + "toolButtonAccentColor": "#282828", + "downArrowColor": "#9f9f9f", + "upArrowColor": "#9f9f9f", + "busyIndicatorColor": "#ffffff", + "navIconColor": "#ffffff", + "rowIconColor": "#e5e5e5" + }, + "helpAboutDialog": { + "headingColor": "#e0e0e0", + "linkColor": "#d4a84b" + }, + "whatsNewDialog": { + "backgroundColor": "#2a2a2a", + "headerTextColor": "#e0e0e0", + "versionTextColor": "#858585", + "contentTextColor": "#e0e0e0", + "linkColor": "#e8b800", + "closeButtonColor": "#dddddd", + "headerDecorationColor": "#e8b800" + }, + "emptyContainer": { + "backgroundColor": "#2a2a2a", + "titleTextColor": "#cccccc", + "textColor": "#cccccc", + "descriptionTextColor": "#aaaaaa", + "searchIconColor": "#4c4c4c" + }, + "sidebar": { + "backgroundColor": "#454545", + "separatorColor": "#bdbfbf", + "sectionSeparatorColor": "#575757", + "uppercaseLabels": true, + "titleTextColor": "#bdbfbf", + "titleDropShadowColor": "#000000", + "busyIndicatorColor": "#ffffff" + }, + "sidebarIcons": { + "iconColor": "#e0e0e0", + "shadowColor": "#000000", + "useSystemFolderIcons": false + }, + "libraryItem": { + "textColor": "#dddfdf", + "libraryIconColor": "#dddfdf", + "libraryIconShadowColor": "#000000", + "selectedTextColor": "#ffffff", + "selectedBackgroundColor": "#2e2e2e", + "libraryIconSelectedColor": "#ffffff", + "libraryOptionsIconColor": "#ffffff" + }, + "importWidget": { + "backgroundColor": "#2a2a2a", + "titleTextColor": "#cccccc", + "descriptionTextColor": "#aaaaaa", + "currentComicTextColor": "#aaaaaa", + "coversViewBackgroundColor": "#3a3a3a", + "coversLabelColor": "#aaaaaa", + "coversDecorationBgColor": "#3a3a3a", + "coversDecorationShadowColor": "#1a1a1a", + "modeIconColor": "#4a4a4a", + "iconColor": "#cccccc", + "iconCheckedColor": "#aaaaaa" + }, + "serverConfigDialog": { + "backgroundColor": "#2a2a2a", + "titleTextColor": "#d0d0d0", + "qrMessageTextColor": "#a3a3a3", + "propagandaTextColor": "#b0b0b0", + "labelTextColor": "#c0c0c0", + "checkBoxTextColor": "#dddddd", + "qrBackgroundColor": "#2a2a2a", + "qrForegroundColor": "#ffffff", + "decorationColor": "#f7f7f7" + }, + "mainToolbar": { + "backgroundColor": "#2a2a2a", + "folderNameColor": "#dddddd", + "dividerColor": "#555555", + "iconColor": "#dddddd", + "iconDisabledColor": "#666666" + }, + "contentSplitter": { + "handleColor": "#1f1f1f", + "horizontalHandleHeight": 4, + "verticalHandleWidth": 4 + }, + "treeView": { + "textColor": "#dddfdf", + "selectionBackgroundColor": "#2e2e2e", + "scrollBackgroundColor": "#404040", + "scrollHandleColor": "#dddddd", + "selectedTextColor": "#ffffff", + "folderIndicatorColor": "#edc518", + "branchIndicatorColor": "#e0e0e0", + "branchIndicatorSelectedColor": "#ffffff", + "folderIconColor": "#e0e0e0", + "folderIconShadowColor": "#000000", + "folderIconSelectedColor": "#e0e0e0", + "folderIconSelectedShadowColor": "#000000", + "folderReadOverlayColor": "#222222", + "folderReadOverlaySelectedColor": "#222222" + }, + "tableView": { + "alternateBackgroundColor": "#2e2e2e", + "backgroundColor": "#2a2a2a", + "headerBackgroundColor": "#2a2a2a", + "headerBorderColor": "#1f1f1f", + "headerGradientColor": "#252525", + "itemBorderBottomColor": "#1f1f1f", + "itemBorderTopColor": "#353535", + "itemBorderBottomWidth": 1, + "itemBorderTopWidth": 1, + "itemTextColor": "#dddddd", + "selectedColor": "#555555", + "selectedTextColor": "#ffffff", + "headerTextColor": "#dddddd", + "starRatingColor": "#e9be0f", + "starRatingSelectedColor": "#ffffff" + }, + "qmlView": { + "backgroundColor": "#2a2a2a", + "cellColor": "#212121", + "cellColorWithBackground": "#99212121", + "selectedColor": "#121212", + "selectedBorderColor": "#ffcc00", + "borderColor": "#121212", + "titleColor": "#ffffff", + "textColor": "#a8a8a8", + "showDropShadow": true, + "infoBackgroundColor": "#2e2e2e", + "infoBorderColor": "#404040", + "infoShadowColor": "#000000", + "infoTextColor": "#b0b0b0", + "infoTitleColor": "#ffffff", + "ratingUnselectedColor": "#1c1c1c", + "ratingSelectedColor": "#ffffff", + "favUncheckedColor": "#1c1c1c", + "favCheckedColor": "#e84852", + "readTickUncheckedColor": "#1c1c1c", + "readTickCheckedColor": "#e84852", + "currentComicBackgroundColor": "#88000000", + "continueReadingBackgroundColor": "#88000000", + "continueReadingColor": "#ffffff", + "backgroundBlurOverlayColor": "#2a2a2a" + }, + "comicsViewToolbar": { + "backgroundColor": "#2a2a2a", + "separatorColor": "#444444", + "checkedBackgroundColor": "#555555", + "iconColor": "#dddddd" + }, + "searchLineEdit": { + "textColor": "#ababab", + "backgroundColor": "#404040", + "iconColor": "#f7f7f7" + }, + "readingListIcons": { + "labelColors": { + "red": "#f67a7b", + "orange": "#f5c240", + "yellow": "#f2e446", + "green": "#ade738", + "cyan": "#a0fddb", + "blue": "#82c7ff", + "violet": "#8f95ff", + "purple": "#d692fc", + "pink": "#fd9cda", + "white": "#fcfcfc", + "light": "#cbcbcb", + "dark": "#b7b7b7" + }, + "labelShadowColor": "#000000", + "labelShadowSelectedColor": "#000000", + "readingListMainColor": "#e7e7e7", + "readingListMainSelectedColor": "#e7e7e7", + "favoritesMainColor": "#e15055", + "favoritesMainSelectedColor": "#e15055", + "currentlyReadingMainColor": "#ffcc00", + "currentlyReadingMainSelectedColor": "#ffcc00", + "currentlyReadingOuterColor": "#000000", + "currentlyReadingOuterSelectedColor": "#000000", + "specialListShadowColor": "#000000", + "specialListShadowSelectedColor": "#000000", + "listMainColor": "#e7e7e7", + "listMainSelectedColor": "#e7e7e7", + "listShadowColor": "#000000", + "listShadowSelectedColor": "#000000", + "listDetailColor": "#464646", + "listDetailSelectedColor": "#464646" + }, + "dialogIcons": { + "iconColor": "#f7f7f7" + }, + "menuIcons": { + "iconColor": "#f7f7f7" + }, + "shortcutsIcons": { + "iconColor": "#f7f7f7" + } +} diff --git a/YACReaderLibrary/themes/builtin_light.json b/YACReaderLibrary/themes/builtin_light.json new file mode 100644 index 00000000..4d9c8744 --- /dev/null +++ b/YACReaderLibrary/themes/builtin_light.json @@ -0,0 +1,238 @@ +{ + "meta": { + "id": "builtin/light", + "displayName": "Default Light", + "variant": "light" + }, + "defaultContentBackgroundColor": "#ffffff", + "comicFlow": { + "backgroundColor": "#dcdcdc", + "textColor": "#303030" + }, + "comicVine": { + "contentTextColor": "#000000", + "contentBackgroundColor": "#ececec", + "contentAltBackgroundColor": "#e0e0e0", + "dialogBackgroundColor": "#fbfbfb", + "tableBackgroundColor": "#f4f4f4", + "tableAltBackgroundColor": "#fafafa", + "tableBorderColor": "#cccccc", + "tableSelectedColor": "#dddddd", + "tableHeaderBackgroundColor": "#e0e0e0", + "tableHeaderGradientColor": "#e0e0e0", + "tableHeaderBorderColor": "#c0c0c0", + "tableHeaderTextColor": "#333333", + "tableScrollHandleColor": "#888888", + "tableScrollBackgroundColor": "#d0d0d0", + "tableSectionBorderLight": "#ffffff", + "tableSectionBorderDark": "#cccccc", + "labelTextColor": "#000000", + "labelBackgroundColor": "#ececec", + "hyperlinkColor": "#ffcc00", + "buttonBackgroundColor": "#e0e0e0", + "buttonTextColor": "#000000", + "buttonBorderColor": "#cccccc", + "radioUncheckedColor": "#e0e0e0", + "radioCheckedBackgroundColor": "#e0e0e0", + "radioCheckedIndicatorColor": "#222222", + "checkBoxTickColor": "#000000", + "toolButtonAccentColor": "#a0a0a0", + "downArrowColor": "#222222", + "upArrowColor": "#222222", + "busyIndicatorColor": "#000000", + "navIconColor": "#222222", + "rowIconColor": "#222222" + }, + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, + "whatsNewDialog": { + "backgroundColor": "#ffffff", + "headerTextColor": "#0a0a0a", + "versionTextColor": "#858585", + "contentTextColor": "#0a0a0a", + "linkColor": "#e8b800", + "closeButtonColor": "#444444", + "headerDecorationColor": "#e8b800" + }, + "emptyContainer": { + "backgroundColor": "#ffffff", + "titleTextColor": "#888888", + "textColor": "#495252", + "descriptionTextColor": "#565959", + "searchIconColor": "#cccccc" + }, + "sidebar": { + "backgroundColor": "#fbfbfb", + "separatorColor": "#808080", + "sectionSeparatorColor": "#e0e0e0", + "uppercaseLabels": true, + "titleTextColor": "#4a494a", + "titleDropShadowColor": "#ffffff", + "busyIndicatorColor": "#808080" + }, + "sidebarIcons": { + "iconColor": "#4f4e4f", + "shadowColor": "#fbfbfb", + "useSystemFolderIcons": false + }, + "libraryItem": { + "textColor": "#000000", + "libraryIconColor": "#606060", + "libraryIconShadowColor": "#ffffff", + "selectedTextColor": "#ffffff", + "selectedBackgroundColor": "#333133", + "libraryIconSelectedColor": "#ffffff", + "libraryOptionsIconColor": "#ffffff" + }, + "importWidget": { + "backgroundColor": "#fafafa", + "titleTextColor": "#495252", + "descriptionTextColor": "#565959", + "currentComicTextColor": "#565959", + "coversViewBackgroundColor": "#e6e6e6", + "coversLabelColor": "#565959", + "coversDecorationBgColor": "#e6e6e6", + "coversDecorationShadowColor": "#a1a1a1", + "modeIconColor": "#e6e6e6", + "iconColor": "#495252", + "iconCheckedColor": "#565959" + }, + "serverConfigDialog": { + "backgroundColor": "#ffffff", + "titleTextColor": "#474747", + "qrMessageTextColor": "#a3a3a3", + "propagandaTextColor": "#4d4d4d", + "labelTextColor": "#575757", + "checkBoxTextColor": "#262626", + "qrBackgroundColor": "#ffffff", + "qrForegroundColor": "#606060", + "decorationColor": "#606060" + }, + "mainToolbar": { + "backgroundColor": "#f0f0f0", + "folderNameColor": "#333133", + "dividerColor": "#b8bdc4", + "iconColor": "#333133", + "iconDisabledColor": "#b0b0b0" + }, + "contentSplitter": { + "handleColor": "#f0f0f0", + "horizontalHandleHeight": 4, + "verticalHandleWidth": 4 + }, + "treeView": { + "textColor": "#000000", + "selectionBackgroundColor": "#333133", + "scrollBackgroundColor": "#e0e0e0", + "scrollHandleColor": "#888888", + "selectedTextColor": "#ffffff", + "folderIndicatorColor": "#555f7f", + "branchIndicatorColor": "#606060", + "branchIndicatorSelectedColor": "#ffffff", + "folderIconColor": "#606060", + "folderIconShadowColor": "#ffffff", + "folderIconSelectedColor": "#ffffff", + "folderIconSelectedShadowColor": "#161616", + "folderReadOverlayColor": "#ffffff", + "folderReadOverlaySelectedColor": "#161616" + }, + "tableView": { + "alternateBackgroundColor": "#f2f2f2", + "backgroundColor": "#fafafa", + "headerBackgroundColor": "#f5f5f5", + "headerBorderColor": "#b8bdc4", + "headerGradientColor": "#f5f5f5", + "itemBorderBottomColor": "#dfdfdf", + "itemBorderTopColor": "#fefefe", + "itemBorderBottomWidth": 0, + "itemBorderTopWidth": 0, + "itemTextColor": "#252626", + "selectedColor": "#595959", + "selectedTextColor": "#ffffff", + "headerTextColor": "#313232", + "starRatingColor": "#e9be0f", + "starRatingSelectedColor": "#ffffff" + }, + "qmlView": { + "backgroundColor": "#f6f6f6", + "cellColor": "#ffffff", + "cellColorWithBackground": "#99ffffff", + "selectedColor": "#ffffff", + "selectedBorderColor": "#ffcc00", + "borderColor": "#dbdbdb", + "titleColor": "#121212", + "textColor": "#636363", + "showDropShadow": true, + "infoBackgroundColor": "#ffffff", + "infoBorderColor": "#808080", + "infoShadowColor": "#444444", + "infoTextColor": "#404040", + "infoTitleColor": "#2e2e2e", + "ratingUnselectedColor": "#dedede", + "ratingSelectedColor": "#2b2b2b", + "favUncheckedColor": "#dedede", + "favCheckedColor": "#e84852", + "readTickUncheckedColor": "#dedede", + "readTickCheckedColor": "#e84852", + "currentComicBackgroundColor": "#88ffffff", + "continueReadingBackgroundColor": "#e8e8e8", + "continueReadingColor": "#000000", + "backgroundBlurOverlayColor": "#9e9e9e" + }, + "comicsViewToolbar": { + "backgroundColor": "#f0f0f0", + "separatorColor": "#cccccc", + "checkedBackgroundColor": "#cccccc", + "iconColor": "#404040" + }, + "searchLineEdit": { + "textColor": "#ffffff", + "backgroundColor": "#333133", + "iconColor": "#efefef" + }, + "readingListIcons": { + "labelColors": { + "red": "#f67a7b", + "orange": "#f5c240", + "yellow": "#f2e446", + "green": "#ade738", + "cyan": "#a0fddb", + "blue": "#82c7ff", + "violet": "#8f95ff", + "purple": "#d692fc", + "pink": "#fd9cda", + "white": "#fcfcfc", + "light": "#cbcbcb", + "dark": "#b7b7b7" + }, + "labelShadowColor": "#8f8f8f", + "labelShadowSelectedColor": "#161616", + "readingListMainColor": "#808080", + "readingListMainSelectedColor": "#808080", + "favoritesMainColor": "#e15055", + "favoritesMainSelectedColor": "#e15055", + "currentlyReadingMainColor": "#ffcc00", + "currentlyReadingMainSelectedColor": "#ffcc00", + "currentlyReadingOuterColor": "#000000", + "currentlyReadingOuterSelectedColor": "#000000", + "specialListShadowColor": "#8f8f8f", + "specialListShadowSelectedColor": "#161616", + "listMainColor": "#808080", + "listMainSelectedColor": "#ffffff", + "listShadowColor": "#8f8f8f", + "listShadowSelectedColor": "#161616", + "listDetailColor": "#ffffff", + "listDetailSelectedColor": "#161616" + }, + "dialogIcons": { + "iconColor": "#606060" + }, + "menuIcons": { + "iconColor": "#606060" + }, + "shortcutsIcons": { + "iconColor": "#606060" + } +} diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index 0d98c0ad..b0254429 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -2,10 +2,12 @@ #define THEME_H #include +#include #include "yacreader_icon.h" #include "help_about_dialog_theme.h" #include "whats_new_dialog_theme.h" +#include "theme_meta.h" struct ComicVineThemeTemplates { QString defaultLabelQSS = "QLabel {color:%1; font-size:12px;font-family:Arial;}"; @@ -452,6 +454,9 @@ struct ComicVineTheme { }; struct Theme { + ThemeMeta meta; + QJsonObject sourceJson; + QColor defaultContentBackgroundColor; ComicFlowColors comicFlow; diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index b9e103e2..1e0818cd 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -300,7 +300,7 @@ struct WhatsNewDialogParams { }; struct ThemeParams { - QString themeName; + ThemeMeta meta; QColor defaultContentBackgroundColor; ComicFlowColors comicFlowColors; @@ -342,13 +342,13 @@ Theme makeTheme(const ThemeParams ¶ms) const auto &t = cv.t; auto recolor = [&](const QString &path, const QColor &color) { - return recoloredSvgToThemeFile(path, color, params.themeName); + return recoloredSvgToThemeFile(path, color, params.meta.id); }; theme.comicVine.defaultLabelQSS = t.defaultLabelQSS.arg(cv.labelTextColor.name()); theme.comicVine.titleLabelQSS = t.titleLabelQSS.arg(cv.labelTextColor.name()); theme.comicVine.coverLabelQSS = t.coverLabelQSS.arg(cv.labelBackgroundColor.name(), cv.labelTextColor.name()); - theme.comicVine.radioButtonQSS = t.radioButtonQSS.arg(cv.buttonTextColor.name(), recolor(":/images/comic_vine/radioUnchecked.svg", cv.radioUncheckedColor), recoloredSvgToThemeFile(":/images/comic_vine/radioChecked.svg", cv.radioCheckedBackgroundColor, cv.radioCheckedIndicatorColor, params.themeName)); + theme.comicVine.radioButtonQSS = t.radioButtonQSS.arg(cv.buttonTextColor.name(), recolor(":/images/comic_vine/radioUnchecked.svg", cv.radioUncheckedColor), recoloredSvgToThemeFile(":/images/comic_vine/radioChecked.svg", cv.radioCheckedBackgroundColor, cv.radioCheckedIndicatorColor, params.meta.id)); theme.comicVine.checkBoxQSS = t.checkBoxQSS.arg(cv.buttonTextColor.name(), cv.buttonBorderColor.name(), cv.buttonBackgroundColor.name(), recolor(":/images/comic_vine/checkBoxTick.svg", cv.checkBoxTickColor)); theme.comicVine.scraperLineEditTitleLabelQSS = t.scraperLineEditTitleLabelQSS.arg(cv.contentTextColor.name()); @@ -399,8 +399,8 @@ Theme makeTheme(const ThemeParams ¶ms) theme.whatsNewDialog.versionTextColor = wn.versionTextColor; theme.whatsNewDialog.contentTextColor = wn.contentTextColor; theme.whatsNewDialog.linkColor = wn.linkColor; - theme.whatsNewDialog.closeButtonIcon = QPixmap(recoloredSvgToThemeFile(":/images/custom_dialog/custom_close_button.svg", wn.closeButtonColor, params.themeName)); - theme.whatsNewDialog.headerDecoration = QPixmap(recoloredSvgToThemeFile(":/images/whats_new/whatsnew_header.svg", wn.headerDecorationColor, params.themeName)); + theme.whatsNewDialog.closeButtonIcon = QPixmap(recoloredSvgToThemeFile(":/images/custom_dialog/custom_close_button.svg", wn.closeButtonColor, params.meta.id)); + theme.whatsNewDialog.headerDecoration = QPixmap(recoloredSvgToThemeFile(":/images/whats_new/whatsnew_header.svg", wn.headerDecorationColor, params.meta.id)); // end WhatsNewDialog // EmptyContainer @@ -411,16 +411,16 @@ Theme makeTheme(const ThemeParams ¶ms) theme.emptyContainer.titleLabelQSS = ect.titleLabelQSS.arg(ec.titleTextColor.name()); theme.emptyContainer.textColor = ec.textColor; theme.emptyContainer.descriptionTextColor = ec.descriptionTextColor; - theme.emptyContainer.noLibrariesIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/noLibrariesIcon.svg", ec.searchIconColor, params.themeName), 165, 160, qApp->devicePixelRatio()); + theme.emptyContainer.noLibrariesIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/noLibrariesIcon.svg", ec.searchIconColor, params.meta.id), 165, 160, qApp->devicePixelRatio()); { const qreal dpr = qApp->devicePixelRatio(); - theme.emptyContainer.searchingIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/search_result.svg", ec.searchIconColor, params.themeName, { .suffix = "_searching" }), 97, dpr); - theme.emptyContainer.noSearchResultsIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/search_result.svg", ec.searchIconColor, params.themeName, { .suffix = "_no_results" }), 239, dpr); + theme.emptyContainer.searchingIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/search_result.svg", ec.searchIconColor, params.meta.id, { .suffix = "_searching" }), 97, dpr); + theme.emptyContainer.noSearchResultsIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/search_result.svg", ec.searchIconColor, params.meta.id, { .suffix = "_no_results" }), 239, dpr); - theme.emptyContainer.emptyFolderIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_folder.svg", ec.searchIconColor, params.themeName), 319, 243, dpr); - theme.emptyContainer.emptyFavoritesIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_favorites.svg", QColor(0xe84853), params.themeName), 238, 223, dpr); - theme.emptyContainer.emptyCurrentReadingsIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_current_readings.svg", ec.searchIconColor, params.themeName), 167, 214, dpr); - theme.emptyContainer.emptyReadingListIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_reading_list.svg", ec.searchIconColor, params.themeName), 248, 187, dpr); + theme.emptyContainer.emptyFolderIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_folder.svg", ec.searchIconColor, params.meta.id), 319, 243, dpr); + theme.emptyContainer.emptyFavoritesIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_favorites.svg", QColor(0xe84853), params.meta.id), 238, 223, dpr); + theme.emptyContainer.emptyCurrentReadingsIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_current_readings.svg", ec.searchIconColor, params.meta.id), 167, 214, dpr); + theme.emptyContainer.emptyReadingListIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/empty_container/empty_reading_list.svg", ec.searchIconColor, params.meta.id), 248, 187, dpr); // Generate empty label icons for each label color const auto &rli = params.readingListIconsParams; @@ -430,7 +430,7 @@ Theme makeTheme(const ThemeParams ¶ms) auto it = rli.labelColors.find(colorName); if (it != rli.labelColors.end()) { theme.emptyContainer.emptyLabelIcons[c] = renderSvgToPixmap( - recoloredSvgToThemeFile(":/images/empty_container/empty_label.svg", it.value(), params.themeName, { .suffix = "_" + colorName }), 243, 243, dpr); + recoloredSvgToThemeFile(":/images/empty_container/empty_label.svg", it.value(), params.meta.id, { .suffix = "_" + colorName }), 243, 243, dpr); } } } @@ -456,14 +456,14 @@ Theme makeTheme(const ThemeParams ¶ms) theme.importWidget.currentComicTextColor = iw.currentComicTextColor; theme.importWidget.coversViewBackgroundColor = iw.coversViewBackgroundColor; theme.importWidget.coversLabelColor = iw.coversLabelColor; - theme.importWidget.topCoversDecoration = QPixmap(recoloredSvgToThemeFile(":/images/import/importTopCoversDecoration.svg", iw.coversDecorationBgColor, iw.coversDecorationShadowColor, params.themeName)); - theme.importWidget.bottomCoversDecoration = QPixmap(recoloredSvgToThemeFile(":/images/import/importBottomCoversDecoration.svg", iw.coversDecorationBgColor, iw.coversDecorationShadowColor, params.themeName)); - theme.importWidget.importingIcon = QPixmap(recoloredSvgToThemeFile(":/images/import/importingIcon.svg", iw.modeIconColor, params.themeName)); - theme.importWidget.updatingIcon = QPixmap(recoloredSvgToThemeFile(":/images/import/updatingIcon.svg", iw.modeIconColor, params.themeName)); + theme.importWidget.topCoversDecoration = QPixmap(recoloredSvgToThemeFile(":/images/import/importTopCoversDecoration.svg", iw.coversDecorationBgColor, iw.coversDecorationShadowColor, params.meta.id)); + theme.importWidget.bottomCoversDecoration = QPixmap(recoloredSvgToThemeFile(":/images/import/importBottomCoversDecoration.svg", iw.coversDecorationBgColor, iw.coversDecorationShadowColor, params.meta.id)); + theme.importWidget.importingIcon = QPixmap(recoloredSvgToThemeFile(":/images/import/importingIcon.svg", iw.modeIconColor, params.meta.id)); + theme.importWidget.updatingIcon = QPixmap(recoloredSvgToThemeFile(":/images/import/updatingIcon.svg", iw.modeIconColor, params.meta.id)); { QIcon coversToggle; - const QString normalPath = recoloredSvgToThemeFile(":/images/import/coversToggle.svg", iw.iconColor, params.themeName); - const QString checkedPath = recoloredSvgToThemeFile(":/images/import/coversToggle.svg", iw.iconCheckedColor, params.themeName, { .suffix = "_checked" }); + const QString normalPath = recoloredSvgToThemeFile(":/images/import/coversToggle.svg", iw.iconColor, params.meta.id); + const QString checkedPath = recoloredSvgToThemeFile(":/images/import/coversToggle.svg", iw.iconCheckedColor, params.meta.id, { .suffix = "_checked" }); coversToggle.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); coversToggle.addFile(checkedPath, QSize(), QIcon::Normal, QIcon::On); theme.importWidget.coversToggleIcon = coversToggle; @@ -503,9 +503,9 @@ Theme makeTheme(const ThemeParams ¶ms) theme.qmlView.textColor = qv.textColor; theme.qmlView.showDropShadow = qv.showDropShadow; theme.qmlView.infoBackgroundColor = qv.infoBackgroundColor; - theme.qmlView.topShadow = recoloredSvgToThemeFile(":/qml/info-top-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.themeName); - theme.qmlView.infoShadow = recoloredSvgToThemeFile(":/qml/info-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.themeName); - theme.qmlView.infoIndicator = recoloredSvgToThemeFile(":/qml/info-indicator.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.themeName); + theme.qmlView.topShadow = recoloredSvgToThemeFile(":/qml/info-top-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.meta.id); + theme.qmlView.infoShadow = recoloredSvgToThemeFile(":/qml/info-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.meta.id); + theme.qmlView.infoIndicator = recoloredSvgToThemeFile(":/qml/info-indicator.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.meta.id); theme.qmlView.infoTextColor = qv.infoTextColor; theme.qmlView.infoTitleColor = qv.infoTitleColor; theme.qmlView.ratingUnselectedColor = qv.ratingUnselectedColor; @@ -557,8 +557,8 @@ Theme makeTheme(const ThemeParams ¶ms) // Build icons with Normal and Disabled states auto makeToolbarIcon = [&](const QString &basePath) { QIcon icon; - const QString normalPath = recoloredSvgToThemeFile(basePath, mt.iconColor, params.themeName); - const QString disabledPath = recoloredSvgToThemeFile(basePath, mt.iconDisabledColor, params.themeName, { .suffix = "_disabled" }); + const QString normalPath = recoloredSvgToThemeFile(basePath, mt.iconColor, params.meta.id); + const QString disabledPath = recoloredSvgToThemeFile(basePath, mt.iconDisabledColor, params.meta.id, { .suffix = "_disabled" }); icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(disabledPath, QSize(), QIcon::Disabled, QIcon::Off); return icon; @@ -581,7 +581,7 @@ Theme makeTheme(const ThemeParams ¶ms) // Helper to create icons with shadow (two-color: #f0f main, #0ff shadow) // Adds both Normal and Selected modes to prevent Qt from applying a selection tint auto makeSidebarIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, si.iconColor, si.shadowColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, si.iconColor, si.shadowColor, params.meta.id); QIcon icon; icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); @@ -590,7 +590,7 @@ Theme makeTheme(const ThemeParams ¶ms) // Helper for single-color icons (only #f0f main) auto makeSingleColorIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, si.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, si.iconColor, params.meta.id); QIcon icon; icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); @@ -600,14 +600,14 @@ Theme makeTheme(const ThemeParams ¶ms) // System folder icons flag and overlay theme.sidebarIcons.useSystemFolderIcons = si.useSystemFolderIcons; if (si.useSystemFolderIcons) { - const QString overlayPath = recoloredSvgToThemeFile(":/images/sidebar/folder_read_overlay.svg", params.treeViewParams.folderReadOverlayColor, params.themeName); + const QString overlayPath = recoloredSvgToThemeFile(":/images/sidebar/folder_read_overlay.svg", params.treeViewParams.folderReadOverlayColor, params.meta.id); theme.sidebarIcons.folderReadOverlay = QPixmap(overlayPath); } // Library icon (unselected state, two-color: #f0f main, #0ff shadow) { const auto &li = params.libraryItemParams; - const QString libraryIconPath = recoloredSvgToThemeFile(":/images/sidebar/libraryIcon.svg", li.libraryIconColor, li.libraryIconShadowColor, params.themeName); + const QString libraryIconPath = recoloredSvgToThemeFile(":/images/sidebar/libraryIcon.svg", li.libraryIconColor, li.libraryIconShadowColor, params.meta.id); QIcon icon; icon.addFile(libraryIconPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(libraryIconPath, QSize(), QIcon::Selected, QIcon::Off); @@ -634,11 +634,11 @@ Theme makeTheme(const ThemeParams ¶ms) theme.libraryItem.selectedBackgroundColor = li.selectedBackgroundColor; // Library icon when selected (uses its own color to contrast with selected background) - const QString libraryIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/libraryIconSelected.svg", li.libraryIconSelectedColor, params.themeName); + const QString libraryIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/libraryIconSelected.svg", li.libraryIconSelectedColor, params.meta.id); theme.libraryItem.libraryIconSelected = QIcon(libraryIconSelectedPath); // Library options icon (shown only when selected, uses its own color) - const QString libraryOptionsPath = recoloredSvgToThemeFile(":/images/sidebar/libraryOptions.svg", li.libraryOptionsIconColor, params.themeName); + const QString libraryOptionsPath = recoloredSvgToThemeFile(":/images/sidebar/libraryOptions.svg", li.libraryOptionsIconColor, params.meta.id); theme.libraryItem.libraryOptionsIcon = QIcon(libraryOptionsPath); // end LibraryItem @@ -646,10 +646,10 @@ Theme makeTheme(const ThemeParams ¶ms) const auto &tv = params.treeViewParams; // Branch indicator icons — own colors, independent of the sidebar icon color - theme.treeView.branchClosedIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorColor, params.themeName); - theme.treeView.branchOpenIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorColor, params.themeName); - theme.treeView.branchClosedIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorSelectedColor, params.themeName, { .suffix = "_selected" }); - theme.treeView.branchOpenIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorSelectedColor, params.themeName, { .suffix = "_selected" }); + theme.treeView.branchClosedIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorColor, params.meta.id); + theme.treeView.branchOpenIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorColor, params.meta.id); + theme.treeView.branchClosedIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); + theme.treeView.branchOpenIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); theme.treeView.treeViewQSS = tv.t.styledTreeViewQSS .arg(tv.textColor.name(), @@ -665,16 +665,16 @@ Theme makeTheme(const ThemeParams ¶ms) // Folder icon — normal and selected states with independent colors { - const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconColor, tv.folderIconShadowColor, params.themeName); - const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, params.themeName, { .suffix = "_selected" }); + const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconColor, tv.folderIconShadowColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, params.meta.id, { .suffix = "_selected" }); theme.treeView.folderIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); theme.treeView.folderIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); } // Folder finished icon — same but with tick (#ff0) recolored independently for each state { - const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconColor, tv.folderIconShadowColor, tv.folderReadOverlayColor, params.themeName); - const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, tv.folderReadOverlaySelectedColor, params.themeName, { .suffix = "_selected" }); + const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconColor, tv.folderIconShadowColor, tv.folderReadOverlayColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, tv.folderReadOverlaySelectedColor, params.meta.id, { .suffix = "_selected" }); theme.treeView.folderFinishedIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); theme.treeView.folderFinishedIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); } @@ -695,7 +695,7 @@ Theme makeTheme(const ThemeParams ¶ms) // Helper to create single-color icons for comics view toolbar auto makeComicsViewIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, cvt.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, cvt.iconColor, params.meta.id); QIcon icon; icon.addFile(path, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(path, QSize(), QIcon::Selected, QIcon::Off); @@ -734,8 +734,8 @@ Theme makeTheme(const ThemeParams ¶ms) theme.searchLineEdit.clearButtonQSS = sle.t.clearButtonQSS; const qreal dpr = qApp->devicePixelRatio(); - theme.searchLineEdit.searchIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/iconSearchNew.svg", sle.iconColor, params.themeName), 15, dpr); - theme.searchLineEdit.clearIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/clearSearchNew.svg", sle.iconColor, params.themeName), 12, dpr); + theme.searchLineEdit.searchIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/iconSearchNew.svg", sle.iconColor, params.meta.id), 15, dpr); + theme.searchLineEdit.clearIcon = renderSvgToPixmap(recoloredSvgToThemeFile(":/images/clearSearchNew.svg", sle.iconColor, params.meta.id), 12, dpr); // end SearchLineEdit // ReadingListIcons @@ -743,8 +743,8 @@ Theme makeTheme(const ThemeParams ¶ms) // Helper to create label icons from template (uses color name to generate label_.svg files) auto makeLabelIcon = [&](const QString &colorName, const QColor &mainColor) { - const QString normalPath = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowColor, params.themeName, { .fileName = "label_" + colorName }); - const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowSelectedColor, params.themeName, { .suffix = "_selected", .fileName = "label_" + colorName }); + const QString normalPath = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowColor, params.meta.id, { .fileName = "label_" + colorName }); + const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/label_template.svg", mainColor, rli.labelShadowSelectedColor, params.meta.id, { .suffix = "_selected", .fileName = "label_" + colorName }); QIcon icon; icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); @@ -757,8 +757,8 @@ Theme makeTheme(const ThemeParams ¶ms) // Special list icons auto makeSpecialIcon = [&](const QString &basePath, const QColor &mainColor, const QColor &mainSelectedColor) { - const QString normalPath = recoloredSvgToThemeFile(basePath, mainColor, rli.specialListShadowColor, params.themeName); - const QString selectedPath = recoloredSvgToThemeFile(basePath, mainSelectedColor, rli.specialListShadowSelectedColor, params.themeName, { .suffix = "_selected" }); + const QString normalPath = recoloredSvgToThemeFile(basePath, mainColor, rli.specialListShadowColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(basePath, mainSelectedColor, rli.specialListShadowSelectedColor, params.meta.id, { .suffix = "_selected" }); QIcon icon; icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); @@ -770,8 +770,8 @@ Theme makeTheme(const ThemeParams ¶ms) // Currently reading has 3 colors { - const QString normalPath = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainColor, rli.specialListShadowColor, rli.currentlyReadingOuterColor, params.themeName); - const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainSelectedColor, rli.specialListShadowSelectedColor, rli.currentlyReadingOuterSelectedColor, params.themeName, { .suffix = "_selected" }); + const QString normalPath = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainColor, rli.specialListShadowColor, rli.currentlyReadingOuterColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/default_2.svg", rli.currentlyReadingMainSelectedColor, rli.specialListShadowSelectedColor, rli.currentlyReadingOuterSelectedColor, params.meta.id, { .suffix = "_selected" }); QIcon icon; icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); @@ -780,8 +780,8 @@ Theme makeTheme(const ThemeParams ¶ms) // List icon (3 colors) { - const QString normalPath = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainColor, rli.listShadowColor, rli.listDetailColor, params.themeName); - const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainSelectedColor, rli.listShadowSelectedColor, rli.listDetailSelectedColor, params.themeName, { .suffix = "_selected" }); + const QString normalPath = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainColor, rli.listShadowColor, rli.listDetailColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(":/images/lists/list.svg", rli.listMainSelectedColor, rli.listShadowSelectedColor, rli.listDetailSelectedColor, params.meta.id, { .suffix = "_selected" }); QIcon icon; icon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); icon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); @@ -792,7 +792,7 @@ Theme makeTheme(const ThemeParams ¶ms) // MenuIcons const auto &mi = params.menuIconsParams; auto makeMenuIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, mi.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, mi.iconColor, params.meta.id); return QIcon(path); }; @@ -811,7 +811,7 @@ Theme makeTheme(const ThemeParams ¶ms) // DialogIcons const auto &di = params.dialogIconsParams; auto makeDialogIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, di.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, di.iconColor, params.meta.id); return QPixmap(path); }; theme.dialogIcons.newLibraryIcon = makeDialogIcon(":/images/library_dialogs/new.svg"); @@ -822,7 +822,7 @@ Theme makeTheme(const ThemeParams ¶ms) theme.dialogIcons.exportLibraryIcon = makeDialogIcon(":/images/library_dialogs/exportLibrary.svg"); theme.dialogIcons.importLibraryIcon = makeDialogIcon(":/images/library_dialogs/importLibrary.svg"); { - const QString path = recoloredSvgToThemeFile(":/images/find_folder.svg", di.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(":/images/find_folder.svg", di.iconColor, params.meta.id); const qreal dpr = qApp->devicePixelRatio(); theme.dialogIcons.findFolderIcon = QIcon(renderSvgToPixmap(path, 13, 13, dpr)); } @@ -831,7 +831,7 @@ Theme makeTheme(const ThemeParams ¶ms) // ShortcutsIcons const auto &sci = params.shortcutsIconsParams; auto makeShortcutsIcon = [&](const QString &basePath) { - const QString path = recoloredSvgToThemeFile(basePath, sci.iconColor, params.themeName); + const QString path = recoloredSvgToThemeFile(basePath, sci.iconColor, params.meta.id); return QIcon(path); }; @@ -852,842 +852,332 @@ Theme makeTheme(const ThemeParams ¶ms) theme.serverConfigDialog.checkBoxQSS = scd.t.checkBoxQSS.arg(scd.checkBoxTextColor.name()); theme.serverConfigDialog.qrBackgroundColor = scd.qrBackgroundColor; theme.serverConfigDialog.qrForegroundColor = scd.qrForegroundColor; - theme.serverConfigDialog.backgroundDecoration = QPixmap(recoloredSvgToThemeFile(":/images/serverConfigBackground.svg", scd.decorationColor, params.themeName)); + theme.serverConfigDialog.backgroundDecoration = QPixmap(recoloredSvgToThemeFile(":/images/serverConfigBackground.svg", scd.decorationColor, params.meta.id)); + + theme.meta = params.meta; return theme; } -ThemeParams classicThemeParams(); -ThemeParams lightThemeParams(); -ThemeParams darkThemeParams(); +// JSON helpers --------------------------------------------------------------- -Theme makeTheme(ThemeId themeId) +static QColor colorFromJson(const QJsonObject &obj, const QString &key, const QColor &fallback) { + if (!obj.contains(key)) + return fallback; + QColor c(obj[key].toString()); + return c.isValid() ? c : fallback; +} - switch (themeId) { - case ThemeId::Classic: - return makeTheme(classicThemeParams()); - case ThemeId::Light: - return makeTheme(lightThemeParams()); - case ThemeId::Dark: - return makeTheme(darkThemeParams()); +Theme makeTheme(const QJsonObject &json) +{ + ThemeParams p; + + if (json.contains("defaultContentBackgroundColor")) { + QColor c(json["defaultContentBackgroundColor"].toString()); + if (c.isValid()) + p.defaultContentBackgroundColor = c; } - return makeTheme(classicThemeParams()); -} - -ThemeParams classicThemeParams() -{ - ThemeParams params; - params.themeName = "classic"; - params.defaultContentBackgroundColor = QColor(0x2A2A2A); - - ComicFlowColors cf; - cf.backgroundColor = Qt::black; - cf.textColor = QColor(0x4C4C4C); - - ComicVineParams cv; - cv.contentTextColor = Qt::white; - cv.contentBackgroundColor = QColor(0x2B2B2B); - cv.contentAltBackgroundColor = QColor(0x2B2B2B); - cv.dialogBackgroundColor = QColor(0x404040); - - cv.tableBackgroundColor = QColor(0x2B2B2B); - cv.tableAltBackgroundColor = QColor(0x2E2E2E); - cv.tableBorderColor = QColor(0x242424); - cv.tableSelectedColor = QColor(0x555555); - cv.tableHeaderBackgroundColor = QColor(0x292929); - cv.tableHeaderGradientColor = QColor(0x292929); - cv.tableHeaderBorderColor = QColor(0x1F1F1F); - cv.tableHeaderTextColor = QColor(0xEBEBEB); - cv.tableScrollHandleColor = QColor(0xDDDDDD); - cv.tableScrollBackgroundColor = QColor(0x404040); - cv.tableSectionBorderLight = QColor(0xFEFEFE); - cv.tableSectionBorderDark = QColor(0xDFDFDF); - - cv.labelTextColor = Qt::white; - cv.labelBackgroundColor = QColor(0x2B2B2B); - cv.hyperlinkColor = QColor(0xFFCC00); - - cv.buttonBackgroundColor = QColor(0x2E2E2E); - cv.buttonTextColor = Qt::white; - cv.buttonBorderColor = QColor(0x242424); - - cv.radioUncheckedColor = QColor(0xE5E5E5); - - cv.radioCheckedBackgroundColor = QColor(0xE5E5E5); - cv.radioCheckedIndicatorColor = QColor(0x5F5F5F); - - cv.checkBoxTickColor = Qt::white; - - cv.toolButtonAccentColor = QColor(0x282828); - - cv.downArrowColor = QColor(0x9F9F9F); - cv.upArrowColor = QColor(0x9F9F9F); - - cv.busyIndicatorColor = Qt::white; - cv.navIconColor = Qt::white; - cv.rowIconColor = QColor(0xE5E5E5); - - cv.t = ComicVineThemeTemplates(); - - params.comicFlowColors = cf; - params.comicVineParams = cv; - - params.helpAboutDialogParams.headingColor = QColor(0x302f2d); - params.helpAboutDialogParams.linkColor = QColor(0xC19441); - - WhatsNewDialogParams wnp; - wnp.backgroundColor = QColor(0x2A2A2A); - wnp.headerTextColor = QColor(0xE0E0E0); - wnp.versionTextColor = QColor(0x858585); - wnp.contentTextColor = QColor(0xE0E0E0); - wnp.linkColor = QColor(0xE8B800); - wnp.closeButtonColor = QColor(0xDDDDDD); - wnp.headerDecorationColor = QColor(0xE8B800); - params.whatsNewDialogParams = wnp; - - EmptyContainerParams ec; - ec.backgroundColor = QColor(0x2A2A2A); - ec.titleTextColor = QColor(0xCCCCCC); - ec.textColor = QColor(0xCCCCCC); - ec.descriptionTextColor = QColor(0xAAAAAA); - ec.searchIconColor = QColor(0x4C4C4C); - ec.t = EmptyContainerThemeTemplates(); - params.emptyContainerParams = ec; - - SidebarParams sb; - sb.backgroundColor = QColor(0x454545); - sb.separatorColor = QColor(0xBDBFBF); - sb.sectionSeparatorColor = QColor(0x575757); - sb.uppercaseLabels = true; - sb.titleTextColor = QColor(0xBDBFBF); - sb.titleDropShadowColor = Qt::black; - sb.busyIndicatorColor = Qt::white; - params.sidebarParams = sb; - - ImportWidgetParams iw; - iw.backgroundColor = QColor(0x2A2A2A); - iw.titleTextColor = QColor(0xCCCCCC); - iw.descriptionTextColor = QColor(0xAAAAAA); - iw.currentComicTextColor = QColor(0xAAAAAA); - iw.coversViewBackgroundColor = QColor(0x3A3A3A); - iw.coversLabelColor = QColor(0xAAAAAA); - iw.coversDecorationBgColor = QColor(0x3A3A3A); - iw.coversDecorationShadowColor = QColor(0x1A1A1A); - iw.modeIconColor = QColor(0x4A4A4A); - iw.iconColor = QColor(0xCCCCCC); - iw.iconCheckedColor = QColor(0xAAAAAA); - params.importWidgetParams = iw; - - TreeViewParams tv; - tv.textColor = QColor(0xDDDFDF); - tv.selectionBackgroundColor = QColor(0x2E2E2E); - tv.scrollBackgroundColor = QColor(0x404040); - tv.scrollHandleColor = QColor(0xDDDDDD); - tv.selectedTextColor = Qt::white; - tv.folderIndicatorColor = QColor(237, 197, 24); - tv.branchIndicatorColor = QColor(0xE0E0E0); - tv.branchIndicatorSelectedColor = QColor(0xFFFFFF); - tv.folderIconColor = QColor(0xE0E0E0); - tv.folderIconShadowColor = QColor(0xFF000000); - tv.folderIconSelectedColor = QColor(0xE0E0E0); - tv.folderIconSelectedShadowColor = QColor(0xFF000000); - tv.folderReadOverlayColor = QColor(0x464646); - tv.folderReadOverlaySelectedColor = QColor(0x464646); - params.treeViewParams = tv; - - TableViewParams tav; - tav.alternateBackgroundColor = QColor(0xF2F2F2); - tav.backgroundColor = QColor(0xFAFAFA); - tav.headerBackgroundColor = QColor(0xF5F5F5); - tav.headerBorderColor = QColor(0xB8BDC4); - tav.headerGradientColor = QColor(0xD1D1D1); - tav.itemBorderBottomColor = QColor(0xDFDFDF); - tav.itemBorderTopColor = QColor(0xFEFEFE); - tav.itemBorderBottomWidth = 1; - tav.itemBorderTopWidth = 1; - tav.itemTextColor = QColor(0x252626); - tav.selectedColor = QColor(0xD4D4D4); - tav.selectedTextColor = QColor(0x252626); - tav.headerTextColor = QColor(0x313232); - tav.starRatingColor = QColor(0xE9BE0F); - tav.starRatingSelectedColor = QColor(0xFFFFFF); - tav.t = TableViewThemeTemplates(); - params.tableViewParams = tav; - - QmlViewParams qv; - qv.backgroundColor = QColor(0x2A2A2A); - qv.cellColor = QColor(0x212121); - qv.cellColorWithBackground = QColor(0x21, 0x21, 0x21, 0x99); - qv.selectedColor = QColor(0x121212); - qv.selectedBorderColor = QColor(0xFFCC00); - qv.borderColor = QColor(0x121212); - qv.titleColor = QColor(0xFFFFFF); - qv.textColor = QColor(0xA8A8A8); - qv.showDropShadow = true; - qv.infoBackgroundColor = QColor(0x2E2E2E); - qv.infoBorderColor = QColor(0x404040); - qv.infoShadowColor = Qt::black; - qv.infoTextColor = QColor(0xB0B0B0); - qv.infoTitleColor = QColor(0xFFFFFF); - qv.ratingUnselectedColor = QColor(0x1C1C1C); - qv.ratingSelectedColor = QColor(0xFFFFFF); - qv.favUncheckedColor = QColor(0x1C1C1C); - qv.favCheckedColor = QColor(0xE84852); - qv.readTickUncheckedColor = QColor(0x1C1C1C); - qv.readTickCheckedColor = QColor(0xE84852); - qv.currentComicBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); - qv.continueReadingBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); - qv.continueReadingColor = QColor(0xFFFFFF); - qv.backgroundBlurOverlayColor = QColor(0x2A2A2A); - params.qmlViewParams = qv; - - MainToolbarParams mt; - mt.backgroundColor = QColor(0xF0F0F0); - mt.folderNameColor = QColor(0x404040); - mt.dividerColor = QColor(0xB8BDC4); - mt.iconColor = QColor(0x404040); - mt.iconDisabledColor = QColor(0xB0B0B0); - params.mainToolbarParams = mt; - - ContentSplitterParams cs; - cs.handleColor = QColor(0xB8B8B8); - cs.horizontalHandleHeight = 4; - cs.verticalHandleWidth = 4; - params.contentSplitterParams = cs; - - SidebarIconsParams si; - si.iconColor = QColor(0xE0E0E0); - si.shadowColor = QColor(0xFF000000); - si.useSystemFolderIcons = false; - params.sidebarIconsParams = si; - - LibraryItemParams li; - li.textColor = QColor(0xDDDFDF); - li.libraryIconColor = QColor(0xDDDFDF); - li.libraryIconShadowColor = QColor(0xFF000000); - li.selectedTextColor = Qt::white; - li.selectedBackgroundColor = QColor(0x2E2E2E); - li.libraryIconSelectedColor = Qt::white; - li.libraryOptionsIconColor = Qt::white; - params.libraryItemParams = li; - - ComicsViewToolbarParams cvt; - cvt.backgroundColor = QColor(0xF0F0F0); - cvt.separatorColor = QColor(0xCCCCCC); - cvt.checkedBackgroundColor = QColor(0xCCCCCC); - cvt.iconColor = QColor(0x404040); - params.comicsViewToolbarParams = cvt; - - SearchLineEditParams sle; - sle.textColor = QColor(0xABABAB); - sle.backgroundColor = QColor(0x404040); - sle.iconColor = QColor(0xF7F7F7); - params.searchLineEditParams = sle; - - ReadingListIconsParams rli; - rli.labelColors = { - { "red", QColor(0xf67a7b) }, - { "orange", QColor(0xf5c240) }, - { "yellow", QColor(0xf2e446) }, - { "green", QColor(0xade738) }, - { "cyan", QColor(0xa0fddb) }, - { "blue", QColor(0x82c7ff) }, - { "violet", QColor(0x8f95ff) }, - { "purple", QColor(0xd692fc) }, - { "pink", QColor(0xfd9cda) }, - { "white", QColor(0xfcfcfc) }, - { "light", QColor(0xcbcbcb) }, - { "dark", QColor(0xb7b7b7) } - }; - rli.labelShadowColor = Qt::black; - rli.labelShadowSelectedColor = Qt::black; - rli.readingListMainColor = QColor(0xe7e7e7); - rli.readingListMainSelectedColor = QColor(0xe7e7e7); - rli.favoritesMainColor = QColor(0xe15055); - rli.favoritesMainSelectedColor = QColor(0xe15055); - rli.currentlyReadingMainColor = QColor(0xffcc00); - rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); - rli.currentlyReadingOuterColor = Qt::black; - rli.currentlyReadingOuterSelectedColor = Qt::black; - rli.specialListShadowColor = Qt::black; - rli.specialListShadowSelectedColor = Qt::black; - rli.listMainColor = QColor(0xe7e7e7); - rli.listMainSelectedColor = QColor(0xe7e7e7); - rli.listShadowColor = Qt::black; - rli.listShadowSelectedColor = Qt::black; - rli.listDetailColor = QColor(0x464646); - rli.listDetailSelectedColor = QColor(0x464646); - params.readingListIconsParams = rli; - - MenuIconsParams mi; - mi.iconColor = QColor(0xF7F7F7); - params.menuIconsParams = mi; - - DialogIconsParams dip; - dip.iconColor = mi.iconColor; - params.dialogIconsParams = dip; - - ShortcutsIconsParams sci; - sci.iconColor = QColor(0xF7F7F7); - params.shortcutsIconsParams = sci; - - ServerConfigDialogParams scd; - scd.backgroundColor = QColor(0x2A2A2A); - scd.titleTextColor = QColor(0x474747); - scd.qrMessageTextColor = QColor(0xA3A3A3); - scd.propagandaTextColor = QColor(0x4D4D4D); - scd.labelTextColor = QColor(0x575757); - scd.checkBoxTextColor = QColor(0x262626); - scd.qrBackgroundColor = QColor(0x2A2A2A); - scd.qrForegroundColor = Qt::white; - scd.decorationColor = QColor(0xF7F7F7); - params.serverConfigDialogParams = scd; - - return params; -} - -ThemeParams lightThemeParams() -{ - ThemeParams params; - params.themeName = "light"; - params.defaultContentBackgroundColor = QColor(0xFFFFFF); - - ComicFlowColors cf; - cf.backgroundColor = QColor(0xDCDCDC); - cf.textColor = QColor(0x303030); - - ComicVineParams cv; - cv.contentTextColor = Qt::black; - cv.contentBackgroundColor = QColor(0xECECEC); - cv.contentAltBackgroundColor = QColor(0xE0E0E0); - cv.dialogBackgroundColor = QColor(0xFBFBFB); - - cv.tableBackgroundColor = QColor(0xF4F4F4); - cv.tableAltBackgroundColor = QColor(0xFAFAFA); - cv.tableBorderColor = QColor(0xCCCCCC); - cv.tableSelectedColor = QColor(0xDDDDDD); - cv.tableHeaderBackgroundColor = QColor(0xE0E0E0); - cv.tableHeaderGradientColor = QColor(0xE0E0E0); - cv.tableHeaderBorderColor = QColor(0xC0C0C0); - cv.tableHeaderTextColor = QColor(0x333333); - cv.tableScrollHandleColor = QColor(0x888888); - cv.tableScrollBackgroundColor = QColor(0xD0D0D0); - cv.tableSectionBorderLight = QColor(0xFFFFFF); - cv.tableSectionBorderDark = QColor(0xCCCCCC); - - cv.labelTextColor = Qt::black; - cv.labelBackgroundColor = QColor(0xECECEC); - cv.hyperlinkColor = QColor(0xFFCC00); - - cv.buttonBackgroundColor = QColor(0xE0E0E0); - cv.buttonTextColor = Qt::black; - cv.buttonBorderColor = QColor(0xCCCCCC); - - cv.radioUncheckedColor = QColor(0xE0E0E0); - - cv.radioCheckedBackgroundColor = QColor(0xE0E0E0); - cv.radioCheckedIndicatorColor = QColor(0x222222); - - cv.checkBoxTickColor = Qt::black; - - cv.toolButtonAccentColor = QColor(0xA0A0A0); - - cv.downArrowColor = QColor(0x222222); - cv.upArrowColor = QColor(0x222222); - - cv.busyIndicatorColor = Qt::black; - cv.navIconColor = QColor(0x222222); - cv.rowIconColor = QColor(0x222222); - - cv.t = ComicVineThemeTemplates(); - - params.comicFlowColors = cf; - params.comicVineParams = cv; - - params.helpAboutDialogParams.headingColor = QColor(0x302f2d); - params.helpAboutDialogParams.linkColor = QColor(0xC19441); - - WhatsNewDialogParams wnp; - wnp.backgroundColor = QColor(0xFFFFFF); - wnp.headerTextColor = QColor(0x0A0A0A); - wnp.versionTextColor = QColor(0x858585); - wnp.contentTextColor = QColor(0x0A0A0A); - wnp.linkColor = QColor(0xE8B800); - wnp.closeButtonColor = QColor(0x444444); - wnp.headerDecorationColor = QColor(0xE8B800); - params.whatsNewDialogParams = wnp; - - EmptyContainerParams ec; - ec.backgroundColor = QColor(0xFFFFFF); - ec.titleTextColor = QColor(0x888888); - ec.textColor = QColor(0x495252); - ec.descriptionTextColor = QColor(0x565959); - ec.searchIconColor = QColor(0xCCCCCC); - ec.t = EmptyContainerThemeTemplates(); - params.emptyContainerParams = ec; - - SidebarParams sb; - sb.backgroundColor = QColor(0xFBFBFB); - sb.separatorColor = QColor(0x808080); - sb.sectionSeparatorColor = QColor(0xE0E0E0); - sb.uppercaseLabels = true; - sb.titleTextColor = QColor(0x4A494A); - sb.titleDropShadowColor = QColor(0xFFFFFF); - sb.busyIndicatorColor = QColor(0x808080); - params.sidebarParams = sb; - - ImportWidgetParams iw; - iw.backgroundColor = QColor(0xFAFAFA); - iw.titleTextColor = QColor(0x495252); - iw.descriptionTextColor = QColor(0x565959); - iw.currentComicTextColor = QColor(0x565959); - iw.coversViewBackgroundColor = QColor(0xE6E6E6); - iw.coversLabelColor = QColor(0x565959); - iw.coversDecorationBgColor = QColor(0xE6E6E6); - iw.coversDecorationShadowColor = QColor(0xA1A1A1); - iw.modeIconColor = QColor(0xE6E6E6); - iw.iconColor = QColor(0x495252); - iw.iconCheckedColor = QColor(0x565959); - params.importWidgetParams = iw; - - TreeViewParams tv; - tv.textColor = Qt::black; - tv.selectionBackgroundColor = QColor(0x333133); - tv.scrollBackgroundColor = QColor(0xE0E0E0); - tv.scrollHandleColor = QColor(0x888888); - tv.selectedTextColor = QColor(0xFFFFFF); - tv.folderIndicatorColor = QColor(85, 95, 127); - tv.branchIndicatorColor = QColor(0x606060); - tv.branchIndicatorSelectedColor = QColor(0xFFFFFF); - tv.folderIconColor = QColor(0x606060); - tv.folderIconShadowColor = QColor(0xFFFFFF); - tv.folderIconSelectedColor = QColor(0xFFFFFF); - tv.folderIconSelectedShadowColor = QColor(0x161616); - tv.folderReadOverlayColor = QColor(0xFFFFFF); - tv.folderReadOverlaySelectedColor = QColor(0x161616); - params.treeViewParams = tv; - - TableViewParams tav; - tav.alternateBackgroundColor = QColor(0xF2F2F2); - tav.backgroundColor = QColor(0xFAFAFA); - tav.headerBackgroundColor = QColor(0xF5F5F5); - tav.headerBorderColor = QColor(0xB8BDC4); - tav.headerGradientColor = QColor(0xF5F5F5); - tav.itemBorderBottomColor = QColor(0xDFDFDF); - tav.itemBorderTopColor = QColor(0xFEFEFE); - tav.itemBorderBottomWidth = 0; - tav.itemBorderTopWidth = 0; - tav.itemTextColor = QColor(0x252626); - tav.selectedColor = QColor(0x595959); - tav.selectedTextColor = QColor(0xFFFFFF); - tav.headerTextColor = QColor(0x313232); - tav.starRatingColor = QColor(0xE9BE0F); - tav.starRatingSelectedColor = QColor(0xFFFFFF); - tav.t = TableViewThemeTemplates(); - params.tableViewParams = tav; - - QmlViewParams qv; - qv.backgroundColor = QColor(0xF6F6F6); - qv.cellColor = QColor(0xFFFFFF); - qv.cellColorWithBackground = QColor(0xFF, 0xFF, 0xFF, 0x99); - qv.selectedColor = QColor(0xFFFFFF); - qv.selectedBorderColor = QColor(0xFFCC00); - qv.borderColor = QColor(0xDBDBDB); - qv.titleColor = QColor(0x121212); - qv.textColor = QColor(0x636363); - qv.showDropShadow = true; - qv.infoBackgroundColor = QColor(0xFFFFFF); - qv.infoBorderColor = QColor(0x808080); - qv.infoShadowColor = QColor(0x444444); - qv.infoTextColor = QColor(0x404040); - qv.infoTitleColor = QColor(0x2E2E2E); - qv.ratingUnselectedColor = QColor(0xDEDEDE); - qv.ratingSelectedColor = QColor(0x2B2B2B); - qv.favUncheckedColor = QColor(0xDEDEDE); - qv.favCheckedColor = QColor(0xE84852); - qv.readTickUncheckedColor = QColor(0xDEDEDE); - qv.readTickCheckedColor = QColor(0xE84852); - qv.currentComicBackgroundColor = QColor(0xFF, 0xFF, 0xFF, 0x88); - qv.continueReadingBackgroundColor = QColor(0xE8E8E8); - qv.continueReadingColor = QColor::fromRgb(0x000000); - qv.backgroundBlurOverlayColor = QColor(0x9E9E9E); - params.qmlViewParams = qv; - - MainToolbarParams mt; - mt.backgroundColor = QColor(0xF0F0F0); - mt.folderNameColor = QColor(0x333133); - mt.dividerColor = QColor(0xB8BDC4); - mt.iconColor = QColor(0x333133); - mt.iconDisabledColor = QColor(0xB0B0B0); - params.mainToolbarParams = mt; - - ContentSplitterParams cs; - cs.handleColor = QColor(0xF0F0F0); - cs.horizontalHandleHeight = 4; - cs.verticalHandleWidth = 4; - params.contentSplitterParams = cs; - - SidebarIconsParams si; - si.iconColor = QColor(0x4F4E4F); - si.shadowColor = QColor(0xFBFBFB); - si.useSystemFolderIcons = false; - params.sidebarIconsParams = si; - - LibraryItemParams li; - li.textColor = Qt::black; - li.libraryIconColor = QColor(0x606060); - li.libraryIconShadowColor = QColor(0xFFFFFF); - li.selectedTextColor = QColor(0xFFFFFF); - li.selectedBackgroundColor = QColor(0x333133); - li.libraryIconSelectedColor = QColor(0xFFFFFF); - li.libraryOptionsIconColor = QColor(0xFFFFFF); - params.libraryItemParams = li; - - ComicsViewToolbarParams cvt; - cvt.backgroundColor = QColor(0xF0F0F0); - cvt.separatorColor = QColor(0xCCCCCC); - cvt.checkedBackgroundColor = QColor(0xCCCCCC); - cvt.iconColor = QColor(0x404040); - params.comicsViewToolbarParams = cvt; - - SearchLineEditParams sle; - sle.textColor = QColor(0xFFFFFF); - sle.backgroundColor = QColor(0x333133); - sle.iconColor = QColor(0xEFEFEF); - params.searchLineEditParams = sle; - - ReadingListIconsParams rli; - rli.labelColors = { - { "red", QColor(0xf67a7b) }, - { "orange", QColor(0xf5c240) }, - { "yellow", QColor(0xf2e446) }, - { "green", QColor(0xade738) }, - { "cyan", QColor(0xa0fddb) }, - { "blue", QColor(0x82c7ff) }, - { "violet", QColor(0x8f95ff) }, - { "purple", QColor(0xd692fc) }, - { "pink", QColor(0xfd9cda) }, - { "white", QColor(0xfcfcfc) }, - { "light", QColor(0xcbcbcb) }, - { "dark", QColor(0xb7b7b7) } - }; - rli.labelShadowColor = QColor(0x8F8F8F); - rli.labelShadowSelectedColor = QColor(0x161616); - rli.readingListMainColor = QColor(0x808080); - rli.readingListMainSelectedColor = QColor(0x808080); - rli.favoritesMainColor = QColor(0xe15055); - rli.favoritesMainSelectedColor = QColor(0xe15055); - rli.currentlyReadingMainColor = QColor(0xffcc00); - rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); - rli.currentlyReadingOuterColor = Qt::black; - rli.currentlyReadingOuterSelectedColor = Qt::black; - rli.specialListShadowColor = QColor(0x8F8F8F); - rli.specialListShadowSelectedColor = QColor(0x161616); - rli.listMainColor = QColor(0x808080); - rli.listMainSelectedColor = QColor(0xFFFFFF); - rli.listShadowColor = QColor(0x8F8F8F); - rli.listShadowSelectedColor = QColor(0x161616); - rli.listDetailColor = QColor(0xFFFFFF); - rli.listDetailSelectedColor = QColor(0x161616); - params.readingListIconsParams = rli; - - MenuIconsParams mi; - mi.iconColor = QColor(0x606060); - params.menuIconsParams = mi; - - DialogIconsParams dip; - dip.iconColor = mi.iconColor; - params.dialogIconsParams = dip; - - ShortcutsIconsParams sci; - sci.iconColor = QColor(0x606060); - params.shortcutsIconsParams = sci; - - ServerConfigDialogParams scd; - scd.backgroundColor = QColor(0xFFFFFF); - scd.titleTextColor = QColor(0x474747); - scd.qrMessageTextColor = QColor(0xA3A3A3); - scd.propagandaTextColor = QColor(0x4D4D4D); - scd.labelTextColor = QColor(0x575757); - scd.checkBoxTextColor = QColor(0x262626); - scd.qrBackgroundColor = Qt::white; - scd.qrForegroundColor = QColor(0x606060); - scd.decorationColor = QColor(0x606060); - params.serverConfigDialogParams = scd; - - return params; -} - -ThemeParams darkThemeParams() -{ - ThemeParams params; - params.themeName = "dark"; - params.defaultContentBackgroundColor = QColor(0x2A2A2A); - - ComicFlowColors cf; - cf.backgroundColor = QColor(0x111111); - cf.textColor = QColor(0x888888); - - ComicVineParams cv; - cv.contentTextColor = Qt::white; - cv.contentBackgroundColor = QColor(0x2B2B2B); - cv.contentAltBackgroundColor = QColor(0x2E2E2E); - cv.dialogBackgroundColor = QColor(0x404040); - - cv.tableBackgroundColor = QColor(0x2B2B2B); - cv.tableAltBackgroundColor = QColor(0x2E2E2E); - cv.tableBorderColor = QColor(0x242424); - cv.tableSelectedColor = QColor(0x555555); - cv.tableHeaderBackgroundColor = QColor(0x292929); - cv.tableHeaderGradientColor = QColor(0x292929); - cv.tableHeaderBorderColor = QColor(0x1F1F1F); - cv.tableHeaderTextColor = QColor(0xEBEBEB); - cv.tableScrollHandleColor = QColor(0xDDDDDD); - cv.tableScrollBackgroundColor = QColor(0x404040); - cv.tableSectionBorderLight = QColor(0xFEFEFE); - cv.tableSectionBorderDark = QColor(0xDFDFDF); - - cv.labelTextColor = Qt::white; - cv.labelBackgroundColor = QColor(0x2B2B2B); - cv.hyperlinkColor = QColor(0xFFCC00); - - cv.buttonBackgroundColor = QColor(0x2E2E2E); - cv.buttonTextColor = Qt::white; - cv.buttonBorderColor = QColor(0x242424); - - cv.radioUncheckedColor = QColor(0xE5E5E5); - - cv.radioCheckedBackgroundColor = QColor(0xE5E5E5); - cv.radioCheckedIndicatorColor = QColor(0x5F5F5F); - - cv.checkBoxTickColor = Qt::white; - - cv.toolButtonAccentColor = QColor(0x282828); - - cv.downArrowColor = QColor(0x9F9F9F); - cv.upArrowColor = QColor(0x9F9F9F); - - cv.busyIndicatorColor = Qt::white; - cv.navIconColor = Qt::white; - cv.rowIconColor = QColor(0xE5E5E5); - - cv.t = ComicVineThemeTemplates(); - - params.comicFlowColors = cf; - params.comicVineParams = cv; - - params.helpAboutDialogParams.headingColor = QColor(0xE0E0E0); - params.helpAboutDialogParams.linkColor = QColor(0xD4A84B); - - WhatsNewDialogParams wnp; - wnp.backgroundColor = QColor(0x2A2A2A); - wnp.headerTextColor = QColor(0xE0E0E0); - wnp.versionTextColor = QColor(0x858585); - wnp.contentTextColor = QColor(0xE0E0E0); - wnp.linkColor = QColor(0xE8B800); - wnp.closeButtonColor = QColor(0xDDDDDD); - wnp.headerDecorationColor = QColor(0xE8B800); - params.whatsNewDialogParams = wnp; - - EmptyContainerParams ec; - ec.backgroundColor = QColor(0x2A2A2A); - ec.titleTextColor = QColor(0xCCCCCC); - ec.textColor = QColor(0xCCCCCC); - ec.descriptionTextColor = QColor(0xAAAAAA); - ec.searchIconColor = QColor(0x4C4C4C); - ec.t = EmptyContainerThemeTemplates(); - params.emptyContainerParams = ec; - - SidebarParams sb; - sb.backgroundColor = QColor(0x454545); - sb.separatorColor = QColor(0xBDBFBF); - sb.sectionSeparatorColor = QColor(0x575757); - sb.uppercaseLabels = true; - sb.titleTextColor = QColor(0xBDBFBF); - sb.titleDropShadowColor = Qt::black; - sb.busyIndicatorColor = Qt::white; - params.sidebarParams = sb; - - ImportWidgetParams iw; - iw.backgroundColor = QColor(0x2A2A2A); - iw.titleTextColor = QColor(0xCCCCCC); - iw.descriptionTextColor = QColor(0xAAAAAA); - iw.currentComicTextColor = QColor(0xAAAAAA); - iw.coversViewBackgroundColor = QColor(0x3A3A3A); - iw.coversLabelColor = QColor(0xAAAAAA); - iw.coversDecorationBgColor = QColor(0x3A3A3A); - iw.coversDecorationShadowColor = QColor(0x1A1A1A); - iw.modeIconColor = QColor(0x4A4A4A); - iw.iconColor = QColor(0xCCCCCC); - iw.iconCheckedColor = QColor(0xAAAAAA); - params.importWidgetParams = iw; - - TreeViewParams tv; - tv.textColor = QColor(0xDDDFDF); - tv.selectionBackgroundColor = QColor(0x2E2E2E); - tv.scrollBackgroundColor = QColor(0x404040); - tv.scrollHandleColor = QColor(0xDDDDDD); - tv.selectedTextColor = Qt::white; - tv.folderIndicatorColor = QColor(237, 197, 24); - tv.branchIndicatorColor = QColor(0xE0E0E0); - tv.branchIndicatorSelectedColor = QColor(0xFFFFFF); - tv.folderIconColor = QColor(0xE0E0E0); - tv.folderIconShadowColor = QColor(0xFF000000); - tv.folderIconSelectedColor = QColor(0xE0E0E0); - tv.folderIconSelectedShadowColor = QColor(0xFF000000); - tv.folderReadOverlayColor = QColor(0x222222); - tv.folderReadOverlaySelectedColor = QColor(0x222222); - params.treeViewParams = tv; - - TableViewParams tav; - tav.alternateBackgroundColor = QColor(0x2E2E2E); - tav.backgroundColor = QColor(0x2A2A2A); - tav.headerBackgroundColor = QColor(0x2A2A2A); - tav.headerBorderColor = QColor(0x1F1F1F); - tav.headerGradientColor = QColor(0x252525); - tav.itemBorderBottomColor = QColor(0x1F1F1F); - tav.itemBorderTopColor = QColor(0x353535); - tav.itemBorderBottomWidth = 1; - tav.itemBorderTopWidth = 1; - tav.itemTextColor = QColor(0xDDDDDD); - tav.selectedColor = QColor(0x555555); - tav.selectedTextColor = QColor(0xFFFFFF); - tav.headerTextColor = QColor(0xDDDDDD); - tav.starRatingColor = QColor(0xE9BE0F); - tav.starRatingSelectedColor = QColor(0xFFFFFF); - tav.t = TableViewThemeTemplates(); - params.tableViewParams = tav; - - QmlViewParams qv; - qv.backgroundColor = QColor(0x2A2A2A); - qv.cellColor = QColor(0x212121); - qv.cellColorWithBackground = QColor(0x21, 0x21, 0x21, 0x99); - qv.selectedColor = QColor(0x121212); - qv.selectedBorderColor = QColor(0xFFCC00); - qv.borderColor = QColor(0x121212); - qv.titleColor = QColor(0xFFFFFF); - qv.textColor = QColor(0xA8A8A8); - qv.showDropShadow = true; - qv.infoBackgroundColor = QColor(0x2E2E2E); - qv.infoBorderColor = QColor(0x404040); - qv.infoShadowColor = Qt::black; - qv.infoTextColor = QColor(0xB0B0B0); - qv.infoTitleColor = QColor(0xFFFFFF); - qv.ratingUnselectedColor = QColor(0x1C1C1C); - qv.ratingSelectedColor = QColor(0xFFFFFF); - qv.favUncheckedColor = QColor(0x1C1C1C); - qv.favCheckedColor = QColor(0xE84852); - qv.readTickUncheckedColor = QColor(0x1C1C1C); - qv.readTickCheckedColor = QColor(0xE84852); - qv.currentComicBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); - qv.continueReadingBackgroundColor = QColor(0x00, 0x00, 0x00, 0x88); - qv.continueReadingColor = QColor(0xFFFFFF); - qv.backgroundBlurOverlayColor = QColor(0x2A2A2A); - params.qmlViewParams = qv; - - MainToolbarParams mt; - mt.backgroundColor = QColor(0x2A2A2A); - mt.folderNameColor = QColor(0xDDDDDD); - mt.dividerColor = QColor(0x555555); - mt.iconColor = QColor(0xDDDDDD); - mt.iconDisabledColor = QColor(0x666666); - params.mainToolbarParams = mt; - - ContentSplitterParams cs; - cs.handleColor = QColor(0x1F1F1F); - cs.horizontalHandleHeight = 4; - cs.verticalHandleWidth = 4; - params.contentSplitterParams = cs; - - SidebarIconsParams si; - si.iconColor = QColor(0xE0E0E0); - si.shadowColor = QColor(0xFF000000); - si.useSystemFolderIcons = false; - params.sidebarIconsParams = si; - - LibraryItemParams li; - li.textColor = QColor(0xDDDFDF); - li.libraryIconColor = QColor(0xDDDFDF); - li.libraryIconShadowColor = QColor(0xFF000000); - li.selectedTextColor = Qt::white; - li.selectedBackgroundColor = QColor(0x2E2E2E); - li.libraryIconSelectedColor = Qt::white; - li.libraryOptionsIconColor = Qt::white; - params.libraryItemParams = li; - - ComicsViewToolbarParams cvt; - cvt.backgroundColor = QColor(0x2A2A2A); - cvt.separatorColor = QColor(0x444444); - cvt.checkedBackgroundColor = QColor(0x555555); - cvt.iconColor = QColor(0xDDDDDD); - params.comicsViewToolbarParams = cvt; - - SearchLineEditParams sle; - sle.textColor = QColor(0xABABAB); - sle.backgroundColor = QColor(0x404040); - sle.iconColor = QColor(0xF7F7F7); - params.searchLineEditParams = sle; - - ReadingListIconsParams rli; - rli.labelColors = { - { "red", QColor(0xf67a7b) }, - { "orange", QColor(0xf5c240) }, - { "yellow", QColor(0xf2e446) }, - { "green", QColor(0xade738) }, - { "cyan", QColor(0xa0fddb) }, - { "blue", QColor(0x82c7ff) }, - { "violet", QColor(0x8f95ff) }, - { "purple", QColor(0xd692fc) }, - { "pink", QColor(0xfd9cda) }, - { "white", QColor(0xfcfcfc) }, - { "light", QColor(0xcbcbcb) }, - { "dark", QColor(0xb7b7b7) } - }; - rli.labelShadowColor = Qt::black; - rli.labelShadowSelectedColor = Qt::black; - rli.readingListMainColor = QColor(0xe7e7e7); - rli.readingListMainSelectedColor = QColor(0xe7e7e7); - rli.favoritesMainColor = QColor(0xe15055); - rli.favoritesMainSelectedColor = QColor(0xe15055); - rli.currentlyReadingMainColor = QColor(0xffcc00); - rli.currentlyReadingMainSelectedColor = QColor(0xffcc00); - rli.currentlyReadingOuterColor = Qt::black; - rli.currentlyReadingOuterSelectedColor = Qt::black; - rli.specialListShadowColor = Qt::black; - rli.specialListShadowSelectedColor = Qt::black; - rli.listMainColor = QColor(0xe7e7e7); - rli.listMainSelectedColor = QColor(0xe7e7e7); - rli.listShadowColor = Qt::black; - rli.listShadowSelectedColor = Qt::black; - rli.listDetailColor = QColor(0x464646); - rli.listDetailSelectedColor = QColor(0x464646); - params.readingListIconsParams = rli; - - MenuIconsParams mi; - mi.iconColor = QColor(0xF7F7F7); - params.menuIconsParams = mi; - - DialogIconsParams dip; - dip.iconColor = mi.iconColor; - params.dialogIconsParams = dip; - - ShortcutsIconsParams sci; - sci.iconColor = QColor(0xF7F7F7); - params.shortcutsIconsParams = sci; - - ServerConfigDialogParams scd; - scd.backgroundColor = QColor(0x2A2A2A); - scd.titleTextColor = QColor(0xD0D0D0); - scd.qrMessageTextColor = QColor(0xA3A3A3); - scd.propagandaTextColor = QColor(0xB0B0B0); - scd.labelTextColor = QColor(0xC0C0C0); - scd.checkBoxTextColor = QColor(0xDDDDDD); - scd.qrBackgroundColor = QColor(0x2A2A2A); - scd.qrForegroundColor = Qt::white; - scd.decorationColor = QColor(0xF7F7F7); - params.serverConfigDialogParams = scd; - - return params; + if (json.contains("comicFlow")) { + const auto o = json["comicFlow"].toObject(); + p.comicFlowColors.backgroundColor = colorFromJson(o, "backgroundColor", p.comicFlowColors.backgroundColor); + p.comicFlowColors.textColor = colorFromJson(o, "textColor", p.comicFlowColors.textColor); + } + + if (json.contains("comicVine")) { + const auto o = json["comicVine"].toObject(); + auto &cv = p.comicVineParams; + cv.contentTextColor = colorFromJson(o, "contentTextColor", cv.contentTextColor); + cv.contentBackgroundColor = colorFromJson(o, "contentBackgroundColor", cv.contentBackgroundColor); + cv.contentAltBackgroundColor = colorFromJson(o, "contentAltBackgroundColor", cv.contentAltBackgroundColor); + cv.dialogBackgroundColor = colorFromJson(o, "dialogBackgroundColor", cv.dialogBackgroundColor); + cv.tableBackgroundColor = colorFromJson(o, "tableBackgroundColor", cv.tableBackgroundColor); + cv.tableAltBackgroundColor = colorFromJson(o, "tableAltBackgroundColor", cv.tableAltBackgroundColor); + cv.tableBorderColor = colorFromJson(o, "tableBorderColor", cv.tableBorderColor); + cv.tableSelectedColor = colorFromJson(o, "tableSelectedColor", cv.tableSelectedColor); + cv.tableHeaderBackgroundColor = colorFromJson(o, "tableHeaderBackgroundColor", cv.tableHeaderBackgroundColor); + cv.tableHeaderGradientColor = colorFromJson(o, "tableHeaderGradientColor", cv.tableHeaderGradientColor); + cv.tableHeaderBorderColor = colorFromJson(o, "tableHeaderBorderColor", cv.tableHeaderBorderColor); + cv.tableHeaderTextColor = colorFromJson(o, "tableHeaderTextColor", cv.tableHeaderTextColor); + cv.tableScrollHandleColor = colorFromJson(o, "tableScrollHandleColor", cv.tableScrollHandleColor); + cv.tableScrollBackgroundColor = colorFromJson(o, "tableScrollBackgroundColor", cv.tableScrollBackgroundColor); + cv.tableSectionBorderLight = colorFromJson(o, "tableSectionBorderLight", cv.tableSectionBorderLight); + cv.tableSectionBorderDark = colorFromJson(o, "tableSectionBorderDark", cv.tableSectionBorderDark); + cv.labelTextColor = colorFromJson(o, "labelTextColor", cv.labelTextColor); + cv.labelBackgroundColor = colorFromJson(o, "labelBackgroundColor", cv.labelBackgroundColor); + cv.hyperlinkColor = colorFromJson(o, "hyperlinkColor", cv.hyperlinkColor); + cv.buttonBackgroundColor = colorFromJson(o, "buttonBackgroundColor", cv.buttonBackgroundColor); + cv.buttonTextColor = colorFromJson(o, "buttonTextColor", cv.buttonTextColor); + cv.buttonBorderColor = colorFromJson(o, "buttonBorderColor", cv.buttonBorderColor); + cv.radioUncheckedColor = colorFromJson(o, "radioUncheckedColor", cv.radioUncheckedColor); + cv.radioCheckedBackgroundColor = colorFromJson(o, "radioCheckedBackgroundColor", cv.radioCheckedBackgroundColor); + cv.radioCheckedIndicatorColor = colorFromJson(o, "radioCheckedIndicatorColor", cv.radioCheckedIndicatorColor); + cv.checkBoxTickColor = colorFromJson(o, "checkBoxTickColor", cv.checkBoxTickColor); + cv.toolButtonAccentColor = colorFromJson(o, "toolButtonAccentColor", cv.toolButtonAccentColor); + cv.downArrowColor = colorFromJson(o, "downArrowColor", cv.downArrowColor); + cv.upArrowColor = colorFromJson(o, "upArrowColor", cv.upArrowColor); + cv.busyIndicatorColor = colorFromJson(o, "busyIndicatorColor", cv.busyIndicatorColor); + cv.navIconColor = colorFromJson(o, "navIconColor", cv.navIconColor); + cv.rowIconColor = colorFromJson(o, "rowIconColor", cv.rowIconColor); + } + + if (json.contains("helpAboutDialog")) { + const auto o = json["helpAboutDialog"].toObject(); + p.helpAboutDialogParams.headingColor = colorFromJson(o, "headingColor", p.helpAboutDialogParams.headingColor); + p.helpAboutDialogParams.linkColor = colorFromJson(o, "linkColor", p.helpAboutDialogParams.linkColor); + } + + if (json.contains("whatsNewDialog")) { + const auto o = json["whatsNewDialog"].toObject(); + auto &wn = p.whatsNewDialogParams; + wn.backgroundColor = colorFromJson(o, "backgroundColor", wn.backgroundColor); + wn.headerTextColor = colorFromJson(o, "headerTextColor", wn.headerTextColor); + wn.versionTextColor = colorFromJson(o, "versionTextColor", wn.versionTextColor); + wn.contentTextColor = colorFromJson(o, "contentTextColor", wn.contentTextColor); + wn.linkColor = colorFromJson(o, "linkColor", wn.linkColor); + wn.closeButtonColor = colorFromJson(o, "closeButtonColor", wn.closeButtonColor); + wn.headerDecorationColor = colorFromJson(o, "headerDecorationColor", wn.headerDecorationColor); + } + + if (json.contains("emptyContainer")) { + const auto o = json["emptyContainer"].toObject(); + auto &ec = p.emptyContainerParams; + ec.backgroundColor = colorFromJson(o, "backgroundColor", ec.backgroundColor); + ec.titleTextColor = colorFromJson(o, "titleTextColor", ec.titleTextColor); + ec.textColor = colorFromJson(o, "textColor", ec.textColor); + ec.descriptionTextColor = colorFromJson(o, "descriptionTextColor", ec.descriptionTextColor); + ec.searchIconColor = colorFromJson(o, "searchIconColor", ec.searchIconColor); + } + + if (json.contains("sidebar")) { + const auto o = json["sidebar"].toObject(); + auto &sb = p.sidebarParams; + sb.backgroundColor = colorFromJson(o, "backgroundColor", sb.backgroundColor); + sb.separatorColor = colorFromJson(o, "separatorColor", sb.separatorColor); + sb.sectionSeparatorColor = colorFromJson(o, "sectionSeparatorColor", sb.sectionSeparatorColor); + if (o.contains("uppercaseLabels")) + sb.uppercaseLabels = o["uppercaseLabels"].toBool(sb.uppercaseLabels); + sb.titleTextColor = colorFromJson(o, "titleTextColor", sb.titleTextColor); + sb.titleDropShadowColor = colorFromJson(o, "titleDropShadowColor", sb.titleDropShadowColor); + sb.busyIndicatorColor = colorFromJson(o, "busyIndicatorColor", sb.busyIndicatorColor); + } + + if (json.contains("sidebarIcons")) { + const auto o = json["sidebarIcons"].toObject(); + auto &si = p.sidebarIconsParams; + si.iconColor = colorFromJson(o, "iconColor", si.iconColor); + si.shadowColor = colorFromJson(o, "shadowColor", si.shadowColor); + if (o.contains("useSystemFolderIcons")) + si.useSystemFolderIcons = o["useSystemFolderIcons"].toBool(si.useSystemFolderIcons); + } + + if (json.contains("libraryItem")) { + const auto o = json["libraryItem"].toObject(); + auto &li = p.libraryItemParams; + li.textColor = colorFromJson(o, "textColor", li.textColor); + li.libraryIconColor = colorFromJson(o, "libraryIconColor", li.libraryIconColor); + li.libraryIconShadowColor = colorFromJson(o, "libraryIconShadowColor", li.libraryIconShadowColor); + li.selectedTextColor = colorFromJson(o, "selectedTextColor", li.selectedTextColor); + li.selectedBackgroundColor = colorFromJson(o, "selectedBackgroundColor", li.selectedBackgroundColor); + li.libraryIconSelectedColor = colorFromJson(o, "libraryIconSelectedColor", li.libraryIconSelectedColor); + li.libraryOptionsIconColor = colorFromJson(o, "libraryOptionsIconColor", li.libraryOptionsIconColor); + } + + if (json.contains("importWidget")) { + const auto o = json["importWidget"].toObject(); + auto &iw = p.importWidgetParams; + iw.backgroundColor = colorFromJson(o, "backgroundColor", iw.backgroundColor); + iw.titleTextColor = colorFromJson(o, "titleTextColor", iw.titleTextColor); + iw.descriptionTextColor = colorFromJson(o, "descriptionTextColor", iw.descriptionTextColor); + iw.currentComicTextColor = colorFromJson(o, "currentComicTextColor", iw.currentComicTextColor); + iw.coversViewBackgroundColor = colorFromJson(o, "coversViewBackgroundColor", iw.coversViewBackgroundColor); + iw.coversLabelColor = colorFromJson(o, "coversLabelColor", iw.coversLabelColor); + iw.coversDecorationBgColor = colorFromJson(o, "coversDecorationBgColor", iw.coversDecorationBgColor); + iw.coversDecorationShadowColor = colorFromJson(o, "coversDecorationShadowColor", iw.coversDecorationShadowColor); + iw.modeIconColor = colorFromJson(o, "modeIconColor", iw.modeIconColor); + iw.iconColor = colorFromJson(o, "iconColor", iw.iconColor); + iw.iconCheckedColor = colorFromJson(o, "iconCheckedColor", iw.iconCheckedColor); + } + + if (json.contains("serverConfigDialog")) { + const auto o = json["serverConfigDialog"].toObject(); + auto &scd2 = p.serverConfigDialogParams; + scd2.backgroundColor = colorFromJson(o, "backgroundColor", scd2.backgroundColor); + scd2.titleTextColor = colorFromJson(o, "titleTextColor", scd2.titleTextColor); + scd2.qrMessageTextColor = colorFromJson(o, "qrMessageTextColor", scd2.qrMessageTextColor); + scd2.propagandaTextColor = colorFromJson(o, "propagandaTextColor", scd2.propagandaTextColor); + scd2.labelTextColor = colorFromJson(o, "labelTextColor", scd2.labelTextColor); + scd2.checkBoxTextColor = colorFromJson(o, "checkBoxTextColor", scd2.checkBoxTextColor); + scd2.qrBackgroundColor = colorFromJson(o, "qrBackgroundColor", scd2.qrBackgroundColor); + scd2.qrForegroundColor = colorFromJson(o, "qrForegroundColor", scd2.qrForegroundColor); + scd2.decorationColor = colorFromJson(o, "decorationColor", scd2.decorationColor); + } + + if (json.contains("mainToolbar")) { + const auto o = json["mainToolbar"].toObject(); + auto &mt = p.mainToolbarParams; + mt.backgroundColor = colorFromJson(o, "backgroundColor", mt.backgroundColor); + mt.folderNameColor = colorFromJson(o, "folderNameColor", mt.folderNameColor); + mt.dividerColor = colorFromJson(o, "dividerColor", mt.dividerColor); + mt.iconColor = colorFromJson(o, "iconColor", mt.iconColor); + mt.iconDisabledColor = colorFromJson(o, "iconDisabledColor", mt.iconDisabledColor); + } + + if (json.contains("contentSplitter")) { + const auto o = json["contentSplitter"].toObject(); + auto &cs = p.contentSplitterParams; + cs.handleColor = colorFromJson(o, "handleColor", cs.handleColor); + if (o.contains("horizontalHandleHeight")) + cs.horizontalHandleHeight = o["horizontalHandleHeight"].toInt(cs.horizontalHandleHeight); + if (o.contains("verticalHandleWidth")) + cs.verticalHandleWidth = o["verticalHandleWidth"].toInt(cs.verticalHandleWidth); + } + + if (json.contains("treeView")) { + const auto o = json["treeView"].toObject(); + auto &tv = p.treeViewParams; + tv.textColor = colorFromJson(o, "textColor", tv.textColor); + tv.selectionBackgroundColor = colorFromJson(o, "selectionBackgroundColor", tv.selectionBackgroundColor); + tv.scrollBackgroundColor = colorFromJson(o, "scrollBackgroundColor", tv.scrollBackgroundColor); + tv.scrollHandleColor = colorFromJson(o, "scrollHandleColor", tv.scrollHandleColor); + tv.selectedTextColor = colorFromJson(o, "selectedTextColor", tv.selectedTextColor); + tv.folderIndicatorColor = colorFromJson(o, "folderIndicatorColor", tv.folderIndicatorColor); + tv.branchIndicatorColor = colorFromJson(o, "branchIndicatorColor", tv.branchIndicatorColor); + tv.branchIndicatorSelectedColor = colorFromJson(o, "branchIndicatorSelectedColor", tv.branchIndicatorSelectedColor); + tv.folderIconColor = colorFromJson(o, "folderIconColor", tv.folderIconColor); + tv.folderIconShadowColor = colorFromJson(o, "folderIconShadowColor", tv.folderIconShadowColor); + tv.folderIconSelectedColor = colorFromJson(o, "folderIconSelectedColor", tv.folderIconSelectedColor); + tv.folderIconSelectedShadowColor = colorFromJson(o, "folderIconSelectedShadowColor", tv.folderIconSelectedShadowColor); + tv.folderReadOverlayColor = colorFromJson(o, "folderReadOverlayColor", tv.folderReadOverlayColor); + tv.folderReadOverlaySelectedColor = colorFromJson(o, "folderReadOverlaySelectedColor", tv.folderReadOverlaySelectedColor); + } + + if (json.contains("tableView")) { + const auto o = json["tableView"].toObject(); + auto &tbv = p.tableViewParams; + tbv.alternateBackgroundColor = colorFromJson(o, "alternateBackgroundColor", tbv.alternateBackgroundColor); + tbv.backgroundColor = colorFromJson(o, "backgroundColor", tbv.backgroundColor); + tbv.headerBackgroundColor = colorFromJson(o, "headerBackgroundColor", tbv.headerBackgroundColor); + tbv.headerBorderColor = colorFromJson(o, "headerBorderColor", tbv.headerBorderColor); + tbv.headerGradientColor = colorFromJson(o, "headerGradientColor", tbv.headerGradientColor); + tbv.itemBorderBottomColor = colorFromJson(o, "itemBorderBottomColor", tbv.itemBorderBottomColor); + tbv.itemBorderTopColor = colorFromJson(o, "itemBorderTopColor", tbv.itemBorderTopColor); + tbv.itemBorderBottomWidth = o["itemBorderBottomWidth"].toInt(tbv.itemBorderBottomWidth); + tbv.itemBorderTopWidth = o["itemBorderTopWidth"].toInt(tbv.itemBorderTopWidth); + tbv.itemTextColor = colorFromJson(o, "itemTextColor", tbv.itemTextColor); + tbv.selectedColor = colorFromJson(o, "selectedColor", tbv.selectedColor); + tbv.selectedTextColor = colorFromJson(o, "selectedTextColor", tbv.selectedTextColor); + tbv.headerTextColor = colorFromJson(o, "headerTextColor", tbv.headerTextColor); + tbv.starRatingColor = colorFromJson(o, "starRatingColor", tbv.starRatingColor); + tbv.starRatingSelectedColor = colorFromJson(o, "starRatingSelectedColor", tbv.starRatingSelectedColor); + } + + if (json.contains("qmlView")) { + const auto o = json["qmlView"].toObject(); + auto &qv = p.qmlViewParams; + qv.backgroundColor = colorFromJson(o, "backgroundColor", qv.backgroundColor); + qv.cellColor = colorFromJson(o, "cellColor", qv.cellColor); + qv.cellColorWithBackground = colorFromJson(o, "cellColorWithBackground", qv.cellColorWithBackground); + qv.selectedColor = colorFromJson(o, "selectedColor", qv.selectedColor); + qv.selectedBorderColor = colorFromJson(o, "selectedBorderColor", qv.selectedBorderColor); + qv.borderColor = colorFromJson(o, "borderColor", qv.borderColor); + qv.titleColor = colorFromJson(o, "titleColor", qv.titleColor); + qv.textColor = colorFromJson(o, "textColor", qv.textColor); + if (o.contains("showDropShadow")) + qv.showDropShadow = o["showDropShadow"].toBool(qv.showDropShadow); + qv.infoBackgroundColor = colorFromJson(o, "infoBackgroundColor", qv.infoBackgroundColor); + qv.infoBorderColor = colorFromJson(o, "infoBorderColor", qv.infoBorderColor); + qv.infoShadowColor = colorFromJson(o, "infoShadowColor", qv.infoShadowColor); + qv.infoTextColor = colorFromJson(o, "infoTextColor", qv.infoTextColor); + qv.infoTitleColor = colorFromJson(o, "infoTitleColor", qv.infoTitleColor); + qv.ratingUnselectedColor = colorFromJson(o, "ratingUnselectedColor", qv.ratingUnselectedColor); + qv.ratingSelectedColor = colorFromJson(o, "ratingSelectedColor", qv.ratingSelectedColor); + qv.favUncheckedColor = colorFromJson(o, "favUncheckedColor", qv.favUncheckedColor); + qv.favCheckedColor = colorFromJson(o, "favCheckedColor", qv.favCheckedColor); + qv.readTickUncheckedColor = colorFromJson(o, "readTickUncheckedColor", qv.readTickUncheckedColor); + qv.readTickCheckedColor = colorFromJson(o, "readTickCheckedColor", qv.readTickCheckedColor); + qv.currentComicBackgroundColor = colorFromJson(o, "currentComicBackgroundColor", qv.currentComicBackgroundColor); + qv.continueReadingBackgroundColor = colorFromJson(o, "continueReadingBackgroundColor", qv.continueReadingBackgroundColor); + qv.continueReadingColor = colorFromJson(o, "continueReadingColor", qv.continueReadingColor); + qv.backgroundBlurOverlayColor = colorFromJson(o, "backgroundBlurOverlayColor", qv.backgroundBlurOverlayColor); + } + + if (json.contains("comicsViewToolbar")) { + const auto o = json["comicsViewToolbar"].toObject(); + auto &cvt = p.comicsViewToolbarParams; + cvt.backgroundColor = colorFromJson(o, "backgroundColor", cvt.backgroundColor); + cvt.separatorColor = colorFromJson(o, "separatorColor", cvt.separatorColor); + cvt.checkedBackgroundColor = colorFromJson(o, "checkedBackgroundColor", cvt.checkedBackgroundColor); + cvt.iconColor = colorFromJson(o, "iconColor", cvt.iconColor); + } + + if (json.contains("searchLineEdit")) { + const auto o = json["searchLineEdit"].toObject(); + auto &sle = p.searchLineEditParams; + sle.textColor = colorFromJson(o, "textColor", sle.textColor); + sle.backgroundColor = colorFromJson(o, "backgroundColor", sle.backgroundColor); + sle.iconColor = colorFromJson(o, "iconColor", sle.iconColor); + } + + if (json.contains("readingListIcons")) { + const auto o = json["readingListIcons"].toObject(); + auto &rli = p.readingListIconsParams; + if (o.contains("labelColors")) { + const auto lc = o["labelColors"].toObject(); + for (auto it = lc.constBegin(); it != lc.constEnd(); ++it) { + QColor c(it.value().toString()); + if (c.isValid()) + rli.labelColors[it.key()] = c; + } + } + rli.labelShadowColor = colorFromJson(o, "labelShadowColor", rli.labelShadowColor); + rli.labelShadowSelectedColor = colorFromJson(o, "labelShadowSelectedColor", rli.labelShadowSelectedColor); + rli.readingListMainColor = colorFromJson(o, "readingListMainColor", rli.readingListMainColor); + rli.readingListMainSelectedColor = colorFromJson(o, "readingListMainSelectedColor", rli.readingListMainSelectedColor); + rli.favoritesMainColor = colorFromJson(o, "favoritesMainColor", rli.favoritesMainColor); + rli.favoritesMainSelectedColor = colorFromJson(o, "favoritesMainSelectedColor", rli.favoritesMainSelectedColor); + rli.currentlyReadingMainColor = colorFromJson(o, "currentlyReadingMainColor", rli.currentlyReadingMainColor); + rli.currentlyReadingMainSelectedColor = colorFromJson(o, "currentlyReadingMainSelectedColor", rli.currentlyReadingMainSelectedColor); + rli.currentlyReadingOuterColor = colorFromJson(o, "currentlyReadingOuterColor", rli.currentlyReadingOuterColor); + rli.currentlyReadingOuterSelectedColor = colorFromJson(o, "currentlyReadingOuterSelectedColor", rli.currentlyReadingOuterSelectedColor); + rli.specialListShadowColor = colorFromJson(o, "specialListShadowColor", rli.specialListShadowColor); + rli.specialListShadowSelectedColor = colorFromJson(o, "specialListShadowSelectedColor", rli.specialListShadowSelectedColor); + rli.listMainColor = colorFromJson(o, "listMainColor", rli.listMainColor); + rli.listMainSelectedColor = colorFromJson(o, "listMainSelectedColor", rli.listMainSelectedColor); + rli.listShadowColor = colorFromJson(o, "listShadowColor", rli.listShadowColor); + rli.listShadowSelectedColor = colorFromJson(o, "listShadowSelectedColor", rli.listShadowSelectedColor); + rli.listDetailColor = colorFromJson(o, "listDetailColor", rli.listDetailColor); + rli.listDetailSelectedColor = colorFromJson(o, "listDetailSelectedColor", rli.listDetailSelectedColor); + } + + if (json.contains("dialogIcons")) { + const auto o = json["dialogIcons"].toObject(); + p.dialogIconsParams.iconColor = colorFromJson(o, "iconColor", p.dialogIconsParams.iconColor); + } + + if (json.contains("menuIcons")) { + const auto o = json["menuIcons"].toObject(); + p.menuIconsParams.iconColor = colorFromJson(o, "iconColor", p.menuIconsParams.iconColor); + } + + if (json.contains("shortcutsIcons")) { + const auto o = json["shortcutsIcons"].toObject(); + p.shortcutsIconsParams.iconColor = colorFromJson(o, "iconColor", p.shortcutsIconsParams.iconColor); + } + + if (json.contains("meta")) { + const auto o = json["meta"].toObject(); + p.meta.id = o["id"].toString(p.meta.id); + p.meta.displayName = o["displayName"].toString(p.meta.displayName); + const QString variantStr = o["variant"].toString(); + if (variantStr == "light") + p.meta.variant = ThemeVariant::Light; + else if (variantStr == "dark") + p.meta.variant = ThemeVariant::Dark; + } + + Theme theme = makeTheme(p); + theme.sourceJson = json; + return theme; } diff --git a/YACReaderLibrary/themes/theme_factory.h b/YACReaderLibrary/themes/theme_factory.h index 72cb4ca2..ebed9bbb 100644 --- a/YACReaderLibrary/themes/theme_factory.h +++ b/YACReaderLibrary/themes/theme_factory.h @@ -2,8 +2,9 @@ #define THEME_FACTORY_H #include "theme.h" -#include "theme_id.h" -Theme makeTheme(ThemeId themeId); +#include + +Theme makeTheme(const QJsonObject &json); #endif // THEME_FACTORY_H diff --git a/YACReaderLibrary/themes/themes.qrc b/YACReaderLibrary/themes/themes.qrc new file mode 100644 index 00000000..62ec21fe --- /dev/null +++ b/YACReaderLibrary/themes/themes.qrc @@ -0,0 +1,7 @@ + + + builtin_classic.json + builtin_light.json + builtin_dark.json + + diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index c754f552..ae0c1639 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -111,17 +111,27 @@ add_library(common_gui STATIC # themes infrastructure (does NOT depend on app-specific theme.h) themes/icon_utils.h themes/icon_utils.cpp - themes/theme_id.h + themes/appearance_configuration.h + themes/appearance_configuration.cpp + themes/theme_variant.h themes/themable.h themes/yacreader_icon.h themes/shared/help_about_dialog_theme.h themes/shared/whats_new_dialog_theme.h + themes/theme_editor_dialog.h + themes/theme_editor_dialog.cpp + themes/theme_meta.h + themes/theme_repository.h + themes/theme_repository.cpp + themes/appearance_tab_widget.h + themes/appearance_tab_widget.cpp ) target_include_directories(common_gui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/themes ${CMAKE_CURRENT_SOURCE_DIR}/themes/shared ) + target_link_libraries(common_gui PUBLIC Qt::Core Qt::Core5Compat diff --git a/common/themes/appearance_config_images.qrc b/common/themes/appearance_config_images.qrc new file mode 100644 index 00000000..c274e563 --- /dev/null +++ b/common/themes/appearance_config_images.qrc @@ -0,0 +1,7 @@ + + + ../../images/appearance_config/theme-mode-system.svg + ../../images/appearance_config/theme-mode-light.svg + ../../images/appearance_config/theme-mode-dark.svg + + diff --git a/common/themes/appearance_configuration.cpp b/common/themes/appearance_configuration.cpp new file mode 100644 index 00000000..dade4c26 --- /dev/null +++ b/common/themes/appearance_configuration.cpp @@ -0,0 +1,96 @@ +#include "appearance_configuration.h" + +#include + +static constexpr auto kGroup = "Appearance"; +static constexpr auto kMode = "ThemeMode"; +static constexpr auto kLightId = "LightThemeId"; +static constexpr auto kDarkId = "DarkThemeId"; +static constexpr auto kFixedId = "FixedThemeId"; + +static QString themeModeToString(ThemeMode mode) +{ + switch (mode) { + case ThemeMode::FollowSystem: + return "FollowSystem"; + case ThemeMode::Light: + return "Light"; + case ThemeMode::Dark: + return "Dark"; + case ThemeMode::ForcedTheme: + return "ForcedTheme"; + } + return "FollowSystem"; +} + +static ThemeMode themeModeFromString(const QString &s) +{ + if (s == "Light") + return ThemeMode::Light; + if (s == "Dark") + return ThemeMode::Dark; + if (s == "ForcedTheme") + return ThemeMode::ForcedTheme; + return ThemeMode::FollowSystem; +} + +AppearanceConfiguration::AppearanceConfiguration(const QString &settingsFilePath, QObject *parent) + : QObject(parent), path(settingsFilePath) +{ + load(); +} + +void AppearanceConfiguration::load() +{ + QSettings s(path, QSettings::IniFormat); + s.beginGroup(kGroup); + sel.mode = themeModeFromString(s.value(kMode, "FollowSystem").toString()); + sel.lightThemeId = s.value(kLightId, sel.lightThemeId).toString(); + sel.darkThemeId = s.value(kDarkId, sel.darkThemeId).toString(); + sel.fixedThemeId = s.value(kFixedId, sel.fixedThemeId).toString(); + s.endGroup(); +} + +void AppearanceConfiguration::write(const QString &key, const QString &value) +{ + QSettings s(path, QSettings::IniFormat); + s.beginGroup(kGroup); + s.setValue(key, value); + s.endGroup(); +} + +void AppearanceConfiguration::setMode(ThemeMode mode) +{ + if (sel.mode == mode) + return; + sel.mode = mode; + write(kMode, themeModeToString(mode)); + emit selectionChanged(); +} + +void AppearanceConfiguration::setLightThemeId(const QString &id) +{ + if (sel.lightThemeId == id) + return; + sel.lightThemeId = id; + write(kLightId, id); + emit selectionChanged(); +} + +void AppearanceConfiguration::setDarkThemeId(const QString &id) +{ + if (sel.darkThemeId == id) + return; + sel.darkThemeId = id; + write(kDarkId, id); + emit selectionChanged(); +} + +void AppearanceConfiguration::setFixedThemeId(const QString &id) +{ + if (sel.fixedThemeId == id) + return; + sel.fixedThemeId = id; + write(kFixedId, id); + emit selectionChanged(); +} diff --git a/common/themes/appearance_configuration.h b/common/themes/appearance_configuration.h new file mode 100644 index 00000000..bcc4d501 --- /dev/null +++ b/common/themes/appearance_configuration.h @@ -0,0 +1,48 @@ +#ifndef APPEARANCE_CONFIGURATION_H +#define APPEARANCE_CONFIGURATION_H + +#include +#include + +enum class ThemeMode { + FollowSystem, + Light, + Dark, + ForcedTheme, +}; + +struct ThemeSelection { + ThemeMode mode = ThemeMode::FollowSystem; + QString lightThemeId = "builtin/light"; + QString darkThemeId = "builtin/dark"; + QString fixedThemeId = "builtin/classic"; +}; + +// Persists theme selection settings to a QSettings INI file under the +// [Appearance] group. All access is on-demand (no persistent QSettings handle) +// so the caller does not need to manage a QSettings lifetime. +class AppearanceConfiguration : public QObject +{ + Q_OBJECT +public: + explicit AppearanceConfiguration(const QString &settingsFilePath, QObject *parent = nullptr); + + ThemeSelection selection() const { return sel; } + + void setMode(ThemeMode mode); + void setLightThemeId(const QString &id); + void setDarkThemeId(const QString &id); + void setFixedThemeId(const QString &id); + +signals: + void selectionChanged(); + +private: + QString path; + ThemeSelection sel; + + void load(); + void write(const QString &key, const QString &value); +}; + +#endif // APPEARANCE_CONFIGURATION_H diff --git a/common/themes/appearance_tab_widget.cpp b/common/themes/appearance_tab_widget.cpp new file mode 100644 index 00000000..8563fb05 --- /dev/null +++ b/common/themes/appearance_tab_widget.cpp @@ -0,0 +1,98 @@ +#include "appearance_tab_widget.h" + +#include "appearance_configuration.h" +#include "theme_editor_dialog.h" + +#include +#include +#include +#include +#include +#include +#include + +AppearanceTabWidget::AppearanceTabWidget( + AppearanceConfiguration *config, + std::function currentThemeJson, + std::function applyTheme, + QWidget *parent) + : QWidget(parent), config(config), currentThemeJson(std::move(currentThemeJson)), applyTheme(std::move(applyTheme)) +{ + // Color scheme selector + auto *modeBox = new QGroupBox(tr("Color scheme"), this); + auto *modeLayout = new QHBoxLayout(); + + auto *sysBtn = new QToolButton(); + auto *lightBtn = new QToolButton(); + auto *darkBtn = new QToolButton(); + + sysBtn->setText(tr("System")); + lightBtn->setText(tr("Light")); + darkBtn->setText(tr("Dark")); + + sysBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-system.svg")); + lightBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-light.svg")); + darkBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-dark.svg")); + + for (auto *btn : { sysBtn, lightBtn, darkBtn }) { + btn->setCheckable(true); + btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + btn->setIconSize(QSize(93, 58)); + btn->setMinimumSize(115, 90); + } + + auto *modeGroup = new QButtonGroup(this); + modeGroup->addButton(sysBtn, static_cast(ThemeMode::FollowSystem)); + modeGroup->addButton(lightBtn, static_cast(ThemeMode::Light)); + modeGroup->addButton(darkBtn, static_cast(ThemeMode::Dark)); + modeGroup->setExclusive(true); + + if (this->config) { + const auto mode = this->config->selection().mode; + if (auto *btn = modeGroup->button(static_cast(mode))) + btn->setChecked(true); + } + + connect(modeGroup, &QButtonGroup::idClicked, this, [this](int id) { + if (this->config) + this->config->setMode(static_cast(id)); + }); + + modeLayout->addStretch(); + modeLayout->addWidget(sysBtn); + modeLayout->addWidget(lightBtn); + modeLayout->addWidget(darkBtn); + modeLayout->addStretch(); + modeBox->setLayout(modeLayout); + + // Theme editor + auto *themeEditorBox = new QGroupBox(tr("Theme editor"), this); + auto *themeEditorLayout = new QVBoxLayout(); + auto *openBtn = new QPushButton(tr("Open Theme Editor...")); + themeEditorLayout->addWidget(openBtn); + themeEditorBox->setLayout(themeEditorLayout); + + connect(openBtn, &QPushButton::clicked, this, [this]() { + if (!themeEditor) { + QJsonObject json = this->currentThemeJson(); + if (json.isEmpty()) { + QMessageBox::critical(this, + tr("Theme editor error"), + tr("The current theme JSON could not be loaded.")); + return; + } + themeEditor = new ThemeEditorDialog(json, this); + themeEditor->setAttribute(Qt::WA_DeleteOnClose); + connect(themeEditor, &ThemeEditorDialog::themeJsonChanged, this, + [this](const QJsonObject &json) { this->applyTheme(json); }); + } + themeEditor->show(); + themeEditor->raise(); + themeEditor->activateWindow(); + }); + + auto *layout = new QVBoxLayout(this); + layout->addWidget(modeBox); + layout->addWidget(themeEditorBox); + layout->addStretch(); +} diff --git a/common/themes/appearance_tab_widget.h b/common/themes/appearance_tab_widget.h new file mode 100644 index 00000000..cbccb88b --- /dev/null +++ b/common/themes/appearance_tab_widget.h @@ -0,0 +1,29 @@ +#ifndef APPEARANCE_TAB_WIDGET_H +#define APPEARANCE_TAB_WIDGET_H + +#include +#include +#include +#include + +class AppearanceConfiguration; +class ThemeEditorDialog; + +class AppearanceTabWidget : public QWidget +{ + Q_OBJECT +public: + explicit AppearanceTabWidget( + AppearanceConfiguration *config, + std::function currentThemeJson, + std::function applyTheme, + QWidget *parent = nullptr); + +private: + AppearanceConfiguration *config; + std::function currentThemeJson; + std::function applyTheme; + QPointer themeEditor; +}; + +#endif // APPEARANCE_TAB_WIDGET_H diff --git a/common/themes/theme_editor_dialog.cpp b/common/themes/theme_editor_dialog.cpp new file mode 100644 index 00000000..eaeed515 --- /dev/null +++ b/common/themes/theme_editor_dialog.cpp @@ -0,0 +1,477 @@ +#include "theme_editor_dialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Role used to store the JSON path (QStringList) on each leaf item. +static const int PathRole = Qt::UserRole; +// Role used to distinguish color items from others. +static const int IsColorRole = Qt::UserRole + 1; +// Role used to distinguish boolean items. +static const int IsBoolRole = Qt::UserRole + 2; +// Role used to distinguish numeric items. +static const int IsNumberRole = Qt::UserRole + 3; + +static bool isColorString(const QString &s) +{ + // Accepts #RGB, #RRGGBB, #AARRGGBB + if (!s.startsWith('#')) + return false; + const int len = s.length(); + return len == 4 || len == 7 || len == 9; +} + +ThemeEditorDialog::ThemeEditorDialog(const QJsonObject ¶ms, QWidget *parent) + : QDialog(parent), params(params) +{ + setWindowTitle(tr("Theme Editor")); + resize(520, 700); + + // --- top toolbar --- + auto *expandBtn = new QPushButton(tr("+"), this); + auto *collapseBtn = new QPushButton(tr("-"), this); + auto *identifyBtn = new QPushButton(tr("i"), this); + expandBtn->setFixedWidth(28); + collapseBtn->setFixedWidth(28); + identifyBtn->setFixedWidth(28); + expandBtn->setToolTip(tr("Expand all")); + collapseBtn->setToolTip(tr("Collapse all")); + identifyBtn->setToolTip(tr("Hold to flash the selected value in the UI (magenta / toggled / 0↔10). Releases restore the original.")); + // NoFocus so clicking the button doesn't steal the tree's current item + identifyBtn->setFocusPolicy(Qt::NoFocus); + + searchEdit = new QLineEdit(this); + searchEdit->setPlaceholderText(tr("Search…")); + searchEdit->setClearButtonEnabled(true); + + auto *toolbar = new QHBoxLayout(); + toolbar->addWidget(expandBtn); + toolbar->addWidget(collapseBtn); + toolbar->addWidget(identifyBtn); + toolbar->addStretch(); + toolbar->addWidget(searchEdit); + + connect(identifyBtn, &QPushButton::pressed, this, &ThemeEditorDialog::identifyPressed); + connect(identifyBtn, &QPushButton::released, this, &ThemeEditorDialog::identifyReleased); + + // --- meta section --- + idLabel = new QLabel(this); + idLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + nameEdit = new QLineEdit(this); + variantCombo = new QComboBox(this); + variantCombo->addItem(tr("Light"), "light"); + variantCombo->addItem(tr("Dark"), "dark"); + + auto *metaForm = new QFormLayout(); + metaForm->addRow(tr("ID:"), idLabel); + metaForm->addRow(tr("Display name:"), nameEdit); + metaForm->addRow(tr("Variant:"), variantCombo); + + auto *metaBox = new QGroupBox(tr("Theme info"), this); + metaBox->setLayout(metaForm); + + syncMetaFromParams(); + + connect(nameEdit, &QLineEdit::textEdited, this, [this](const QString &text) { + auto meta = this->params["meta"].toObject(); + meta["displayName"] = text; + this->params["meta"] = meta; + emit themeJsonChanged(this->params); + }); + connect(variantCombo, &QComboBox::currentIndexChanged, this, [this](int index) { + auto meta = this->params["meta"].toObject(); + meta["variant"] = variantCombo->itemData(index).toString(); + this->params["meta"] = meta; + emit themeJsonChanged(this->params); + }); + + // --- tree --- + tree = new QTreeWidget(this); + tree->setColumnCount(2); + tree->setHeaderLabels({ tr("Parameter"), tr("Value") }); + tree->header()->setSectionResizeMode(0, QHeaderView::Stretch); + tree->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); + tree->setRootIsDecorated(true); + tree->setUniformRowHeights(true); + tree->setAlternatingRowColors(true); + + populate(nullptr, params, {}); + tree->expandAll(); + + connect(expandBtn, &QPushButton::clicked, tree, &QTreeWidget::expandAll); + connect(collapseBtn, &QPushButton::clicked, tree, &QTreeWidget::collapseAll); + connect(searchEdit, &QLineEdit::textChanged, this, &ThemeEditorDialog::filterTree); + + connect(tree, &QTreeWidget::itemDoubleClicked, this, [this](QTreeWidgetItem *item, int) { + if (item->data(0, IsColorRole).toBool()) + editColorItem(item); + else if (item->data(0, IsBoolRole).toBool()) + toggleBoolItem(item); + else if (item->data(0, IsNumberRole).toBool()) + editNumberItem(item); + }); + + // --- bottom buttons --- + auto *saveBtn = new QPushButton(tr("Save to file..."), this); + auto *loadBtn = new QPushButton(tr("Load from file..."), this); + auto *closeBtn = new QPushButton(tr("Close"), this); + connect(saveBtn, &QPushButton::clicked, this, &ThemeEditorDialog::saveToFile); + connect(loadBtn, &QPushButton::clicked, this, &ThemeEditorDialog::loadFromFile); + connect(closeBtn, &QPushButton::clicked, this, &QDialog::close); + auto *buttons = new QHBoxLayout(); + buttons->addWidget(saveBtn); + buttons->addWidget(loadBtn); + buttons->addStretch(); + buttons->addWidget(closeBtn); + + auto *layout = new QVBoxLayout(this); + layout->addLayout(toolbar); + layout->addWidget(metaBox); + layout->addWidget(tree); + layout->addLayout(buttons); + + setLayout(layout); +} + +void ThemeEditorDialog::populate(QTreeWidgetItem *parent, const QJsonObject &obj, const QStringList &path) +{ + for (auto it = obj.constBegin(); it != obj.constEnd(); ++it) { + const QString key = it.key(); + + // "meta" is handled by the dedicated UI above the tree + if (path.isEmpty() && key == "meta") + continue; + const QJsonValue val = it.value(); + const QStringList childPath = path + QStringList(key); + + if (val.isObject()) { + // Group row + QTreeWidgetItem *group = parent ? new QTreeWidgetItem(parent) + : new QTreeWidgetItem(tree); + QFont bold = group->font(0); + bold.setBold(true); + group->setFont(0, bold); + group->setText(0, key); + group->setFlags(group->flags() & ~Qt::ItemIsSelectable); + populate(group, val.toObject(), childPath); + } else { + // Leaf row + QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) + : new QTreeWidgetItem(tree); + item->setText(0, key); + item->setData(0, PathRole, childPath); + + const QString strVal = val.toString(); + if (val.isString() && isColorString(strVal)) { + const QColor color(strVal); + item->setIcon(1, colorIcon(color)); + item->setText(1, strVal); + item->setData(0, IsColorRole, true); + item->setToolTip(1, tr("Double-click to edit color")); + } else if (val.isBool()) { + item->setText(1, val.toBool() ? tr("true") : tr("false")); + item->setData(0, IsColorRole, false); + item->setData(0, IsBoolRole, true); + item->setToolTip(1, tr("Double-click to toggle")); + } else if (val.isDouble()) { + item->setText(1, QString::number(val.toDouble())); + item->setData(0, IsNumberRole, true); + item->setToolTip(1, tr("Double-click to edit value")); + } else { + item->setText(1, strVal); + item->setData(0, IsColorRole, false); + } + } + } +} + +void ThemeEditorDialog::editColorItem(QTreeWidgetItem *item) +{ + const QColor current(item->text(1)); + QColorDialog dialog(current, this); + dialog.setOption(QColorDialog::ShowAlphaChannel, true); + dialog.setWindowTitle(tr("Edit: %1").arg(item->text(0))); + + // Live update as user drags the picker + connect(&dialog, &QColorDialog::currentColorChanged, this, [this, item](const QColor &color) { + applyColorToItem(item, color); + emit themeJsonChanged(params); + }); + + if (dialog.exec() == QDialog::Accepted) { + applyColorToItem(item, dialog.selectedColor()); + } else { + // Revert to original if cancelled + applyColorToItem(item, current); + } + emit themeJsonChanged(params); +} + +void ThemeEditorDialog::applyColorToItem(QTreeWidgetItem *item, const QColor &color) +{ + const QString hexStr = color.alpha() < 255 + ? color.name(QColor::HexArgb) + : color.name(QColor::HexRgb); + item->setText(1, hexStr); + item->setIcon(1, colorIcon(color)); + + const QStringList path = item->data(0, PathRole).toStringList(); + setJsonPath(params, path, hexStr); +} + +void ThemeEditorDialog::toggleBoolItem(QTreeWidgetItem *item) +{ + const bool newValue = item->text(1) != tr("true"); + item->setText(1, newValue ? tr("true") : tr("false")); + const QStringList path = item->data(0, PathRole).toStringList(); + setJsonPath(params, path, newValue); + emit themeJsonChanged(params); +} + +void ThemeEditorDialog::editNumberItem(QTreeWidgetItem *item) +{ + const double current = item->text(1).toDouble(); + // Use integer dialog when the stored value has no fractional part + const bool isInt = (current == std::floor(current)); + bool ok = false; + double newValue; + if (isInt) { + const int result = QInputDialog::getInt( + this, tr("Edit: %1").arg(item->text(0)), item->text(0), + static_cast(current), INT_MIN, INT_MAX, 1, &ok); + newValue = result; + } else { + newValue = QInputDialog::getDouble( + this, tr("Edit: %1").arg(item->text(0)), item->text(0), + current, -1e9, 1e9, 4, &ok); + } + if (!ok) + return; + item->setText(1, isInt ? QString::number(static_cast(newValue)) : QString::number(newValue)); + const QStringList path = item->data(0, PathRole).toStringList(); + setJsonPath(params, path, newValue); + emit themeJsonChanged(params); +} + +// Returns true if the item or any of its descendants should be visible. +static bool applyFilter(QTreeWidgetItem *item, const QString &query) +{ + if (query.isEmpty()) { + item->setHidden(false); + for (int i = 0; i < item->childCount(); ++i) + applyFilter(item->child(i), query); + return true; + } + + const bool selfMatch = item->text(0).contains(query, Qt::CaseInsensitive); + + if (item->childCount() == 0) { + // Leaf: match on key name or value text + const bool match = selfMatch || item->text(1).contains(query, Qt::CaseInsensitive); + item->setHidden(!match); + return match; + } + + // Group: if the group name itself matches, show all children + bool anyChildVisible = false; + for (int i = 0; i < item->childCount(); ++i) { + if (selfMatch) { + item->child(i)->setHidden(false); + anyChildVisible = true; + } else { + if (applyFilter(item->child(i), query)) + anyChildVisible = true; + } + } + item->setHidden(!anyChildVisible); + return anyChildVisible; +} + +void ThemeEditorDialog::filterTree(const QString &query) +{ + for (int i = 0; i < tree->topLevelItemCount(); ++i) + applyFilter(tree->topLevelItem(i), query); + + // Keep visible results expanded so they're reachable + if (!query.isEmpty()) + tree->expandAll(); +} + +QIcon ThemeEditorDialog::colorIcon(const QColor &color) +{ + const int size = qApp->style()->pixelMetric(QStyle::PM_SmallIconSize); + QPixmap pix(size, size); + pix.fill(color); + return QIcon(pix); +} + +void ThemeEditorDialog::setJsonPath(QJsonObject &root, const QStringList &path, const QJsonValue &value) +{ + if (path.isEmpty()) + return; + if (path.size() == 1) { + root[path[0]] = value; + return; + } + QJsonObject sub = root[path[0]].toObject(); + setJsonPath(sub, path.mid(1), value); + root[path[0]] = sub; +} + +void ThemeEditorDialog::syncMetaToParams() +{ + auto meta = params["meta"].toObject(); + meta["displayName"] = nameEdit->text(); + meta["variant"] = variantCombo->currentData().toString(); + params["meta"] = meta; +} + +void ThemeEditorDialog::syncMetaFromParams() +{ + const auto meta = params["meta"].toObject(); + idLabel->setText(meta["id"].toString()); + nameEdit->setText(meta["displayName"].toString()); + const QString variant = meta["variant"].toString("dark"); + variantCombo->setCurrentIndex(variant == "light" ? 0 : 1); +} + +void ThemeEditorDialog::saveToFile() +{ + // Assign a user-scoped UUID if the current id is builtin or empty + auto meta = params["meta"].toObject(); + const QString currentId = meta["id"].toString(); + if (currentId.isEmpty() || currentId.startsWith("builtin/")) { + const QString newId = "user/" + QUuid::createUuid().toString(QUuid::WithoutBraces); + meta["id"] = newId; + params["meta"] = meta; + idLabel->setText(newId); + } + + const QString path = QFileDialog::getSaveFileName( + this, tr("Save theme"), QString(), tr("JSON files (*.json);;All files (*)")); + if (path.isEmpty()) + return; + + QFile file(path); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::warning(this, tr("Save failed"), tr("Could not open file for writing:\n%1").arg(path)); + return; + } + file.write(QJsonDocument(params).toJson(QJsonDocument::Indented)); +} + +void ThemeEditorDialog::loadFromFile() +{ + const QString path = QFileDialog::getOpenFileName( + this, tr("Load theme"), QString(), tr("JSON files (*.json);;All files (*)")); + if (path.isEmpty()) + return; + + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::warning(this, tr("Load failed"), tr("Could not open file:\n%1").arg(path)); + return; + } + + QJsonParseError err; + const QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err); + if (doc.isNull()) { + QMessageBox::warning(this, tr("Load failed"), tr("Invalid JSON:\n%1").arg(err.errorString())); + return; + } + if (!doc.isObject()) { + QMessageBox::warning(this, tr("Load failed"), tr("Expected a JSON object.")); + return; + } + + params = doc.object(); + syncMetaFromParams(); + tree->clear(); + populate(nullptr, params, {}); + tree->expandAll(); + emit themeJsonChanged(params); +} + +void ThemeEditorDialog::identifyPressed() +{ + QTreeWidgetItem *item = tree->currentItem(); + if (!item) + return; + + const QStringList path = item->data(0, PathRole).toStringList(); + if (path.isEmpty()) + return; // group row, not a leaf + + if (item->data(0, IsColorRole).toBool()) { + identifySnapshot = QJsonValue(item->text(1)); + identifyItem = item; + identifyPath = path; + applyColorToItem(item, QColor(0xFA00FA)); + } else if (item->data(0, IsBoolRole).toBool()) { + const bool current = (item->text(1) == tr("true")); + identifySnapshot = QJsonValue(current); + identifyItem = item; + identifyPath = path; + const bool flipped = !current; + item->setText(1, flipped ? tr("true") : tr("false")); + setJsonPath(params, path, flipped); + } else if (item->data(0, IsNumberRole).toBool()) { + const double current = item->text(1).toDouble(); + identifySnapshot = QJsonValue(current); + identifyItem = item; + identifyPath = path; + const bool isInt = (current == std::floor(current)); + const double highlight = (current > 0.0) ? 0.0 : 10.0; + item->setText(1, isInt ? QString::number(static_cast(highlight)) : QString::number(highlight)); + setJsonPath(params, path, highlight); + } else { + return; // non-editable leaf (plain string), nothing to flash + } + emit themeJsonChanged(params); +} + +void ThemeEditorDialog::identifyReleased() +{ + if (!identifyItem) + return; + + QTreeWidgetItem *item = identifyItem; + const QStringList path = identifyPath; + identifyItem = nullptr; + identifyPath.clear(); + + if (item->data(0, IsColorRole).toBool()) { + applyColorToItem(item, QColor(identifySnapshot.toString())); + } else if (item->data(0, IsBoolRole).toBool()) { + const bool restored = identifySnapshot.toBool(); + item->setText(1, restored ? tr("true") : tr("false")); + setJsonPath(params, path, restored); + } else if (item->data(0, IsNumberRole).toBool()) { + const double restored = identifySnapshot.toDouble(); + const bool isInt = (restored == std::floor(restored)); + item->setText(1, isInt ? QString::number(static_cast(restored)) : QString::number(restored)); + setJsonPath(params, path, restored); + } + identifySnapshot = QJsonValue(); + emit themeJsonChanged(params); +} diff --git a/common/themes/theme_editor_dialog.h b/common/themes/theme_editor_dialog.h new file mode 100644 index 00000000..a2f5a5e2 --- /dev/null +++ b/common/themes/theme_editor_dialog.h @@ -0,0 +1,63 @@ +#ifndef THEME_EDITOR_DIALOG_H +#define THEME_EDITOR_DIALOG_H + +#include +#include + +class QComboBox; +class QLabel; +class QLineEdit; +class QTreeWidget; +class QTreeWidgetItem; + +// Generic theme parameter editor. +// Works entirely on QJsonObject — has no knowledge of app-specific ThemeParams. +// Connect to themeJsonChanged to receive live updates as the user edits colors. +class ThemeEditorDialog : public QDialog +{ + Q_OBJECT +public: + explicit ThemeEditorDialog(const QJsonObject ¶ms, QWidget *parent = nullptr); + + QJsonObject currentParams() const { return params; } + +signals: + void themeJsonChanged(const QJsonObject ¶ms); + +private: + void populate(QTreeWidgetItem *parent, const QJsonObject &obj, const QStringList &path); + void editColorItem(QTreeWidgetItem *item); + void applyColorToItem(QTreeWidgetItem *item, const QColor &color); + void toggleBoolItem(QTreeWidgetItem *item); + void editNumberItem(QTreeWidgetItem *item); + void filterTree(const QString &query); + void saveToFile(); + void loadFromFile(); + + // Identify feature: hold the (i) button to temporarily flash the UI element + // that uses the current item's value. The original value is restored on release. + void identifyPressed(); + void identifyReleased(); + + static QIcon colorIcon(const QColor &color); + static void setJsonPath(QJsonObject &root, const QStringList &path, const QJsonValue &value); + + QTreeWidget *tree; + QLineEdit *searchEdit; + QJsonObject params; + + // Meta UI + QLabel *idLabel; + QLineEdit *nameEdit; + QComboBox *variantCombo; + + void syncMetaToParams(); + void syncMetaFromParams(); + + // Identify state (null item = inactive) + QTreeWidgetItem *identifyItem = nullptr; + QStringList identifyPath; + QJsonValue identifySnapshot; // original value saved on press, restored on release +}; + +#endif // THEME_EDITOR_DIALOG_H diff --git a/common/themes/theme_id.h b/common/themes/theme_id.h deleted file mode 100644 index f42c3069..00000000 --- a/common/themes/theme_id.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef THEME_ID_H -#define THEME_ID_H - -enum class ThemeId { - Classic, - Light, - Dark, -}; - -#endif // THEME_ID_H diff --git a/common/themes/theme_manager.cpp b/common/themes/theme_manager.cpp index 094000c2..589b201e 100644 --- a/common/themes/theme_manager.cpp +++ b/common/themes/theme_manager.cpp @@ -1,14 +1,13 @@ #include "theme_manager.h" +#include "appearance_configuration.h" #include "theme.h" #include "theme_factory.h" +#include "theme_repository.h" #include -#include #include -// TODO: add API to force color scheme //styleHints->setColorScheme(Qt::ColorScheme::Dark); - ThemeManager::ThemeManager() { } @@ -19,36 +18,106 @@ ThemeManager &ThemeManager::instance() return instance; } -void ThemeManager::initialize() +void ThemeManager::initialize(AppearanceConfiguration *config, ThemeRepository *repository) { + this->config = config; + this->repository = repository; + auto *styleHints = qGuiApp->styleHints(); - auto colorScheme = styleHints->colorScheme(); + // Re-resolve when OS color scheme changes (relevant for FollowSystem mode) + connect(styleHints, &QStyleHints::colorSchemeChanged, this, &ThemeManager::resolveTheme, Qt::QueuedConnection); - // TODO: settings are needed to decide what theme to use - auto applyColorScheme = [this](Qt::ColorScheme scheme) { - setTheme(scheme == Qt::ColorScheme::Dark ? ThemeId::Dark : ThemeId::Light); - }; + // Re-resolve when the user changes any theme setting + connect(config, &AppearanceConfiguration::selectionChanged, this, &ThemeManager::resolveTheme); - applyColorScheme(colorScheme); - - connect(styleHints, &QStyleHints::colorSchemeChanged, this, applyColorScheme, Qt::QueuedConnection); + resolveTheme(); } -void ThemeManager::setTheme(ThemeId themeId) +void ThemeManager::setTheme(const Theme &theme) { - if (this->themeId == themeId) { - return; - } - - this->themeId = themeId; - - updateCurrentTheme(); - + currentTheme = theme; emit themeChanged(); } -void ThemeManager::updateCurrentTheme() +Theme ThemeManager::themeFromId(const QString &id, ThemeVariant fallbackVariant) { - currentTheme = makeTheme(themeId); + // Try the repository first (handles both builtin and user themes via JSON) + if (repository && repository->contains(id)) { + QJsonObject json = repository->loadThemeJson(id); + if (!json.isEmpty()) + return makeTheme(json); + } + + // Fallback to the builtin that matches the current dark/light intent. + const QString fallbackId = (fallbackVariant == ThemeVariant::Dark) + ? QStringLiteral("builtin/dark") + : QStringLiteral("builtin/light"); + if (repository && repository->contains(fallbackId)) { + QJsonObject json = repository->loadThemeJson(fallbackId); + if (!json.isEmpty()) + return makeTheme(json); + } + + return {}; +} + +void ThemeManager::resolveTheme() +{ + if (!config) + return; + + const auto &sel = config->selection(); + + QString id; + ThemeVariant fallbackVariant; + switch (sel.mode) { + case ThemeMode::FollowSystem: { + const bool isDark = (qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark); + id = isDark ? sel.darkThemeId : sel.lightThemeId; + fallbackVariant = isDark ? ThemeVariant::Dark : ThemeVariant::Light; + break; + } + case ThemeMode::Light: + id = sel.lightThemeId; + fallbackVariant = ThemeVariant::Light; + break; + case ThemeMode::Dark: + id = sel.darkThemeId; + fallbackVariant = ThemeVariant::Dark; + break; + case ThemeMode::ForcedTheme: + id = sel.fixedThemeId; + fallbackVariant = (qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark) + ? ThemeVariant::Dark + : ThemeVariant::Light; + break; + } + + const Theme theme = themeFromId(id, fallbackVariant); + + // Sync Qt's application-level color scheme so native widgets (menus, scrollbars, + // standard dialogs) use the correct palette before themeChanged() is emitted. +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + Qt::ColorScheme scheme; + switch (sel.mode) { + case ThemeMode::FollowSystem: + scheme = Qt::ColorScheme::Unknown; // delegate to OS + break; + case ThemeMode::Light: + scheme = Qt::ColorScheme::Light; + break; + case ThemeMode::Dark: + scheme = Qt::ColorScheme::Dark; + break; + case ThemeMode::ForcedTheme: + scheme = (theme.meta.variant == ThemeVariant::Dark) + ? Qt::ColorScheme::Dark + : Qt::ColorScheme::Light; + break; + } + qGuiApp->styleHints()->setColorScheme(scheme); +#endif + + setTheme(theme); } diff --git a/common/themes/theme_manager.h b/common/themes/theme_manager.h index 8bac2dad..42b8d0d0 100644 --- a/common/themes/theme_manager.h +++ b/common/themes/theme_manager.h @@ -1,11 +1,13 @@ #ifndef THEME_MANAGER_H #define THEME_MANAGER_H +#include "appearance_configuration.h" #include "theme.h" -#include "theme_id.h" #include +class ThemeRepository; + class ThemeManager : public QObject { Q_OBJECT @@ -17,21 +19,27 @@ public: ThemeManager(ThemeManager &&) = delete; ThemeManager &operator=(ThemeManager &&) = delete; - void initialize(); - - void setTheme(ThemeId themeId); + void initialize(AppearanceConfiguration *config, ThemeRepository *repository); + void setTheme(const Theme &theme); const Theme &getCurrentTheme() const { return currentTheme; } + AppearanceConfiguration *getAppearanceConfiguration() const { return config; } + signals: void themeChanged(); private: explicit ThemeManager(); - ThemeId themeId = ThemeId::Classic; + + AppearanceConfiguration *config = nullptr; + ThemeRepository *repository = nullptr; Theme currentTheme; - void updateCurrentTheme(); + Theme themeFromId(const QString &id, ThemeVariant fallbackVariant); + +private slots: + void resolveTheme(); }; #endif // THEME_MANAGER_H diff --git a/common/themes/theme_meta.h b/common/themes/theme_meta.h new file mode 100644 index 00000000..e3b9c6d8 --- /dev/null +++ b/common/themes/theme_meta.h @@ -0,0 +1,14 @@ +#ifndef THEME_META_H +#define THEME_META_H + +#include "theme_variant.h" + +#include + +struct ThemeMeta { + QString id; + QString displayName; + ThemeVariant variant; +}; + +#endif // THEME_META_H diff --git a/common/themes/theme_repository.cpp b/common/themes/theme_repository.cpp new file mode 100644 index 00000000..3290cd63 --- /dev/null +++ b/common/themes/theme_repository.cpp @@ -0,0 +1,206 @@ +#include "theme_repository.h" + +#include +#include +#include +#include +#include + +ThemeRepository::ThemeRepository(const QString &qrcPrefix, const QString &userThemesDir) + : qrcPrefix(qrcPrefix), userThemesDir(userThemesDir) +{ + scanBuiltins(); + scanUserThemes(); +} + +QList ThemeRepository::availableThemes() const +{ + QList result; + result.reserve(builtins.size() + userThemes.size()); + + for (const auto &b : builtins) + result.append({ b.meta.id, b.meta.displayName, b.meta.variant, true }); + + for (const auto &u : userThemes) + result.append({ u.meta.id, u.meta.displayName, u.meta.variant, false }); + + return result; +} + +bool ThemeRepository::contains(const QString &themeId) const +{ + for (const auto &b : builtins) + if (b.id == themeId) + return true; + + for (const auto &u : userThemes) + if (u.id == themeId) + return true; + + return false; +} + +QJsonObject ThemeRepository::loadThemeJson(const QString &themeId) const +{ + for (const auto &b : builtins) + if (b.id == themeId) + return readJsonFile(b.resourcePath); + + for (const auto &u : userThemes) + if (u.id == themeId) + return readJsonFile(u.filePath); + + return {}; +} + +QString ThemeRepository::saveUserTheme(QJsonObject themeJson) +{ + QDir().mkpath(userThemesDir); + + auto metaObj = themeJson["meta"].toObject(); + QString id = metaObj["id"].toString(); + + if (id.isEmpty() || id.startsWith("builtin/")) { + const QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); + id = "user/" + uuid; + metaObj["id"] = id; + themeJson["meta"] = metaObj; + } + + // Extract uuid from "user/" + const QString uuid = id.mid(5); // skip "user/" + const QString filePath = filePathForUserTheme(uuid); + + QFile file(filePath); + if (file.open(QIODevice::WriteOnly)) { + file.write(QJsonDocument(themeJson).toJson(QJsonDocument::Indented)); + file.close(); + } + + // Update cache + refresh(); + + return id; +} + +bool ThemeRepository::deleteUserTheme(const QString &themeId) +{ + if (themeId.startsWith("builtin/")) + return false; + + for (const auto &u : userThemes) { + if (u.id == themeId) { + const bool removed = QFile::remove(u.filePath); + if (removed) + refresh(); + return removed; + } + } + + return false; +} + +QString ThemeRepository::importThemeFromFile(const QString &filePath) +{ + QJsonObject json = readJsonFile(filePath); + if (json.isEmpty()) + return {}; + + // Force a new user id regardless of what the file contains + auto metaObj = json["meta"].toObject(); + const QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); + const QString id = "user/" + uuid; + metaObj["id"] = id; + json["meta"] = metaObj; + + return saveUserTheme(json); +} + +void ThemeRepository::refresh() +{ + scanUserThemes(); +} + +// --- Private helpers --- + +void ThemeRepository::scanBuiltins() +{ + builtins.clear(); + + static const QStringList builtinNames = { "classic", "light", "dark" }; + + for (const auto &name : builtinNames) { + const QString resourcePath = qrcPrefix + "/builtin_" + name + ".json"; + const QJsonObject json = readJsonFile(resourcePath); + if (json.isEmpty()) + continue; + + BuiltinEntry entry; + entry.id = "builtin/" + name; + entry.resourcePath = resourcePath; + entry.meta = extractMeta(json); + // Ensure the id matches the canonical form + entry.meta.id = entry.id; + builtins.append(entry); + } +} + +void ThemeRepository::scanUserThemes() +{ + userThemes.clear(); + + QDir dir(userThemesDir); + if (!dir.exists()) + return; + + const auto entries = dir.entryList({ "*.json" }, QDir::Files); + for (const auto &fileName : entries) { + const QString filePath = dir.absoluteFilePath(fileName); + const QJsonObject json = readJsonFile(filePath); + if (json.isEmpty()) + continue; + + ThemeMeta meta = extractMeta(json); + if (meta.id.isEmpty()) { + // Derive id from filename (strip .json extension) + const QString baseName = fileName.chopped(5); // remove ".json" + meta.id = "user/" + baseName; + } + + UserEntry entry; + entry.id = meta.id; + entry.filePath = filePath; + entry.meta = meta; + userThemes.append(entry); + } +} + +ThemeMeta ThemeRepository::extractMeta(const QJsonObject &json) +{ + const auto meta = json["meta"].toObject(); + return ThemeMeta { + meta["id"].toString(), + meta["displayName"].toString(), + (meta["variant"].toString() == "light") ? ThemeVariant::Light : ThemeVariant::Dark + }; +} + +QJsonObject ThemeRepository::readJsonFile(const QString &path) +{ + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return {}; + + const QByteArray data = file.readAll(); + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) + return {}; + + return doc.object(); +} + +QString ThemeRepository::filePathForUserTheme(const QString &uuid) const +{ + return userThemesDir + "/" + uuid + ".json"; +} diff --git a/common/themes/theme_repository.h b/common/themes/theme_repository.h new file mode 100644 index 00000000..e9ec4a85 --- /dev/null +++ b/common/themes/theme_repository.h @@ -0,0 +1,57 @@ +#ifndef THEME_REPOSITORY_H +#define THEME_REPOSITORY_H + +#include "theme_meta.h" + +#include +#include +#include + +struct ThemeListEntry { + QString id; + QString displayName; + ThemeVariant variant; + bool isBuiltin; +}; + +class ThemeRepository +{ +public: + explicit ThemeRepository(const QString &qrcPrefix, const QString &userThemesDir); + + QList availableThemes() const; + bool contains(const QString &themeId) const; + QJsonObject loadThemeJson(const QString &themeId) const; + + QString saveUserTheme(QJsonObject themeJson); + bool deleteUserTheme(const QString &themeId); + QString importThemeFromFile(const QString &filePath); + + void refresh(); + +private: + QString qrcPrefix; + QString userThemesDir; + + struct BuiltinEntry { + QString id; + QString resourcePath; + ThemeMeta meta; + }; + QList builtins; + + struct UserEntry { + QString id; + QString filePath; + ThemeMeta meta; + }; + QList userThemes; + + void scanBuiltins(); + void scanUserThemes(); + static ThemeMeta extractMeta(const QJsonObject &json); + static QJsonObject readJsonFile(const QString &path); + QString filePathForUserTheme(const QString &uuid) const; +}; + +#endif // THEME_REPOSITORY_H diff --git a/common/themes/theme_variant.h b/common/themes/theme_variant.h new file mode 100644 index 00000000..adff0327 --- /dev/null +++ b/common/themes/theme_variant.h @@ -0,0 +1,9 @@ +#ifndef THEME_VARIANT_H +#define THEME_VARIANT_H + +enum class ThemeVariant { + Light, + Dark, +}; + +#endif // THEME_VARIANT_H diff --git a/images/appearance_config/theme-mode-dark.svg b/images/appearance_config/theme-mode-dark.svg new file mode 100644 index 00000000..a30277b9 --- /dev/null +++ b/images/appearance_config/theme-mode-dark.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/images/appearance_config/theme-mode-light.svg b/images/appearance_config/theme-mode-light.svg new file mode 100644 index 00000000..401b54c8 --- /dev/null +++ b/images/appearance_config/theme-mode-light.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/images/appearance_config/theme-mode-system.svg b/images/appearance_config/theme-mode-system.svg new file mode 100644 index 00000000..62fc4569 --- /dev/null +++ b/images/appearance_config/theme-mode-system.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e0930d7a68c0c77ec397efc334a0e62b8cb3410e Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Mon, 2 Mar 2026 22:31:56 +0100 Subject: [PATCH 18/26] Rename YACReaderLibrary json theme sections to be more user friendly --- .../comic_vine/comic_vine_dialog.cpp | 18 +- .../comic_vine/scraper_checkbox.cpp | 4 +- .../comic_vine/scraper_lineedit.cpp | 6 +- .../comic_vine/scraper_results_paginator.cpp | 18 +- .../comic_vine/scraper_scroll_label.cpp | 6 +- .../comic_vine/scraper_tableview.cpp | 4 +- .../comic_vine/search_single_comic.cpp | 4 +- YACReaderLibrary/comic_vine/search_volume.cpp | 4 +- YACReaderLibrary/comic_vine/select_comic.cpp | 6 +- YACReaderLibrary/comic_vine/select_volume.cpp | 6 +- .../comic_vine/series_question.cpp | 8 +- .../comic_vine/sort_volume_comics.cpp | 24 +- YACReaderLibrary/comic_vine/title_header.cpp | 6 +- YACReaderLibrary/comics_view_transition.cpp | 4 +- YACReaderLibrary/db/folder_model.cpp | 4 +- YACReaderLibrary/db/reading_list_item.cpp | 2 +- YACReaderLibrary/folder_content_view.cpp | 40 +- YACReaderLibrary/grid_comics_view.cpp | 48 +- YACReaderLibrary/info_comics_view.cpp | 30 +- YACReaderLibrary/themes/builtin_classic.json | 9 +- YACReaderLibrary/themes/builtin_dark.json | 9 +- YACReaderLibrary/themes/builtin_light.json | 9 +- YACReaderLibrary/themes/theme.h | 32 +- YACReaderLibrary/themes/theme_factory.cpp | 448 +++++++++--------- custom_widgets/yacreader_table_view.cpp | 2 +- custom_widgets/yacreader_table_view.h | 4 +- custom_widgets/yacreader_treeview.cpp | 2 +- custom_widgets/yacreader_treeview.h | 2 +- 28 files changed, 372 insertions(+), 387 deletions(-) diff --git a/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp b/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp index 23d74cd3..5efab527 100644 --- a/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp +++ b/YACReaderLibrary/comic_vine/comic_vine_dialog.cpp @@ -649,16 +649,16 @@ void ComicVineDialog::launchSearchComic() void ComicVineDialog::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - setStyleSheet(comicVineTheme.dialogQSS); + setStyleSheet(metadataScraperDialogTheme.dialogQSS); - skipButton->setStyleSheet(comicVineTheme.dialogButtonsQSS); - backButton->setStyleSheet(comicVineTheme.dialogButtonsQSS); - nextButton->setStyleSheet(comicVineTheme.dialogButtonsQSS); - searchButton->setStyleSheet(comicVineTheme.dialogButtonsQSS); - closeButton->setStyleSheet(comicVineTheme.dialogButtonsQSS); + skipButton->setStyleSheet(metadataScraperDialogTheme.dialogButtonsQSS); + backButton->setStyleSheet(metadataScraperDialogTheme.dialogButtonsQSS); + nextButton->setStyleSheet(metadataScraperDialogTheme.dialogButtonsQSS); + searchButton->setStyleSheet(metadataScraperDialogTheme.dialogButtonsQSS); + closeButton->setStyleSheet(metadataScraperDialogTheme.dialogButtonsQSS); - loadingMessage->setStyleSheet(comicVineTheme.defaultLabelQSS); - busyWidget->setColor(comicVineTheme.busyIndicatorColor); + loadingMessage->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); + busyWidget->setColor(metadataScraperDialogTheme.busyIndicatorColor); } diff --git a/YACReaderLibrary/comic_vine/scraper_checkbox.cpp b/YACReaderLibrary/comic_vine/scraper_checkbox.cpp index 2aa78b9b..e15b3ac9 100644 --- a/YACReaderLibrary/comic_vine/scraper_checkbox.cpp +++ b/YACReaderLibrary/comic_vine/scraper_checkbox.cpp @@ -8,7 +8,7 @@ ScraperCheckBox::ScraperCheckBox(const QString &text, QWidget *parent) void ScraperCheckBox::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - setStyleSheet(comicVineTheme.checkBoxQSS); + setStyleSheet(metadataScraperDialogTheme.checkBoxQSS); } diff --git a/YACReaderLibrary/comic_vine/scraper_lineedit.cpp b/YACReaderLibrary/comic_vine/scraper_lineedit.cpp index fb305c05..a67c8004 100644 --- a/YACReaderLibrary/comic_vine/scraper_lineedit.cpp +++ b/YACReaderLibrary/comic_vine/scraper_lineedit.cpp @@ -20,8 +20,8 @@ void ScraperLineEdit::resizeEvent(QResizeEvent *) void ScraperLineEdit::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - titleLabel->setStyleSheet(comicVineTheme.scraperLineEditTitleLabelQSS); - setStyleSheet(comicVineTheme.scraperLineEditQSS.arg(titleLabel->sizeHint().width() + 6)); + titleLabel->setStyleSheet(metadataScraperDialogTheme.scraperLineEditTitleLabelQSS); + setStyleSheet(metadataScraperDialogTheme.scraperLineEditQSS.arg(titleLabel->sizeHint().width() + 6)); } diff --git a/YACReaderLibrary/comic_vine/scraper_results_paginator.cpp b/YACReaderLibrary/comic_vine/scraper_results_paginator.cpp index 637b7fb9..8594656f 100644 --- a/YACReaderLibrary/comic_vine/scraper_results_paginator.cpp +++ b/YACReaderLibrary/comic_vine/scraper_results_paginator.cpp @@ -63,16 +63,16 @@ void ScraperResultsPaginator::setCustomLabel(const QString &label) void ScraperResultsPaginator::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - numElements->setStyleSheet(comicVineTheme.defaultLabelQSS); - numPages->setStyleSheet(comicVineTheme.defaultLabelQSS); + numElements->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); + numPages->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); - nextPage->setStyleSheet(comicVineTheme.noBorderToolButtonQSS); - nextPage->setIconSize(comicVineTheme.nextPageIcon.size); - nextPage->setIcon(comicVineTheme.nextPageIcon.icon); + nextPage->setStyleSheet(metadataScraperDialogTheme.noBorderToolButtonQSS); + nextPage->setIconSize(metadataScraperDialogTheme.nextPageIcon.size); + nextPage->setIcon(metadataScraperDialogTheme.nextPageIcon.icon); - previousPage->setStyleSheet(comicVineTheme.noBorderToolButtonQSS); - previousPage->setIconSize(comicVineTheme.previousPageIcon.size); - previousPage->setIcon(comicVineTheme.previousPageIcon.icon); + previousPage->setStyleSheet(metadataScraperDialogTheme.noBorderToolButtonQSS); + previousPage->setIconSize(metadataScraperDialogTheme.previousPageIcon.size); + previousPage->setIcon(metadataScraperDialogTheme.previousPageIcon.icon); } diff --git a/YACReaderLibrary/comic_vine/scraper_scroll_label.cpp b/YACReaderLibrary/comic_vine/scraper_scroll_label.cpp index 314a7ac3..f9422890 100644 --- a/YACReaderLibrary/comic_vine/scraper_scroll_label.cpp +++ b/YACReaderLibrary/comic_vine/scraper_scroll_label.cpp @@ -41,8 +41,8 @@ void ScraperScrollLabel::openLink(const QString &link) void ScraperScrollLabel::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - textLabel->setStyleSheet(comicVineTheme.scraperScrollLabelTextQSS); - setStyleSheet(comicVineTheme.scraperScrollLabelScrollAreaQSS); + textLabel->setStyleSheet(metadataScraperDialogTheme.scraperScrollLabelTextQSS); + setStyleSheet(metadataScraperDialogTheme.scraperScrollLabelScrollAreaQSS); } diff --git a/YACReaderLibrary/comic_vine/scraper_tableview.cpp b/YACReaderLibrary/comic_vine/scraper_tableview.cpp index 0b528802..47efab2c 100644 --- a/YACReaderLibrary/comic_vine/scraper_tableview.cpp +++ b/YACReaderLibrary/comic_vine/scraper_tableview.cpp @@ -32,7 +32,7 @@ ScraperTableView::ScraperTableView(QWidget *parent) void ScraperTableView::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - setStyleSheet(comicVineTheme.scraperTableViewQSS); + setStyleSheet(metadataScraperDialogTheme.scraperTableViewQSS); } diff --git a/YACReaderLibrary/comic_vine/search_single_comic.cpp b/YACReaderLibrary/comic_vine/search_single_comic.cpp index edf18782..9dd7c7db 100644 --- a/YACReaderLibrary/comic_vine/search_single_comic.cpp +++ b/YACReaderLibrary/comic_vine/search_single_comic.cpp @@ -74,7 +74,7 @@ void SearchSingleComic::clean() void SearchSingleComic::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - label->setStyleSheet(comicVineTheme.defaultLabelQSS); + label->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); } diff --git a/YACReaderLibrary/comic_vine/search_volume.cpp b/YACReaderLibrary/comic_vine/search_volume.cpp index e520f02c..7a0a4cfa 100644 --- a/YACReaderLibrary/comic_vine/search_volume.cpp +++ b/YACReaderLibrary/comic_vine/search_volume.cpp @@ -49,7 +49,7 @@ QString SearchVolume::getVolumeInfo() const void SearchVolume::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - label->setStyleSheet(comicVineTheme.defaultLabelQSS); + label->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); } diff --git a/YACReaderLibrary/comic_vine/select_comic.cpp b/YACReaderLibrary/comic_vine/select_comic.cpp index aa5eb668..67dd1ac2 100644 --- a/YACReaderLibrary/comic_vine/select_comic.cpp +++ b/YACReaderLibrary/comic_vine/select_comic.cpp @@ -165,8 +165,8 @@ QString SelectComic::getSelectedComicId() void SelectComic::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - label->setStyleSheet(comicVineTheme.defaultLabelQSS); - cover->setStyleSheet(comicVineTheme.coverLabelQSS); + label->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); + cover->setStyleSheet(metadataScraperDialogTheme.coverLabelQSS); } diff --git a/YACReaderLibrary/comic_vine/select_volume.cpp b/YACReaderLibrary/comic_vine/select_volume.cpp index 2ed1656d..66e6c5ee 100644 --- a/YACReaderLibrary/comic_vine/select_volume.cpp +++ b/YACReaderLibrary/comic_vine/select_volume.cpp @@ -219,8 +219,8 @@ SelectedVolumeInfo SelectVolume::getSelectedVolumeInfo() void SelectVolume::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - label->setStyleSheet(comicVineTheme.defaultLabelQSS); - cover->setStyleSheet(comicVineTheme.coverLabelQSS); + label->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); + cover->setStyleSheet(metadataScraperDialogTheme.coverLabelQSS); } diff --git a/YACReaderLibrary/comic_vine/series_question.cpp b/YACReaderLibrary/comic_vine/series_question.cpp index caab57fe..34c53c7e 100644 --- a/YACReaderLibrary/comic_vine/series_question.cpp +++ b/YACReaderLibrary/comic_vine/series_question.cpp @@ -40,9 +40,9 @@ void SeriesQuestion::setYes(bool y) void SeriesQuestion::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - questionLabel->setStyleSheet(comicVineTheme.defaultLabelQSS); - yes->setStyleSheet(comicVineTheme.radioButtonQSS); - no->setStyleSheet(comicVineTheme.radioButtonQSS); + questionLabel->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); + yes->setStyleSheet(metadataScraperDialogTheme.radioButtonQSS); + no->setStyleSheet(metadataScraperDialogTheme.radioButtonQSS); } diff --git a/YACReaderLibrary/comic_vine/sort_volume_comics.cpp b/YACReaderLibrary/comic_vine/sort_volume_comics.cpp index d44774d4..5bb2d6c5 100644 --- a/YACReaderLibrary/comic_vine/sort_volume_comics.cpp +++ b/YACReaderLibrary/comic_vine/sort_volume_comics.cpp @@ -22,8 +22,8 @@ QWidget *ScrapperToolButton::getSeparator() { QWidget *w = new QWidget; w->setFixedWidth(1); - auto comicVineTheme = ThemeManager::instance().getCurrentTheme().comicVine; - w->setStyleSheet(comicVineTheme.scraperToolButtonSeparatorQSS); + auto metadataScraperDialogTheme = ThemeManager::instance().getCurrentTheme().metadataScraperDialog; + w->setStyleSheet(metadataScraperDialogTheme.scraperToolButtonSeparatorQSS); return w; } @@ -47,9 +47,9 @@ void ScrapperToolButton::paintEvent(QPaintEvent *e) void ScrapperToolButton::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; - setStyleSheet(comicVineTheme.scraperToolButtonQSS); - fillColor = comicVineTheme.scraperToolButtonFillColor; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; + setStyleSheet(metadataScraperDialogTheme.scraperToolButtonQSS); + fillColor = metadataScraperDialogTheme.scraperToolButtonFillColor; update(); } @@ -267,13 +267,13 @@ QList> SortVolumeComics::getMatchingInfo() void SortVolumeComics::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - label->setStyleSheet(comicVineTheme.defaultLabelQSS); - sortLabel->setStyleSheet(comicVineTheme.defaultLabelQSS); + label->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); + sortLabel->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); - moveUpButtonCL->setIconSize(comicVineTheme.rowUpIcon.size); - moveUpButtonCL->setIcon(comicVineTheme.rowUpIcon.icon); - moveDownButtonCL->setIconSize(comicVineTheme.rowDownIcon.size); - moveDownButtonCL->setIcon(comicVineTheme.rowDownIcon.icon); + moveUpButtonCL->setIconSize(metadataScraperDialogTheme.rowUpIcon.size); + moveUpButtonCL->setIcon(metadataScraperDialogTheme.rowUpIcon.icon); + moveDownButtonCL->setIconSize(metadataScraperDialogTheme.rowDownIcon.size); + moveDownButtonCL->setIcon(metadataScraperDialogTheme.rowDownIcon.icon); } diff --git a/YACReaderLibrary/comic_vine/title_header.cpp b/YACReaderLibrary/comic_vine/title_header.cpp index 06585908..8f54c5b3 100644 --- a/YACReaderLibrary/comic_vine/title_header.cpp +++ b/YACReaderLibrary/comic_vine/title_header.cpp @@ -49,8 +49,8 @@ void TitleHeader::showButtons(bool show) void TitleHeader::applyTheme(const Theme &theme) { - auto comicVineTheme = theme.comicVine; + auto metadataScraperDialogTheme = theme.metadataScraperDialog; - mainTitleLabel->setStyleSheet(comicVineTheme.titleLabelQSS); - subTitleLabel->setStyleSheet(comicVineTheme.defaultLabelQSS); + mainTitleLabel->setStyleSheet(metadataScraperDialogTheme.titleLabelQSS); + subTitleLabel->setStyleSheet(metadataScraperDialogTheme.defaultLabelQSS); } diff --git a/YACReaderLibrary/comics_view_transition.cpp b/YACReaderLibrary/comics_view_transition.cpp index 0c083d93..886292ac 100644 --- a/YACReaderLibrary/comics_view_transition.cpp +++ b/YACReaderLibrary/comics_view_transition.cpp @@ -10,12 +10,12 @@ ComicsViewTransition::ComicsViewTransition(QWidget *parent) void ComicsViewTransition::applyTheme(const Theme &theme) { - setStyleSheet(QString("QWidget {background:%1}").arg(theme.defaultContentBackgroundColor.name())); + setStyleSheet(QString("QWidget {background:%1}").arg(theme.gridAndInfoView.backgroundColor.name())); update(); } void ComicsViewTransition::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.fillRect(0, 0, width(), height(), theme.defaultContentBackgroundColor); + painter.fillRect(0, 0, width(), height(), theme.gridAndInfoView.backgroundColor); } diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index 8a71c9c2..a160ecd6 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -144,8 +144,8 @@ void FolderModel::applyTheme(const Theme &theme) folderIcon = QFileIconProvider().icon(QFileIconProvider::Folder); folderFinishedIcon = drawFinishedFolderIcon(sidebarIcons.folderReadOverlay); } else { - folderIcon = theme.treeView.folderIcon; - folderFinishedIcon = theme.treeView.folderFinishedIcon; + folderIcon = theme.navigationTree.folderIcon; + folderFinishedIcon = theme.navigationTree.folderFinishedIcon; } } diff --git a/YACReaderLibrary/db/reading_list_item.cpp b/YACReaderLibrary/db/reading_list_item.cpp index e403f2ed..0fd02f3d 100644 --- a/YACReaderLibrary/db/reading_list_item.cpp +++ b/YACReaderLibrary/db/reading_list_item.cpp @@ -153,7 +153,7 @@ QIcon ReadingListItem::getIcon() const else if (theme.sidebarIcons.useSystemFolderIcons) return QFileIconProvider().icon(QFileIconProvider::Folder); else - return theme.treeView.folderIcon; // sublist + return theme.navigationTree.folderIcon; // sublist } int ReadingListItem::childCount() const diff --git a/YACReaderLibrary/folder_content_view.cpp b/YACReaderLibrary/folder_content_view.cpp index 485032bf..28535922 100644 --- a/YACReaderLibrary/folder_content_view.cpp +++ b/YACReaderLibrary/folder_content_view.cpp @@ -263,36 +263,36 @@ void FolderContentView::droppedFiles(const QList &urls, Qt::DropAction act void FolderContentView::applyTheme(const Theme &theme) { QQmlContext *ctxt = view->rootContext(); - const auto &qv = theme.qmlView; + const auto &giv = theme.gridAndInfoView; toolbar->setStyleSheet(theme.comicsViewToolbar.toolbarQSS); // Continue reading section colors - ctxt->setContextProperty("continueReadingBackgroundColor", qv.continueReadingBackgroundColor); - ctxt->setContextProperty("continueReadingColor", qv.continueReadingColor); + ctxt->setContextProperty("continueReadingBackgroundColor", giv.continueReadingBackgroundColor); + ctxt->setContextProperty("continueReadingColor", giv.continueReadingColor); // Grid colors - ctxt->setContextProperty("backgroundColor", qv.backgroundColor); - ctxt->setContextProperty("cellColor", qv.cellColor); - ctxt->setContextProperty("selectedColor", qv.selectedColor); - ctxt->setContextProperty("selectedBorderColor", qv.selectedBorderColor); - ctxt->setContextProperty("borderColor", qv.borderColor); - ctxt->setContextProperty("titleColor", qv.titleColor); - ctxt->setContextProperty("textColor", qv.textColor); - ctxt->setContextProperty("dropShadow", QVariant(qv.showDropShadow)); + ctxt->setContextProperty("backgroundColor", giv.backgroundColor); + ctxt->setContextProperty("cellColor", giv.cellColor); + ctxt->setContextProperty("selectedColor", giv.selectedColor); + ctxt->setContextProperty("selectedBorderColor", giv.selectedBorderColor); + ctxt->setContextProperty("borderColor", giv.borderColor); + ctxt->setContextProperty("titleColor", giv.titleColor); + ctxt->setContextProperty("textColor", giv.textColor); + ctxt->setContextProperty("dropShadow", QVariant(giv.showDropShadow)); // Info panel colors - ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("infoTextColor", qv.infoTextColor); - ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); + ctxt->setContextProperty("infoBackgroundColor", giv.infoBackgroundColor); + ctxt->setContextProperty("infoTextColor", giv.infoTextColor); + ctxt->setContextProperty("infoTitleColor", giv.infoTitleColor); // Rating and favorite colors - ctxt->setContextProperty("ratingUnselectedColor", qv.ratingUnselectedColor); - ctxt->setContextProperty("ratingSelectedColor", qv.ratingSelectedColor); - ctxt->setContextProperty("favUncheckedColor", qv.favUncheckedColor); - ctxt->setContextProperty("favCheckedColor", qv.favCheckedColor); - ctxt->setContextProperty("readTickUncheckedColor", qv.readTickUncheckedColor); - ctxt->setContextProperty("readTickCheckedColor", qv.readTickCheckedColor); + ctxt->setContextProperty("ratingUnselectedColor", giv.ratingUnselectedColor); + ctxt->setContextProperty("ratingSelectedColor", giv.ratingSelectedColor); + ctxt->setContextProperty("favUncheckedColor", giv.favUncheckedColor); + ctxt->setContextProperty("favCheckedColor", giv.favCheckedColor); + ctxt->setContextProperty("readTickUncheckedColor", giv.readTickUncheckedColor); + ctxt->setContextProperty("readTickCheckedColor", giv.readTickCheckedColor); // Update zoom slider icons if (smallZoomLabel) { diff --git a/YACReaderLibrary/grid_comics_view.cpp b/YACReaderLibrary/grid_comics_view.cpp index 39b67f01..2542f85c 100644 --- a/YACReaderLibrary/grid_comics_view.cpp +++ b/YACReaderLibrary/grid_comics_view.cpp @@ -219,10 +219,10 @@ void GridComicsView::updateBackgroundConfig() } // Use theme colors for cell and selected colors - const auto &qv = theme.qmlView; - ctxt->setContextProperty("backgroundColor", useBackgroundImage ? qv.backgroundBlurOverlayColor : qv.backgroundColor); - ctxt->setContextProperty("cellColor", useBackgroundImage ? qv.cellColorWithBackground : qv.cellColor); - ctxt->setContextProperty("selectedColor", qv.selectedColor); + const auto &giv = theme.gridAndInfoView; + ctxt->setContextProperty("backgroundColor", useBackgroundImage ? giv.backgroundBlurOverlayColor : giv.backgroundColor); + ctxt->setContextProperty("cellColor", useBackgroundImage ? giv.cellColorWithBackground : giv.cellColor); + ctxt->setContextProperty("selectedColor", giv.selectedColor); } void GridComicsView::showInfo() @@ -488,34 +488,34 @@ void GridComicsView::selectedItem(int index) void GridComicsView::applyTheme(const Theme &theme) { QQmlContext *ctxt = view->rootContext(); - const auto &qv = theme.qmlView; + const auto &giv = theme.gridAndInfoView; // Grid colors - ctxt->setContextProperty("backgroundColor", qv.backgroundColor); - ctxt->setContextProperty("backgroundBlurOverlayColor", qv.backgroundBlurOverlayColor); - ctxt->setContextProperty("cellColor", qv.cellColor); - ctxt->setContextProperty("selectedColor", qv.selectedColor); - ctxt->setContextProperty("selectedBorderColor", qv.selectedBorderColor); - ctxt->setContextProperty("borderColor", qv.borderColor); - ctxt->setContextProperty("titleColor", qv.titleColor); - ctxt->setContextProperty("textColor", qv.textColor); - ctxt->setContextProperty("showDropShadow", QVariant(qv.showDropShadow)); + ctxt->setContextProperty("backgroundColor", giv.backgroundColor); + ctxt->setContextProperty("backgroundBlurOverlayColor", giv.backgroundBlurOverlayColor); + ctxt->setContextProperty("cellColor", giv.cellColor); + ctxt->setContextProperty("selectedColor", giv.selectedColor); + ctxt->setContextProperty("selectedBorderColor", giv.selectedBorderColor); + ctxt->setContextProperty("borderColor", giv.borderColor); + ctxt->setContextProperty("titleColor", giv.titleColor); + ctxt->setContextProperty("textColor", giv.textColor); + ctxt->setContextProperty("showDropShadow", QVariant(giv.showDropShadow)); // Info panel colors - ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("infoTextColor", qv.infoTextColor); - ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); + ctxt->setContextProperty("infoBackgroundColor", giv.infoBackgroundColor); + ctxt->setContextProperty("infoTextColor", giv.infoTextColor); + ctxt->setContextProperty("infoTitleColor", giv.infoTitleColor); // Rating and favorite colors - ctxt->setContextProperty("ratingUnselectedColor", qv.ratingUnselectedColor); - ctxt->setContextProperty("ratingSelectedColor", qv.ratingSelectedColor); - ctxt->setContextProperty("favUncheckedColor", qv.favUncheckedColor); - ctxt->setContextProperty("favCheckedColor", qv.favCheckedColor); - ctxt->setContextProperty("readTickUncheckedColor", qv.readTickUncheckedColor); - ctxt->setContextProperty("readTickCheckedColor", qv.readTickCheckedColor); + ctxt->setContextProperty("ratingUnselectedColor", giv.ratingUnselectedColor); + ctxt->setContextProperty("ratingSelectedColor", giv.ratingSelectedColor); + ctxt->setContextProperty("favUncheckedColor", giv.favUncheckedColor); + ctxt->setContextProperty("favCheckedColor", giv.favCheckedColor); + ctxt->setContextProperty("readTickUncheckedColor", giv.readTickUncheckedColor); + ctxt->setContextProperty("readTickCheckedColor", giv.readTickCheckedColor); // Current comic banner - ctxt->setContextProperty("currentComicBackgroundColor", qv.currentComicBackgroundColor); + ctxt->setContextProperty("currentComicBackgroundColor", giv.currentComicBackgroundColor); // Update background config to apply theme cell colors updateBackgroundConfig(); diff --git a/YACReaderLibrary/info_comics_view.cpp b/YACReaderLibrary/info_comics_view.cpp index bb58b5bf..9aba46c9 100644 --- a/YACReaderLibrary/info_comics_view.cpp +++ b/YACReaderLibrary/info_comics_view.cpp @@ -224,7 +224,7 @@ void InfoComicsView::selectedItem(int index) void InfoComicsView::applyTheme(const Theme &theme) { QQmlContext *ctxt = view->rootContext(); - const auto &qv = theme.qmlView; + const auto &giv = theme.gridAndInfoView; // Info panel colors // Cache-bust the SVG file URLs so QML's image cache doesn't serve stale @@ -235,21 +235,21 @@ void InfoComicsView::applyTheme(const Theme &theme) url.setQuery(bust); return url; }; - ctxt->setContextProperty("infoBackgroundColor", qv.infoBackgroundColor); - ctxt->setContextProperty("topShadow", svgUrl(qv.topShadow)); - ctxt->setContextProperty("infoShadow", svgUrl(qv.infoShadow)); - ctxt->setContextProperty("infoIndicator", svgUrl(qv.infoIndicator)); - ctxt->setContextProperty("infoTextColor", qv.infoTextColor); - ctxt->setContextProperty("infoTitleColor", qv.infoTitleColor); + ctxt->setContextProperty("infoBackgroundColor", giv.infoBackgroundColor); + ctxt->setContextProperty("topShadow", svgUrl(giv.topShadow)); + ctxt->setContextProperty("infoShadow", svgUrl(giv.infoShadow)); + ctxt->setContextProperty("infoIndicator", svgUrl(giv.infoIndicator)); + ctxt->setContextProperty("infoTextColor", giv.infoTextColor); + ctxt->setContextProperty("infoTitleColor", giv.infoTitleColor); // Rating and favorite colors - ctxt->setContextProperty("ratingUnselectedColor", qv.ratingUnselectedColor); - ctxt->setContextProperty("ratingSelectedColor", qv.ratingSelectedColor); - ctxt->setContextProperty("favUncheckedColor", qv.favUncheckedColor); - ctxt->setContextProperty("favCheckedColor", qv.favCheckedColor); - ctxt->setContextProperty("readTickUncheckedColor", qv.readTickUncheckedColor); - ctxt->setContextProperty("readTickCheckedColor", qv.readTickCheckedColor); + ctxt->setContextProperty("ratingUnselectedColor", giv.ratingUnselectedColor); + ctxt->setContextProperty("ratingSelectedColor", giv.ratingSelectedColor); + ctxt->setContextProperty("favUncheckedColor", giv.favUncheckedColor); + ctxt->setContextProperty("favCheckedColor", giv.favCheckedColor); + ctxt->setContextProperty("readTickUncheckedColor", giv.readTickUncheckedColor); + ctxt->setContextProperty("readTickCheckedColor", giv.readTickCheckedColor); - ctxt->setContextProperty("showDropShadow", QVariant(qv.showDropShadow)); - ctxt->setContextProperty("backgroundBlurOverlayColor", qv.backgroundBlurOverlayColor); + ctxt->setContextProperty("showDropShadow", QVariant(giv.showDropShadow)); + ctxt->setContextProperty("backgroundBlurOverlayColor", giv.backgroundBlurOverlayColor); } diff --git a/YACReaderLibrary/themes/builtin_classic.json b/YACReaderLibrary/themes/builtin_classic.json index a365fbb8..b410662d 100644 --- a/YACReaderLibrary/themes/builtin_classic.json +++ b/YACReaderLibrary/themes/builtin_classic.json @@ -4,12 +4,11 @@ "displayName": "Default Classic", "variant": "dark" }, - "defaultContentBackgroundColor": "#2a2a2a", "comicFlow": { "backgroundColor": "#000000", "textColor": "#4c4c4c" }, - "comicVine": { + "metadataScraperDialog": { "contentTextColor": "#ffffff", "contentBackgroundColor": "#2b2b2b", "contentAltBackgroundColor": "#2b2b2b", @@ -122,7 +121,7 @@ "horizontalHandleHeight": 4, "verticalHandleWidth": 4 }, - "treeView": { + "navigationTree": { "textColor": "#dddfdf", "selectionBackgroundColor": "#2e2e2e", "scrollBackgroundColor": "#404040", @@ -138,7 +137,7 @@ "folderReadOverlayColor": "#464646", "folderReadOverlaySelectedColor": "#464646" }, - "tableView": { + "comicsViewTable": { "alternateBackgroundColor": "#f2f2f2", "backgroundColor": "#fafafa", "headerBackgroundColor": "#f5f5f5", @@ -155,7 +154,7 @@ "starRatingColor": "#e9be0f", "starRatingSelectedColor": "#ffffff" }, - "qmlView": { + "gridAndInfoView": { "backgroundColor": "#2a2a2a", "cellColor": "#212121", "cellColorWithBackground": "#99212121", diff --git a/YACReaderLibrary/themes/builtin_dark.json b/YACReaderLibrary/themes/builtin_dark.json index 21855aca..1634400a 100644 --- a/YACReaderLibrary/themes/builtin_dark.json +++ b/YACReaderLibrary/themes/builtin_dark.json @@ -4,12 +4,11 @@ "displayName": "Default Dark", "variant": "dark" }, - "defaultContentBackgroundColor": "#2a2a2a", "comicFlow": { "backgroundColor": "#111111", "textColor": "#888888" }, - "comicVine": { + "metadataScraperDialog": { "contentTextColor": "#ffffff", "contentBackgroundColor": "#2b2b2b", "contentAltBackgroundColor": "#2e2e2e", @@ -122,7 +121,7 @@ "horizontalHandleHeight": 4, "verticalHandleWidth": 4 }, - "treeView": { + "navigationTree": { "textColor": "#dddfdf", "selectionBackgroundColor": "#2e2e2e", "scrollBackgroundColor": "#404040", @@ -138,7 +137,7 @@ "folderReadOverlayColor": "#222222", "folderReadOverlaySelectedColor": "#222222" }, - "tableView": { + "comicsViewTable": { "alternateBackgroundColor": "#2e2e2e", "backgroundColor": "#2a2a2a", "headerBackgroundColor": "#2a2a2a", @@ -155,7 +154,7 @@ "starRatingColor": "#e9be0f", "starRatingSelectedColor": "#ffffff" }, - "qmlView": { + "gridAndInfoView": { "backgroundColor": "#2a2a2a", "cellColor": "#212121", "cellColorWithBackground": "#99212121", diff --git a/YACReaderLibrary/themes/builtin_light.json b/YACReaderLibrary/themes/builtin_light.json index 4d9c8744..f1cf40e4 100644 --- a/YACReaderLibrary/themes/builtin_light.json +++ b/YACReaderLibrary/themes/builtin_light.json @@ -4,12 +4,11 @@ "displayName": "Default Light", "variant": "light" }, - "defaultContentBackgroundColor": "#ffffff", "comicFlow": { "backgroundColor": "#dcdcdc", "textColor": "#303030" }, - "comicVine": { + "metadataScraperDialog": { "contentTextColor": "#000000", "contentBackgroundColor": "#ececec", "contentAltBackgroundColor": "#e0e0e0", @@ -122,7 +121,7 @@ "horizontalHandleHeight": 4, "verticalHandleWidth": 4 }, - "treeView": { + "navigationTree": { "textColor": "#000000", "selectionBackgroundColor": "#333133", "scrollBackgroundColor": "#e0e0e0", @@ -138,7 +137,7 @@ "folderReadOverlayColor": "#ffffff", "folderReadOverlaySelectedColor": "#161616" }, - "tableView": { + "comicsViewTable": { "alternateBackgroundColor": "#f2f2f2", "backgroundColor": "#fafafa", "headerBackgroundColor": "#f5f5f5", @@ -155,7 +154,7 @@ "starRatingColor": "#e9be0f", "starRatingSelectedColor": "#ffffff" }, - "qmlView": { + "gridAndInfoView": { "backgroundColor": "#f6f6f6", "cellColor": "#ffffff", "cellColorWithBackground": "#99ffffff", diff --git a/YACReaderLibrary/themes/theme.h b/YACReaderLibrary/themes/theme.h index b0254429..76764508 100644 --- a/YACReaderLibrary/themes/theme.h +++ b/YACReaderLibrary/themes/theme.h @@ -9,7 +9,7 @@ #include "whats_new_dialog_theme.h" #include "theme_meta.h" -struct ComicVineThemeTemplates { +struct MetadataScraperDialogThemeTemplates { QString defaultLabelQSS = "QLabel {color:%1; font-size:12px;font-family:Arial;}"; QString titleLabelQSS = "QLabel {color:%1; font-size:18px;font-family:Arial;}"; QString coverLabelQSS = "QLabel {background-color: %1; color:%2; font-size:12px; font-family:Arial; }"; @@ -98,7 +98,7 @@ struct ComicFlowColors { QColor textColor; }; -struct TableViewThemeTemplates { +struct ComicsViewTableThemeTemplates { QString tableViewQSS = "QTableView {alternate-background-color: %1; background-color: %2; outline: 0px; border: none;}" "QTableCornerButton::section {background-color:%3; border:none; border-bottom:1px solid %4; border-right:1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %5, stop: 1 %4);}" "QTableView::item {outline: 0px; border-bottom: %12px solid %6; border-top: %13px solid %7; padding-bottom:1px; color:%8;}" @@ -107,7 +107,7 @@ struct TableViewThemeTemplates { "QHeaderView::section:vertical {border-bottom: 1px solid %6; border-top: 1px solid %7;}"; }; -struct TableViewTheme { +struct ComicsViewTableTheme { QString tableViewQSS; QColor starRatingColor; QColor starRatingSelectedColor; @@ -173,10 +173,10 @@ struct ImportWidgetTheme { QIcon coversToggleIcon; }; -struct TreeViewThemeTemplates { +struct NavigationTreeThemeTemplates { // Styled tree view template with custom scroll bars // %1 = text color, %2 = selection/hover background, %3 = scroll background, %4 = scroll handle, %5 = selected text color - QString styledTreeViewQSS = "QTreeView {background-color:transparent; border: none; color:%1; outline:0; show-decoration-selected: 0;}" + QString navigationTreeQSS = "QTreeView {background-color:transparent; border: none; color:%1; outline:0; show-decoration-selected: 0;}" "QTreeView::item:selected {background-color: %2; color:%5; font:bold;}" "QTreeView::item:hover {background-color:%2; color:%5; font:bold;}" "QTreeView::branch:selected {background-color:%2;}" @@ -193,8 +193,8 @@ struct TreeViewThemeTemplates { "QTreeView::branch:open:has-children:selected:!has-siblings,QTreeView::branch:open:has-children:selected:has-siblings {border-image: none;image: url('%9');}"; }; -struct TreeViewTheme { - QString treeViewQSS; +struct NavigationTreeTheme { + QString navigationTreeQSS; QColor folderIndicatorColor; // For incomplete folders and recently updated folders // Branch indicator icon paths (used by QSS url()) @@ -208,8 +208,8 @@ struct TreeViewTheme { QIcon folderFinishedIcon; }; -// QML view theme colors (used by GridComicsView, FolderContentView, InfoComicsView) -struct QmlViewTheme { +// Grid and info view theme colors (used by GridComicsView, FolderContentView, InfoComicsView) +struct GridAndInfoViewTheme { // Grid colors QColor backgroundColor; QColor cellColor; @@ -281,7 +281,7 @@ struct ContentSplitterTheme { struct SidebarIconsTheme { // When true, use QFileIconProvider for folder icons and overlay folderReadOverlay for finished folders - // When false, use the themed folderIcon and folderFinishedIcon from TreeViewTheme + // When false, use the themed folderIcon and folderFinishedIcon from NavigationTreeTheme bool useSystemFolderIcons; QPixmap folderReadOverlay; // Tick overlay drawn on system folder icons when useSystemFolderIcons is true @@ -420,7 +420,7 @@ struct MainToolbarTheme { QString folderNameLabelQSS; }; -struct ComicVineTheme { +struct MetadataScraperDialogTheme { QString defaultLabelQSS; QString titleLabelQSS; QString coverLabelQSS; @@ -457,10 +457,8 @@ struct Theme { ThemeMeta meta; QJsonObject sourceJson; - QColor defaultContentBackgroundColor; - ComicFlowColors comicFlow; - ComicVineTheme comicVine; + MetadataScraperDialogTheme metadataScraperDialog; HelpAboutDialogTheme helpAboutDialog; WhatsNewDialogTheme whatsNewDialog; EmptyContainerTheme emptyContainer; @@ -469,9 +467,9 @@ struct Theme { LibraryItemTheme libraryItem; ImportWidgetTheme importWidget; ServerConfigDialogTheme serverConfigDialog; - TreeViewTheme treeView; - TableViewTheme tableView; - QmlViewTheme qmlView; + NavigationTreeTheme navigationTree; + ComicsViewTableTheme comicsViewTable; + GridAndInfoViewTheme gridAndInfoView; MainToolbarTheme mainToolbar; ContentSplitterTheme contentSplitter; ComicsViewToolbarTheme comicsViewToolbar; diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index 1e0818cd..dbe90109 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -5,8 +5,8 @@ #include "icon_utils.h" #include "yacreader_global.h" -struct ComicVineParams { - ComicVineThemeTemplates t; +struct MetadataScraperDialogParams { + MetadataScraperDialogThemeTemplates t; QColor contentTextColor; QColor contentBackgroundColor; @@ -93,8 +93,8 @@ struct ImportWidgetParams { QColor iconCheckedColor; }; -struct TreeViewParams { - TreeViewThemeTemplates t; +struct NavigationTreeParams { + NavigationTreeThemeTemplates t; QColor textColor; QColor selectionBackgroundColor; @@ -116,8 +116,8 @@ struct TreeViewParams { QColor folderReadOverlaySelectedColor; // Tick/checkmark color for selected folder }; -struct TableViewParams { - TableViewThemeTemplates t; +struct ComicsViewTableParams { + ComicsViewTableThemeTemplates t; QColor alternateBackgroundColor; QColor backgroundColor; @@ -137,7 +137,7 @@ struct TableViewParams { QColor starRatingSelectedColor; }; -struct QmlViewParams { +struct GridAndInfoViewParams { // Grid colors QColor backgroundColor; QColor cellColor; @@ -301,10 +301,9 @@ struct WhatsNewDialogParams { struct ThemeParams { ThemeMeta meta; - QColor defaultContentBackgroundColor; ComicFlowColors comicFlowColors; - ComicVineParams comicVineParams; + MetadataScraperDialogParams metadataScraperDialogParams; HelpAboutDialogTheme helpAboutDialogParams; EmptyContainerParams emptyContainerParams; SidebarParams sidebarParams; @@ -314,9 +313,9 @@ struct ThemeParams { ServerConfigDialogParams serverConfigDialogParams; MainToolbarParams mainToolbarParams; ContentSplitterParams contentSplitterParams; - TreeViewParams treeViewParams; - TableViewParams tableViewParams; - QmlViewParams qmlViewParams; + NavigationTreeParams navigationTreeParams; + ComicsViewTableParams comicsViewTableParams; + GridAndInfoViewParams gridAndInfoViewParams; ComicsViewToolbarParams comicsViewToolbarParams; SearchLineEditParams searchLineEditParams; ReadingListIconsParams readingListIconsParams; @@ -330,63 +329,61 @@ Theme makeTheme(const ThemeParams ¶ms) { Theme theme; - theme.defaultContentBackgroundColor = params.defaultContentBackgroundColor; - // Comic Flow const auto &cf = params.comicFlowColors; theme.comicFlow.backgroundColor = cf.backgroundColor; theme.comicFlow.textColor = cf.textColor; - // Comic Vine - const auto &cv = params.comicVineParams; - const auto &t = cv.t; + // MetadataScraperDialog + const auto &msd = params.metadataScraperDialogParams; + const auto &t = msd.t; auto recolor = [&](const QString &path, const QColor &color) { return recoloredSvgToThemeFile(path, color, params.meta.id); }; - theme.comicVine.defaultLabelQSS = t.defaultLabelQSS.arg(cv.labelTextColor.name()); - theme.comicVine.titleLabelQSS = t.titleLabelQSS.arg(cv.labelTextColor.name()); - theme.comicVine.coverLabelQSS = t.coverLabelQSS.arg(cv.labelBackgroundColor.name(), cv.labelTextColor.name()); - theme.comicVine.radioButtonQSS = t.radioButtonQSS.arg(cv.buttonTextColor.name(), recolor(":/images/comic_vine/radioUnchecked.svg", cv.radioUncheckedColor), recoloredSvgToThemeFile(":/images/comic_vine/radioChecked.svg", cv.radioCheckedBackgroundColor, cv.radioCheckedIndicatorColor, params.meta.id)); - theme.comicVine.checkBoxQSS = t.checkBoxQSS.arg(cv.buttonTextColor.name(), cv.buttonBorderColor.name(), cv.buttonBackgroundColor.name(), recolor(":/images/comic_vine/checkBoxTick.svg", cv.checkBoxTickColor)); + theme.metadataScraperDialog.defaultLabelQSS = t.defaultLabelQSS.arg(msd.labelTextColor.name()); + theme.metadataScraperDialog.titleLabelQSS = t.titleLabelQSS.arg(msd.labelTextColor.name()); + theme.metadataScraperDialog.coverLabelQSS = t.coverLabelQSS.arg(msd.labelBackgroundColor.name(), msd.labelTextColor.name()); + theme.metadataScraperDialog.radioButtonQSS = t.radioButtonQSS.arg(msd.buttonTextColor.name(), recolor(":/images/comic_vine/radioUnchecked.svg", msd.radioUncheckedColor), recoloredSvgToThemeFile(":/images/comic_vine/radioChecked.svg", msd.radioCheckedBackgroundColor, msd.radioCheckedIndicatorColor, params.meta.id)); + theme.metadataScraperDialog.checkBoxQSS = t.checkBoxQSS.arg(msd.buttonTextColor.name(), msd.buttonBorderColor.name(), msd.buttonBackgroundColor.name(), recolor(":/images/comic_vine/checkBoxTick.svg", msd.checkBoxTickColor)); - theme.comicVine.scraperLineEditTitleLabelQSS = t.scraperLineEditTitleLabelQSS.arg(cv.contentTextColor.name()); - theme.comicVine.scraperLineEditQSS = t.scraperLineEditQSS.arg(cv.contentAltBackgroundColor.name(), cv.contentTextColor.name(), "%1"); + theme.metadataScraperDialog.scraperLineEditTitleLabelQSS = t.scraperLineEditTitleLabelQSS.arg(msd.contentTextColor.name()); + theme.metadataScraperDialog.scraperLineEditQSS = t.scraperLineEditQSS.arg(msd.contentAltBackgroundColor.name(), msd.contentTextColor.name(), "%1"); - theme.comicVine.scraperToolButtonQSS = t.scraperToolButtonQSS.arg(cv.buttonBackgroundColor.name(), cv.buttonTextColor.name(), cv.toolButtonAccentColor.name()); - theme.comicVine.scraperToolButtonSeparatorQSS = t.scraperToolButtonSeparatorQSS.arg(cv.toolButtonAccentColor.name()); - theme.comicVine.scraperToolButtonFillColor = cv.buttonBackgroundColor; + theme.metadataScraperDialog.scraperToolButtonQSS = t.scraperToolButtonQSS.arg(msd.buttonBackgroundColor.name(), msd.buttonTextColor.name(), msd.toolButtonAccentColor.name()); + theme.metadataScraperDialog.scraperToolButtonSeparatorQSS = t.scraperToolButtonSeparatorQSS.arg(msd.toolButtonAccentColor.name()); + theme.metadataScraperDialog.scraperToolButtonFillColor = msd.buttonBackgroundColor; - theme.comicVine.scraperScrollLabelTextQSS = t.scraperScrollLabelTextQSS.arg(cv.contentBackgroundColor.name(), cv.contentTextColor.name(), cv.hyperlinkColor.name()); - theme.comicVine.scraperScrollLabelScrollAreaQSS = t.scraperScrollLabelScrollAreaQSS.arg(cv.contentBackgroundColor.name(), cv.tableScrollHandleColor.name(), cv.tableScrollBackgroundColor.name()); + theme.metadataScraperDialog.scraperScrollLabelTextQSS = t.scraperScrollLabelTextQSS.arg(msd.contentBackgroundColor.name(), msd.contentTextColor.name(), msd.hyperlinkColor.name()); + theme.metadataScraperDialog.scraperScrollLabelScrollAreaQSS = t.scraperScrollLabelScrollAreaQSS.arg(msd.contentBackgroundColor.name(), msd.tableScrollHandleColor.name(), msd.tableScrollBackgroundColor.name()); - theme.comicVine.scraperTableViewQSS = t.scraperTableViewQSS - .arg(cv.tableHeaderTextColor.name(), - cv.tableAltBackgroundColor.name(), - cv.tableBackgroundColor.name(), - cv.tableSelectedColor.name(), - cv.tableHeaderBackgroundColor.name(), - cv.tableHeaderBorderColor.name(), - cv.tableHeaderTextColor.name(), - cv.tableSectionBorderDark.name(), - cv.tableSectionBorderLight.name(), - cv.tableScrollHandleColor.name(), - cv.tableScrollBackgroundColor.name(), - recolor(":/images/comic_vine/downArrow.svg", cv.downArrowColor), - recolor(":/images/comic_vine/upArrow.svg", cv.upArrowColor), - cv.tableHeaderGradientColor.name()); + theme.metadataScraperDialog.scraperTableViewQSS = t.scraperTableViewQSS + .arg(msd.tableHeaderTextColor.name(), + msd.tableAltBackgroundColor.name(), + msd.tableBackgroundColor.name(), + msd.tableSelectedColor.name(), + msd.tableHeaderBackgroundColor.name(), + msd.tableHeaderBorderColor.name(), + msd.tableHeaderTextColor.name(), + msd.tableSectionBorderDark.name(), + msd.tableSectionBorderLight.name(), + msd.tableScrollHandleColor.name(), + msd.tableScrollBackgroundColor.name(), + recolor(":/images/comic_vine/downArrow.svg", msd.downArrowColor), + recolor(":/images/comic_vine/upArrow.svg", msd.upArrowColor), + msd.tableHeaderGradientColor.name()); - theme.comicVine.dialogQSS = t.dialogQSS.arg(cv.dialogBackgroundColor.name()); - theme.comicVine.dialogButtonsQSS = t.dialogButtonsQSS.arg(cv.buttonBorderColor.name(), cv.buttonBackgroundColor.name(), cv.buttonTextColor.name()); + theme.metadataScraperDialog.dialogQSS = t.dialogQSS.arg(msd.dialogBackgroundColor.name()); + theme.metadataScraperDialog.dialogButtonsQSS = t.dialogButtonsQSS.arg(msd.buttonBorderColor.name(), msd.buttonBackgroundColor.name(), msd.buttonTextColor.name()); - theme.comicVine.busyIndicatorColor = cv.busyIndicatorColor; + theme.metadataScraperDialog.busyIndicatorColor = msd.busyIndicatorColor; - theme.comicVine.nextPageIcon = { QIcon(recolor(t.nextPageIcon, cv.navIconColor)), t.pageIconSize }; - theme.comicVine.previousPageIcon = { QIcon(recolor(t.previousPageIcon, cv.navIconColor)), t.pageIconSize }; + theme.metadataScraperDialog.nextPageIcon = { QIcon(recolor(t.nextPageIcon, msd.navIconColor)), t.pageIconSize }; + theme.metadataScraperDialog.previousPageIcon = { QIcon(recolor(t.previousPageIcon, msd.navIconColor)), t.pageIconSize }; - theme.comicVine.rowUpIcon = { QIcon(recolor(t.rowUpIcon, cv.rowIconColor)), t.rowIconSize }; - theme.comicVine.rowDownIcon = { QIcon(recolor(t.rowDownIcon, cv.rowIconColor)), t.rowIconSize }; + theme.metadataScraperDialog.rowUpIcon = { QIcon(recolor(t.rowUpIcon, msd.rowIconColor)), t.rowIconSize }; + theme.metadataScraperDialog.rowDownIcon = { QIcon(recolor(t.rowDownIcon, msd.rowIconColor)), t.rowIconSize }; // HelpAboutDialog theme.helpAboutDialog = params.helpAboutDialogParams; @@ -470,55 +467,54 @@ Theme makeTheme(const ThemeParams ¶ms) } // end ImportWidget - // TableView - const auto &tav = params.tableViewParams; - const auto &tavt = tav.t; - theme.tableView.tableViewQSS = tavt.tableViewQSS - .arg(tav.alternateBackgroundColor.name(), - tav.backgroundColor.name(), - tav.headerBackgroundColor.name(), - tav.headerBorderColor.name(), - tav.headerGradientColor.name(), - tav.itemBorderBottomColor.name(), - tav.itemBorderTopColor.name(), - tav.itemTextColor.name(), - tav.selectedColor.name(), - tav.selectedTextColor.name(), - tav.headerTextColor.name(), - QString::number(tav.itemBorderBottomWidth), - QString::number(tav.itemBorderTopWidth)); - theme.tableView.starRatingColor = tav.starRatingColor; - theme.tableView.starRatingSelectedColor = tav.starRatingSelectedColor; - // end TableView + // ComicsViewTable + const auto &cvta = params.comicsViewTableParams; + theme.comicsViewTable.tableViewQSS = cvta.t.tableViewQSS + .arg(cvta.alternateBackgroundColor.name(), + cvta.backgroundColor.name(), + cvta.headerBackgroundColor.name(), + cvta.headerBorderColor.name(), + cvta.headerGradientColor.name(), + cvta.itemBorderBottomColor.name(), + cvta.itemBorderTopColor.name(), + cvta.itemTextColor.name(), + cvta.selectedColor.name(), + cvta.selectedTextColor.name(), + cvta.headerTextColor.name(), + QString::number(cvta.itemBorderBottomWidth), + QString::number(cvta.itemBorderTopWidth)); + theme.comicsViewTable.starRatingColor = cvta.starRatingColor; + theme.comicsViewTable.starRatingSelectedColor = cvta.starRatingSelectedColor; + // end ComicsViewTable - // QmlView - const auto &qv = params.qmlViewParams; - theme.qmlView.backgroundColor = qv.backgroundColor; - theme.qmlView.cellColor = qv.cellColor; - theme.qmlView.cellColorWithBackground = qv.cellColorWithBackground; - theme.qmlView.selectedColor = qv.selectedColor; - theme.qmlView.selectedBorderColor = qv.selectedBorderColor; - theme.qmlView.borderColor = qv.borderColor; - theme.qmlView.titleColor = qv.titleColor; - theme.qmlView.textColor = qv.textColor; - theme.qmlView.showDropShadow = qv.showDropShadow; - theme.qmlView.infoBackgroundColor = qv.infoBackgroundColor; - theme.qmlView.topShadow = recoloredSvgToThemeFile(":/qml/info-top-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.meta.id); - theme.qmlView.infoShadow = recoloredSvgToThemeFile(":/qml/info-shadow.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.meta.id); - theme.qmlView.infoIndicator = recoloredSvgToThemeFile(":/qml/info-indicator.svg", qv.infoBackgroundColor, qv.infoBorderColor, qv.infoShadowColor, params.meta.id); - theme.qmlView.infoTextColor = qv.infoTextColor; - theme.qmlView.infoTitleColor = qv.infoTitleColor; - theme.qmlView.ratingUnselectedColor = qv.ratingUnselectedColor; - theme.qmlView.ratingSelectedColor = qv.ratingSelectedColor; - theme.qmlView.favUncheckedColor = qv.favUncheckedColor; - theme.qmlView.favCheckedColor = qv.favCheckedColor; - theme.qmlView.readTickUncheckedColor = qv.readTickUncheckedColor; - theme.qmlView.readTickCheckedColor = qv.readTickCheckedColor; - theme.qmlView.currentComicBackgroundColor = qv.currentComicBackgroundColor; - theme.qmlView.continueReadingBackgroundColor = qv.continueReadingBackgroundColor; - theme.qmlView.continueReadingColor = qv.continueReadingColor; - theme.qmlView.backgroundBlurOverlayColor = qv.backgroundBlurOverlayColor; - // end QmlView + // GridAndInfoView + const auto &giv = params.gridAndInfoViewParams; + theme.gridAndInfoView.backgroundColor = giv.backgroundColor; + theme.gridAndInfoView.cellColor = giv.cellColor; + theme.gridAndInfoView.cellColorWithBackground = giv.cellColorWithBackground; + theme.gridAndInfoView.selectedColor = giv.selectedColor; + theme.gridAndInfoView.selectedBorderColor = giv.selectedBorderColor; + theme.gridAndInfoView.borderColor = giv.borderColor; + theme.gridAndInfoView.titleColor = giv.titleColor; + theme.gridAndInfoView.textColor = giv.textColor; + theme.gridAndInfoView.showDropShadow = giv.showDropShadow; + theme.gridAndInfoView.infoBackgroundColor = giv.infoBackgroundColor; + theme.gridAndInfoView.topShadow = recoloredSvgToThemeFile(":/qml/info-top-shadow.svg", giv.infoBackgroundColor, giv.infoBorderColor, giv.infoShadowColor, params.meta.id); + theme.gridAndInfoView.infoShadow = recoloredSvgToThemeFile(":/qml/info-shadow.svg", giv.infoBackgroundColor, giv.infoBorderColor, giv.infoShadowColor, params.meta.id); + theme.gridAndInfoView.infoIndicator = recoloredSvgToThemeFile(":/qml/info-indicator.svg", giv.infoBackgroundColor, giv.infoBorderColor, giv.infoShadowColor, params.meta.id); + theme.gridAndInfoView.infoTextColor = giv.infoTextColor; + theme.gridAndInfoView.infoTitleColor = giv.infoTitleColor; + theme.gridAndInfoView.ratingUnselectedColor = giv.ratingUnselectedColor; + theme.gridAndInfoView.ratingSelectedColor = giv.ratingSelectedColor; + theme.gridAndInfoView.favUncheckedColor = giv.favUncheckedColor; + theme.gridAndInfoView.favCheckedColor = giv.favCheckedColor; + theme.gridAndInfoView.readTickUncheckedColor = giv.readTickUncheckedColor; + theme.gridAndInfoView.readTickCheckedColor = giv.readTickCheckedColor; + theme.gridAndInfoView.currentComicBackgroundColor = giv.currentComicBackgroundColor; + theme.gridAndInfoView.continueReadingBackgroundColor = giv.continueReadingBackgroundColor; + theme.gridAndInfoView.continueReadingColor = giv.continueReadingColor; + theme.gridAndInfoView.backgroundBlurOverlayColor = giv.backgroundBlurOverlayColor; + // end GridAndInfoView // MainToolbar const auto &mt = params.mainToolbarParams; @@ -600,7 +596,7 @@ Theme makeTheme(const ThemeParams ¶ms) // System folder icons flag and overlay theme.sidebarIcons.useSystemFolderIcons = si.useSystemFolderIcons; if (si.useSystemFolderIcons) { - const QString overlayPath = recoloredSvgToThemeFile(":/images/sidebar/folder_read_overlay.svg", params.treeViewParams.folderReadOverlayColor, params.meta.id); + const QString overlayPath = recoloredSvgToThemeFile(":/images/sidebar/folder_read_overlay.svg", params.navigationTreeParams.folderReadOverlayColor, params.meta.id); theme.sidebarIcons.folderReadOverlay = QPixmap(overlayPath); } @@ -642,43 +638,43 @@ Theme makeTheme(const ThemeParams ¶ms) theme.libraryItem.libraryOptionsIcon = QIcon(libraryOptionsPath); // end LibraryItem - // TreeView - const auto &tv = params.treeViewParams; + // NavigationTree + const auto &nt = params.navigationTreeParams; // Branch indicator icons — own colors, independent of the sidebar icon color - theme.treeView.branchClosedIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorColor, params.meta.id); - theme.treeView.branchOpenIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorColor, params.meta.id); - theme.treeView.branchClosedIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", tv.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); - theme.treeView.branchOpenIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", tv.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); + theme.navigationTree.branchClosedIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", nt.branchIndicatorColor, params.meta.id); + theme.navigationTree.branchOpenIconPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", nt.branchIndicatorColor, params.meta.id); + theme.navigationTree.branchClosedIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-closed.svg", nt.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); + theme.navigationTree.branchOpenIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", nt.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); - theme.treeView.treeViewQSS = tv.t.styledTreeViewQSS - .arg(tv.textColor.name(), - tv.selectionBackgroundColor.name(), - tv.scrollBackgroundColor.name(), - tv.scrollHandleColor.name(), - tv.selectedTextColor.name(), - theme.treeView.branchClosedIconPath, - theme.treeView.branchOpenIconPath, - theme.treeView.branchClosedIconSelectedPath, - theme.treeView.branchOpenIconSelectedPath); - theme.treeView.folderIndicatorColor = tv.folderIndicatorColor; + theme.navigationTree.navigationTreeQSS = nt.t.navigationTreeQSS + .arg(nt.textColor.name(), + nt.selectionBackgroundColor.name(), + nt.scrollBackgroundColor.name(), + nt.scrollHandleColor.name(), + nt.selectedTextColor.name(), + theme.navigationTree.branchClosedIconPath, + theme.navigationTree.branchOpenIconPath, + theme.navigationTree.branchClosedIconSelectedPath, + theme.navigationTree.branchOpenIconSelectedPath); + theme.navigationTree.folderIndicatorColor = nt.folderIndicatorColor; // Folder icon — normal and selected states with independent colors { - const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconColor, tv.folderIconShadowColor, params.meta.id); - const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, params.meta.id, { .suffix = "_selected" }); - theme.treeView.folderIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); - theme.treeView.folderIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); + const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", nt.folderIconColor, nt.folderIconShadowColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder.svg", nt.folderIconSelectedColor, nt.folderIconSelectedShadowColor, params.meta.id, { .suffix = "_selected" }); + theme.navigationTree.folderIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + theme.navigationTree.folderIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); } // Folder finished icon — same but with tick (#ff0) recolored independently for each state { - const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconColor, tv.folderIconShadowColor, tv.folderReadOverlayColor, params.meta.id); - const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", tv.folderIconSelectedColor, tv.folderIconSelectedShadowColor, tv.folderReadOverlaySelectedColor, params.meta.id, { .suffix = "_selected" }); - theme.treeView.folderFinishedIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); - theme.treeView.folderFinishedIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); + const QString normalPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", nt.folderIconColor, nt.folderIconShadowColor, nt.folderReadOverlayColor, params.meta.id); + const QString selectedPath = recoloredSvgToThemeFile(":/images/sidebar/folder_finished.svg", nt.folderIconSelectedColor, nt.folderIconSelectedShadowColor, nt.folderReadOverlaySelectedColor, params.meta.id, { .suffix = "_selected" }); + theme.navigationTree.folderFinishedIcon.addFile(normalPath, QSize(), QIcon::Normal, QIcon::Off); + theme.navigationTree.folderFinishedIcon.addFile(selectedPath, QSize(), QIcon::Selected, QIcon::Off); } - // end TreeView + // end NavigationTree // ContentSplitter const auto &cs = params.contentSplitterParams; @@ -873,53 +869,47 @@ Theme makeTheme(const QJsonObject &json) { ThemeParams p; - if (json.contains("defaultContentBackgroundColor")) { - QColor c(json["defaultContentBackgroundColor"].toString()); - if (c.isValid()) - p.defaultContentBackgroundColor = c; - } - if (json.contains("comicFlow")) { const auto o = json["comicFlow"].toObject(); p.comicFlowColors.backgroundColor = colorFromJson(o, "backgroundColor", p.comicFlowColors.backgroundColor); p.comicFlowColors.textColor = colorFromJson(o, "textColor", p.comicFlowColors.textColor); } - if (json.contains("comicVine")) { - const auto o = json["comicVine"].toObject(); - auto &cv = p.comicVineParams; - cv.contentTextColor = colorFromJson(o, "contentTextColor", cv.contentTextColor); - cv.contentBackgroundColor = colorFromJson(o, "contentBackgroundColor", cv.contentBackgroundColor); - cv.contentAltBackgroundColor = colorFromJson(o, "contentAltBackgroundColor", cv.contentAltBackgroundColor); - cv.dialogBackgroundColor = colorFromJson(o, "dialogBackgroundColor", cv.dialogBackgroundColor); - cv.tableBackgroundColor = colorFromJson(o, "tableBackgroundColor", cv.tableBackgroundColor); - cv.tableAltBackgroundColor = colorFromJson(o, "tableAltBackgroundColor", cv.tableAltBackgroundColor); - cv.tableBorderColor = colorFromJson(o, "tableBorderColor", cv.tableBorderColor); - cv.tableSelectedColor = colorFromJson(o, "tableSelectedColor", cv.tableSelectedColor); - cv.tableHeaderBackgroundColor = colorFromJson(o, "tableHeaderBackgroundColor", cv.tableHeaderBackgroundColor); - cv.tableHeaderGradientColor = colorFromJson(o, "tableHeaderGradientColor", cv.tableHeaderGradientColor); - cv.tableHeaderBorderColor = colorFromJson(o, "tableHeaderBorderColor", cv.tableHeaderBorderColor); - cv.tableHeaderTextColor = colorFromJson(o, "tableHeaderTextColor", cv.tableHeaderTextColor); - cv.tableScrollHandleColor = colorFromJson(o, "tableScrollHandleColor", cv.tableScrollHandleColor); - cv.tableScrollBackgroundColor = colorFromJson(o, "tableScrollBackgroundColor", cv.tableScrollBackgroundColor); - cv.tableSectionBorderLight = colorFromJson(o, "tableSectionBorderLight", cv.tableSectionBorderLight); - cv.tableSectionBorderDark = colorFromJson(o, "tableSectionBorderDark", cv.tableSectionBorderDark); - cv.labelTextColor = colorFromJson(o, "labelTextColor", cv.labelTextColor); - cv.labelBackgroundColor = colorFromJson(o, "labelBackgroundColor", cv.labelBackgroundColor); - cv.hyperlinkColor = colorFromJson(o, "hyperlinkColor", cv.hyperlinkColor); - cv.buttonBackgroundColor = colorFromJson(o, "buttonBackgroundColor", cv.buttonBackgroundColor); - cv.buttonTextColor = colorFromJson(o, "buttonTextColor", cv.buttonTextColor); - cv.buttonBorderColor = colorFromJson(o, "buttonBorderColor", cv.buttonBorderColor); - cv.radioUncheckedColor = colorFromJson(o, "radioUncheckedColor", cv.radioUncheckedColor); - cv.radioCheckedBackgroundColor = colorFromJson(o, "radioCheckedBackgroundColor", cv.radioCheckedBackgroundColor); - cv.radioCheckedIndicatorColor = colorFromJson(o, "radioCheckedIndicatorColor", cv.radioCheckedIndicatorColor); - cv.checkBoxTickColor = colorFromJson(o, "checkBoxTickColor", cv.checkBoxTickColor); - cv.toolButtonAccentColor = colorFromJson(o, "toolButtonAccentColor", cv.toolButtonAccentColor); - cv.downArrowColor = colorFromJson(o, "downArrowColor", cv.downArrowColor); - cv.upArrowColor = colorFromJson(o, "upArrowColor", cv.upArrowColor); - cv.busyIndicatorColor = colorFromJson(o, "busyIndicatorColor", cv.busyIndicatorColor); - cv.navIconColor = colorFromJson(o, "navIconColor", cv.navIconColor); - cv.rowIconColor = colorFromJson(o, "rowIconColor", cv.rowIconColor); + if (json.contains("metadataScraperDialog")) { + const auto o = json["metadataScraperDialog"].toObject(); + auto &msd = p.metadataScraperDialogParams; + msd.contentTextColor = colorFromJson(o, "contentTextColor", msd.contentTextColor); + msd.contentBackgroundColor = colorFromJson(o, "contentBackgroundColor", msd.contentBackgroundColor); + msd.contentAltBackgroundColor = colorFromJson(o, "contentAltBackgroundColor", msd.contentAltBackgroundColor); + msd.dialogBackgroundColor = colorFromJson(o, "dialogBackgroundColor", msd.dialogBackgroundColor); + msd.tableBackgroundColor = colorFromJson(o, "tableBackgroundColor", msd.tableBackgroundColor); + msd.tableAltBackgroundColor = colorFromJson(o, "tableAltBackgroundColor", msd.tableAltBackgroundColor); + msd.tableBorderColor = colorFromJson(o, "tableBorderColor", msd.tableBorderColor); + msd.tableSelectedColor = colorFromJson(o, "tableSelectedColor", msd.tableSelectedColor); + msd.tableHeaderBackgroundColor = colorFromJson(o, "tableHeaderBackgroundColor", msd.tableHeaderBackgroundColor); + msd.tableHeaderGradientColor = colorFromJson(o, "tableHeaderGradientColor", msd.tableHeaderGradientColor); + msd.tableHeaderBorderColor = colorFromJson(o, "tableHeaderBorderColor", msd.tableHeaderBorderColor); + msd.tableHeaderTextColor = colorFromJson(o, "tableHeaderTextColor", msd.tableHeaderTextColor); + msd.tableScrollHandleColor = colorFromJson(o, "tableScrollHandleColor", msd.tableScrollHandleColor); + msd.tableScrollBackgroundColor = colorFromJson(o, "tableScrollBackgroundColor", msd.tableScrollBackgroundColor); + msd.tableSectionBorderLight = colorFromJson(o, "tableSectionBorderLight", msd.tableSectionBorderLight); + msd.tableSectionBorderDark = colorFromJson(o, "tableSectionBorderDark", msd.tableSectionBorderDark); + msd.labelTextColor = colorFromJson(o, "labelTextColor", msd.labelTextColor); + msd.labelBackgroundColor = colorFromJson(o, "labelBackgroundColor", msd.labelBackgroundColor); + msd.hyperlinkColor = colorFromJson(o, "hyperlinkColor", msd.hyperlinkColor); + msd.buttonBackgroundColor = colorFromJson(o, "buttonBackgroundColor", msd.buttonBackgroundColor); + msd.buttonTextColor = colorFromJson(o, "buttonTextColor", msd.buttonTextColor); + msd.buttonBorderColor = colorFromJson(o, "buttonBorderColor", msd.buttonBorderColor); + msd.radioUncheckedColor = colorFromJson(o, "radioUncheckedColor", msd.radioUncheckedColor); + msd.radioCheckedBackgroundColor = colorFromJson(o, "radioCheckedBackgroundColor", msd.radioCheckedBackgroundColor); + msd.radioCheckedIndicatorColor = colorFromJson(o, "radioCheckedIndicatorColor", msd.radioCheckedIndicatorColor); + msd.checkBoxTickColor = colorFromJson(o, "checkBoxTickColor", msd.checkBoxTickColor); + msd.toolButtonAccentColor = colorFromJson(o, "toolButtonAccentColor", msd.toolButtonAccentColor); + msd.downArrowColor = colorFromJson(o, "downArrowColor", msd.downArrowColor); + msd.upArrowColor = colorFromJson(o, "upArrowColor", msd.upArrowColor); + msd.busyIndicatorColor = colorFromJson(o, "busyIndicatorColor", msd.busyIndicatorColor); + msd.navIconColor = colorFromJson(o, "navIconColor", msd.navIconColor); + msd.rowIconColor = colorFromJson(o, "rowIconColor", msd.rowIconColor); } if (json.contains("helpAboutDialog")) { @@ -1034,73 +1024,73 @@ Theme makeTheme(const QJsonObject &json) cs.verticalHandleWidth = o["verticalHandleWidth"].toInt(cs.verticalHandleWidth); } - if (json.contains("treeView")) { - const auto o = json["treeView"].toObject(); - auto &tv = p.treeViewParams; - tv.textColor = colorFromJson(o, "textColor", tv.textColor); - tv.selectionBackgroundColor = colorFromJson(o, "selectionBackgroundColor", tv.selectionBackgroundColor); - tv.scrollBackgroundColor = colorFromJson(o, "scrollBackgroundColor", tv.scrollBackgroundColor); - tv.scrollHandleColor = colorFromJson(o, "scrollHandleColor", tv.scrollHandleColor); - tv.selectedTextColor = colorFromJson(o, "selectedTextColor", tv.selectedTextColor); - tv.folderIndicatorColor = colorFromJson(o, "folderIndicatorColor", tv.folderIndicatorColor); - tv.branchIndicatorColor = colorFromJson(o, "branchIndicatorColor", tv.branchIndicatorColor); - tv.branchIndicatorSelectedColor = colorFromJson(o, "branchIndicatorSelectedColor", tv.branchIndicatorSelectedColor); - tv.folderIconColor = colorFromJson(o, "folderIconColor", tv.folderIconColor); - tv.folderIconShadowColor = colorFromJson(o, "folderIconShadowColor", tv.folderIconShadowColor); - tv.folderIconSelectedColor = colorFromJson(o, "folderIconSelectedColor", tv.folderIconSelectedColor); - tv.folderIconSelectedShadowColor = colorFromJson(o, "folderIconSelectedShadowColor", tv.folderIconSelectedShadowColor); - tv.folderReadOverlayColor = colorFromJson(o, "folderReadOverlayColor", tv.folderReadOverlayColor); - tv.folderReadOverlaySelectedColor = colorFromJson(o, "folderReadOverlaySelectedColor", tv.folderReadOverlaySelectedColor); + if (json.contains("navigationTree")) { + const auto o = json["navigationTree"].toObject(); + auto &nt = p.navigationTreeParams; + nt.textColor = colorFromJson(o, "textColor", nt.textColor); + nt.selectionBackgroundColor = colorFromJson(o, "selectionBackgroundColor", nt.selectionBackgroundColor); + nt.scrollBackgroundColor = colorFromJson(o, "scrollBackgroundColor", nt.scrollBackgroundColor); + nt.scrollHandleColor = colorFromJson(o, "scrollHandleColor", nt.scrollHandleColor); + nt.selectedTextColor = colorFromJson(o, "selectedTextColor", nt.selectedTextColor); + nt.folderIndicatorColor = colorFromJson(o, "folderIndicatorColor", nt.folderIndicatorColor); + nt.branchIndicatorColor = colorFromJson(o, "branchIndicatorColor", nt.branchIndicatorColor); + nt.branchIndicatorSelectedColor = colorFromJson(o, "branchIndicatorSelectedColor", nt.branchIndicatorSelectedColor); + nt.folderIconColor = colorFromJson(o, "folderIconColor", nt.folderIconColor); + nt.folderIconShadowColor = colorFromJson(o, "folderIconShadowColor", nt.folderIconShadowColor); + nt.folderIconSelectedColor = colorFromJson(o, "folderIconSelectedColor", nt.folderIconSelectedColor); + nt.folderIconSelectedShadowColor = colorFromJson(o, "folderIconSelectedShadowColor", nt.folderIconSelectedShadowColor); + nt.folderReadOverlayColor = colorFromJson(o, "folderReadOverlayColor", nt.folderReadOverlayColor); + nt.folderReadOverlaySelectedColor = colorFromJson(o, "folderReadOverlaySelectedColor", nt.folderReadOverlaySelectedColor); } - if (json.contains("tableView")) { - const auto o = json["tableView"].toObject(); - auto &tbv = p.tableViewParams; - tbv.alternateBackgroundColor = colorFromJson(o, "alternateBackgroundColor", tbv.alternateBackgroundColor); - tbv.backgroundColor = colorFromJson(o, "backgroundColor", tbv.backgroundColor); - tbv.headerBackgroundColor = colorFromJson(o, "headerBackgroundColor", tbv.headerBackgroundColor); - tbv.headerBorderColor = colorFromJson(o, "headerBorderColor", tbv.headerBorderColor); - tbv.headerGradientColor = colorFromJson(o, "headerGradientColor", tbv.headerGradientColor); - tbv.itemBorderBottomColor = colorFromJson(o, "itemBorderBottomColor", tbv.itemBorderBottomColor); - tbv.itemBorderTopColor = colorFromJson(o, "itemBorderTopColor", tbv.itemBorderTopColor); - tbv.itemBorderBottomWidth = o["itemBorderBottomWidth"].toInt(tbv.itemBorderBottomWidth); - tbv.itemBorderTopWidth = o["itemBorderTopWidth"].toInt(tbv.itemBorderTopWidth); - tbv.itemTextColor = colorFromJson(o, "itemTextColor", tbv.itemTextColor); - tbv.selectedColor = colorFromJson(o, "selectedColor", tbv.selectedColor); - tbv.selectedTextColor = colorFromJson(o, "selectedTextColor", tbv.selectedTextColor); - tbv.headerTextColor = colorFromJson(o, "headerTextColor", tbv.headerTextColor); - tbv.starRatingColor = colorFromJson(o, "starRatingColor", tbv.starRatingColor); - tbv.starRatingSelectedColor = colorFromJson(o, "starRatingSelectedColor", tbv.starRatingSelectedColor); + if (json.contains("comicsViewTable")) { + const auto o = json["comicsViewTable"].toObject(); + auto &cvta = p.comicsViewTableParams; + cvta.alternateBackgroundColor = colorFromJson(o, "alternateBackgroundColor", cvta.alternateBackgroundColor); + cvta.backgroundColor = colorFromJson(o, "backgroundColor", cvta.backgroundColor); + cvta.headerBackgroundColor = colorFromJson(o, "headerBackgroundColor", cvta.headerBackgroundColor); + cvta.headerBorderColor = colorFromJson(o, "headerBorderColor", cvta.headerBorderColor); + cvta.headerGradientColor = colorFromJson(o, "headerGradientColor", cvta.headerGradientColor); + cvta.itemBorderBottomColor = colorFromJson(o, "itemBorderBottomColor", cvta.itemBorderBottomColor); + cvta.itemBorderTopColor = colorFromJson(o, "itemBorderTopColor", cvta.itemBorderTopColor); + cvta.itemBorderBottomWidth = o["itemBorderBottomWidth"].toInt(cvta.itemBorderBottomWidth); + cvta.itemBorderTopWidth = o["itemBorderTopWidth"].toInt(cvta.itemBorderTopWidth); + cvta.itemTextColor = colorFromJson(o, "itemTextColor", cvta.itemTextColor); + cvta.selectedColor = colorFromJson(o, "selectedColor", cvta.selectedColor); + cvta.selectedTextColor = colorFromJson(o, "selectedTextColor", cvta.selectedTextColor); + cvta.headerTextColor = colorFromJson(o, "headerTextColor", cvta.headerTextColor); + cvta.starRatingColor = colorFromJson(o, "starRatingColor", cvta.starRatingColor); + cvta.starRatingSelectedColor = colorFromJson(o, "starRatingSelectedColor", cvta.starRatingSelectedColor); } - if (json.contains("qmlView")) { - const auto o = json["qmlView"].toObject(); - auto &qv = p.qmlViewParams; - qv.backgroundColor = colorFromJson(o, "backgroundColor", qv.backgroundColor); - qv.cellColor = colorFromJson(o, "cellColor", qv.cellColor); - qv.cellColorWithBackground = colorFromJson(o, "cellColorWithBackground", qv.cellColorWithBackground); - qv.selectedColor = colorFromJson(o, "selectedColor", qv.selectedColor); - qv.selectedBorderColor = colorFromJson(o, "selectedBorderColor", qv.selectedBorderColor); - qv.borderColor = colorFromJson(o, "borderColor", qv.borderColor); - qv.titleColor = colorFromJson(o, "titleColor", qv.titleColor); - qv.textColor = colorFromJson(o, "textColor", qv.textColor); + if (json.contains("gridAndInfoView")) { + const auto o = json["gridAndInfoView"].toObject(); + auto &giv = p.gridAndInfoViewParams; + giv.backgroundColor = colorFromJson(o, "backgroundColor", giv.backgroundColor); + giv.cellColor = colorFromJson(o, "cellColor", giv.cellColor); + giv.cellColorWithBackground = colorFromJson(o, "cellColorWithBackground", giv.cellColorWithBackground); + giv.selectedColor = colorFromJson(o, "selectedColor", giv.selectedColor); + giv.selectedBorderColor = colorFromJson(o, "selectedBorderColor", giv.selectedBorderColor); + giv.borderColor = colorFromJson(o, "borderColor", giv.borderColor); + giv.titleColor = colorFromJson(o, "titleColor", giv.titleColor); + giv.textColor = colorFromJson(o, "textColor", giv.textColor); if (o.contains("showDropShadow")) - qv.showDropShadow = o["showDropShadow"].toBool(qv.showDropShadow); - qv.infoBackgroundColor = colorFromJson(o, "infoBackgroundColor", qv.infoBackgroundColor); - qv.infoBorderColor = colorFromJson(o, "infoBorderColor", qv.infoBorderColor); - qv.infoShadowColor = colorFromJson(o, "infoShadowColor", qv.infoShadowColor); - qv.infoTextColor = colorFromJson(o, "infoTextColor", qv.infoTextColor); - qv.infoTitleColor = colorFromJson(o, "infoTitleColor", qv.infoTitleColor); - qv.ratingUnselectedColor = colorFromJson(o, "ratingUnselectedColor", qv.ratingUnselectedColor); - qv.ratingSelectedColor = colorFromJson(o, "ratingSelectedColor", qv.ratingSelectedColor); - qv.favUncheckedColor = colorFromJson(o, "favUncheckedColor", qv.favUncheckedColor); - qv.favCheckedColor = colorFromJson(o, "favCheckedColor", qv.favCheckedColor); - qv.readTickUncheckedColor = colorFromJson(o, "readTickUncheckedColor", qv.readTickUncheckedColor); - qv.readTickCheckedColor = colorFromJson(o, "readTickCheckedColor", qv.readTickCheckedColor); - qv.currentComicBackgroundColor = colorFromJson(o, "currentComicBackgroundColor", qv.currentComicBackgroundColor); - qv.continueReadingBackgroundColor = colorFromJson(o, "continueReadingBackgroundColor", qv.continueReadingBackgroundColor); - qv.continueReadingColor = colorFromJson(o, "continueReadingColor", qv.continueReadingColor); - qv.backgroundBlurOverlayColor = colorFromJson(o, "backgroundBlurOverlayColor", qv.backgroundBlurOverlayColor); + giv.showDropShadow = o["showDropShadow"].toBool(giv.showDropShadow); + giv.infoBackgroundColor = colorFromJson(o, "infoBackgroundColor", giv.infoBackgroundColor); + giv.infoBorderColor = colorFromJson(o, "infoBorderColor", giv.infoBorderColor); + giv.infoShadowColor = colorFromJson(o, "infoShadowColor", giv.infoShadowColor); + giv.infoTextColor = colorFromJson(o, "infoTextColor", giv.infoTextColor); + giv.infoTitleColor = colorFromJson(o, "infoTitleColor", giv.infoTitleColor); + giv.ratingUnselectedColor = colorFromJson(o, "ratingUnselectedColor", giv.ratingUnselectedColor); + giv.ratingSelectedColor = colorFromJson(o, "ratingSelectedColor", giv.ratingSelectedColor); + giv.favUncheckedColor = colorFromJson(o, "favUncheckedColor", giv.favUncheckedColor); + giv.favCheckedColor = colorFromJson(o, "favCheckedColor", giv.favCheckedColor); + giv.readTickUncheckedColor = colorFromJson(o, "readTickUncheckedColor", giv.readTickUncheckedColor); + giv.readTickCheckedColor = colorFromJson(o, "readTickCheckedColor", giv.readTickCheckedColor); + giv.currentComicBackgroundColor = colorFromJson(o, "currentComicBackgroundColor", giv.currentComicBackgroundColor); + giv.continueReadingBackgroundColor = colorFromJson(o, "continueReadingBackgroundColor", giv.continueReadingBackgroundColor); + giv.continueReadingColor = colorFromJson(o, "continueReadingColor", giv.continueReadingColor); + giv.backgroundBlurOverlayColor = colorFromJson(o, "backgroundBlurOverlayColor", giv.backgroundBlurOverlayColor); } if (json.contains("comicsViewToolbar")) { diff --git a/custom_widgets/yacreader_table_view.cpp b/custom_widgets/yacreader_table_view.cpp index 85c6ccba..1075f9dd 100644 --- a/custom_widgets/yacreader_table_view.cpp +++ b/custom_widgets/yacreader_table_view.cpp @@ -56,7 +56,7 @@ YACReaderTableView::YACReaderTableView(QWidget *parent) void YACReaderTableView::applyTheme(const Theme &theme) { - setStyleSheet(theme.tableView.tableViewQSS); + setStyleSheet(theme.comicsViewTable.tableViewQSS); } void YACReaderTableView::mouseMoveEvent(QMouseEvent *event) diff --git a/custom_widgets/yacreader_table_view.h b/custom_widgets/yacreader_table_view.h index 7c17e34f..f455854a 100644 --- a/custom_widgets/yacreader_table_view.h +++ b/custom_widgets/yacreader_table_view.h @@ -13,8 +13,8 @@ class YACReaderTableView : public QTableView, protected Themable Q_OBJECT public: explicit YACReaderTableView(QWidget *parent = 0); - QColor starRatingColor() const { return theme.tableView.starRatingColor; } - QColor starRatingSelectedColor() const { return theme.tableView.starRatingSelectedColor; } + QColor starRatingColor() const { return theme.comicsViewTable.starRatingColor; } + QColor starRatingSelectedColor() const { return theme.comicsViewTable.starRatingSelectedColor; } protected: void applyTheme(const Theme &theme) override; diff --git a/custom_widgets/yacreader_treeview.cpp b/custom_widgets/yacreader_treeview.cpp index 4a07424e..c2699bd4 100644 --- a/custom_widgets/yacreader_treeview.cpp +++ b/custom_widgets/yacreader_treeview.cpp @@ -21,7 +21,7 @@ YACReaderTreeView::YACReaderTreeView(QWidget *parent) void YACReaderTreeView::applyTheme(const Theme &theme) { - setStyleSheet(theme.treeView.treeViewQSS); + setStyleSheet(theme.navigationTree.navigationTreeQSS); } void YACReaderTreeView::mousePressEvent(QMouseEvent *event) diff --git a/custom_widgets/yacreader_treeview.h b/custom_widgets/yacreader_treeview.h index 78b0154f..bf8e43f1 100644 --- a/custom_widgets/yacreader_treeview.h +++ b/custom_widgets/yacreader_treeview.h @@ -10,7 +10,7 @@ class YACReaderTreeView : public QTreeView, protected Themable Q_OBJECT public: explicit YACReaderTreeView(QWidget *parent = 0); - QColor folderIndicatorColor() const { return theme.treeView.folderIndicatorColor; } + QColor folderIndicatorColor() const { return theme.navigationTree.folderIndicatorColor; } private: void mousePressEvent(QMouseEvent *event) override; From 2d669870453884ae3e675d502d3f25b56b13adbd Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Mon, 2 Mar 2026 22:44:08 +0100 Subject: [PATCH 19/26] Make json keys display as human readable strings in the theme editor --- common/themes/theme_editor_dialog.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/common/themes/theme_editor_dialog.cpp b/common/themes/theme_editor_dialog.cpp index eaeed515..4f4ef7d4 100644 --- a/common/themes/theme_editor_dialog.cpp +++ b/common/themes/theme_editor_dialog.cpp @@ -32,6 +32,24 @@ static const int IsBoolRole = Qt::UserRole + 2; // Role used to distinguish numeric items. static const int IsNumberRole = Qt::UserRole + 3; +// Converts a camelCase JSON key to a human-readable display string. +// "metadataScraperDialog" → "Metadata scraper dialog" +// "navigationTreeQSS" → "Navigation tree qss" +// Consecutive uppercase letters (acronyms) are kept together as one word. +static QString displayKey(const QString &key) +{ + QString result; + for (int i = 0; i < key.size(); ++i) { + const bool isUpper = key[i].isUpper(); + const bool prevIsLower = (i > 0) && key[i - 1].isLower(); + const bool nextIsLower = (i + 1 < key.size()) && key[i + 1].isLower(); + if (i > 0 && isUpper && (prevIsLower || nextIsLower)) + result += ' '; + result += result.isEmpty() ? key[i].toUpper() : key[i].toLower(); + } + return result; +} + static bool isColorString(const QString &s) { // Accepts #RGB, #RRGGBB, #AARRGGBB @@ -171,14 +189,14 @@ void ThemeEditorDialog::populate(QTreeWidgetItem *parent, const QJsonObject &obj QFont bold = group->font(0); bold.setBold(true); group->setFont(0, bold); - group->setText(0, key); + group->setText(0, displayKey(key)); group->setFlags(group->flags() & ~Qt::ItemIsSelectable); populate(group, val.toObject(), childPath); } else { // Leaf row QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(tree); - item->setText(0, key); + item->setText(0, displayKey(key)); item->setData(0, PathRole, childPath); const QString strVal = val.toString(); From ad28216f5024a292b4eab23bdd4a8dc6fe6a2e05 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Tue, 3 Mar 2026 22:13:39 +0100 Subject: [PATCH 20/26] Fix qrc prefix --- common/themes/appearance_config_images.qrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/themes/appearance_config_images.qrc b/common/themes/appearance_config_images.qrc index c274e563..3284bda9 100644 --- a/common/themes/appearance_config_images.qrc +++ b/common/themes/appearance_config_images.qrc @@ -1,5 +1,5 @@ - + ../../images/appearance_config/theme-mode-system.svg ../../images/appearance_config/theme-mode-light.svg ../../images/appearance_config/theme-mode-dark.svg From 3799c0633d1fda249c81828b12b58067bd3255a5 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Tue, 3 Mar 2026 22:43:23 +0100 Subject: [PATCH 21/26] Reformat json theme files so the content is sorted alphabetically allowing easy tracking of changes through git --- YACReader/themes/builtin_classic.json | 62 +-- YACReader/themes/builtin_dark.json | 62 +-- YACReader/themes/builtin_light.json | 62 +-- YACReaderLibrary/themes/builtin_classic.json | 394 +++++++++---------- YACReaderLibrary/themes/builtin_dark.json | 390 +++++++++--------- YACReaderLibrary/themes/builtin_light.json | 392 +++++++++--------- 6 files changed, 681 insertions(+), 681 deletions(-) diff --git a/YACReader/themes/builtin_classic.json b/YACReader/themes/builtin_classic.json index 74dff6b4..f3edf088 100644 --- a/YACReader/themes/builtin_classic.json +++ b/YACReader/themes/builtin_classic.json @@ -1,17 +1,37 @@ { + "goToFlowWidget": { + "editBackgroundColor": "#55000000", + "editBorderColor": "#77000000", + "editTextColor": "#ffffff", + "flowBackgroundColor": "#282828", + "flowTextColor": "#ffffff", + "iconColor": "#ffffff", + "labelTextColor": "#ffffff", + "sliderBorderColor": "#22ffffff", + "sliderGrooveColor": "#77000000", + "sliderHandleColor": "#55ffffff", + "toolbarBackgroundColor": "#99000000" + }, + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, "meta": { - "id": "builtin/classic", "displayName": "Default Classic", + "id": "builtin/classic", "variant": "dark" }, + "shortcutsIcons": { + "iconColor": "#404040" + }, "toolbar": { + "backgroundColor": "#f3f3f3", + "checkedButtonColor": "#cccccc", + "iconCheckedColor": "#5a5a5a", "iconColor": "#404040", "iconDisabledColor": "#858585", - "iconCheckedColor": "#5a5a5a", - "backgroundColor": "#f3f3f3", - "separatorColor": "#cccccc", - "checkedButtonColor": "#cccccc", - "menuIndicatorColor": "#404040" + "menuIndicatorColor": "#404040", + "separatorColor": "#cccccc" }, "viewer": { "defaultBackgroundColor": "#282828", @@ -19,33 +39,13 @@ "infoBackgroundColor": "#bb000000", "infoTextColor": "#ffffff" }, - "goToFlowWidget": { - "flowBackgroundColor": "#282828", - "flowTextColor": "#ffffff", - "toolbarBackgroundColor": "#99000000", - "sliderBorderColor": "#22ffffff", - "sliderGrooveColor": "#77000000", - "sliderHandleColor": "#55ffffff", - "editBorderColor": "#77000000", - "editBackgroundColor": "#55000000", - "editTextColor": "#ffffff", - "labelTextColor": "#ffffff", - "iconColor": "#ffffff" - }, - "helpAboutDialog": { - "headingColor": "#302f2d", - "linkColor": "#c19441" - }, "whatsNewDialog": { "backgroundColor": "#ffffff", - "headerTextColor": "#0a0a0a", - "versionTextColor": "#858585", - "contentTextColor": "#0a0a0a", - "linkColor": "#e8b800", "closeButtonColor": "#444444", - "headerDecorationColor": "#e8b800" - }, - "shortcutsIcons": { - "iconColor": "#404040" + "contentTextColor": "#0a0a0a", + "headerDecorationColor": "#e8b800", + "headerTextColor": "#0a0a0a", + "linkColor": "#e8b800", + "versionTextColor": "#858585" } } diff --git a/YACReader/themes/builtin_dark.json b/YACReader/themes/builtin_dark.json index 01085ca9..61038dfa 100644 --- a/YACReader/themes/builtin_dark.json +++ b/YACReader/themes/builtin_dark.json @@ -1,17 +1,37 @@ { + "goToFlowWidget": { + "editBackgroundColor": "#55000000", + "editBorderColor": "#77000000", + "editTextColor": "#ffffff", + "flowBackgroundColor": "#282828", + "flowTextColor": "#ffffff", + "iconColor": "#cccccc", + "labelTextColor": "#ffffff", + "sliderBorderColor": "#22ffffff", + "sliderGrooveColor": "#77000000", + "sliderHandleColor": "#55ffffff", + "toolbarBackgroundColor": "#99000000" + }, + "helpAboutDialog": { + "headingColor": "#e0e0e0", + "linkColor": "#d4a84b" + }, "meta": { - "id": "builtin/dark", "displayName": "Default Dark", + "id": "builtin/dark", "variant": "dark" }, + "shortcutsIcons": { + "iconColor": "#d0d0d0" + }, "toolbar": { + "backgroundColor": "#202020", + "checkedButtonColor": "#3a3a3a", + "iconCheckedColor": "#dadada", "iconColor": "#cccccc", "iconDisabledColor": "#444444", - "iconCheckedColor": "#dadada", - "backgroundColor": "#202020", - "separatorColor": "#444444", - "checkedButtonColor": "#3a3a3a", - "menuIndicatorColor": "#cccccc" + "menuIndicatorColor": "#cccccc", + "separatorColor": "#444444" }, "viewer": { "defaultBackgroundColor": "#282828", @@ -19,33 +39,13 @@ "infoBackgroundColor": "#bb000000", "infoTextColor": "#b0b0b0" }, - "goToFlowWidget": { - "flowBackgroundColor": "#282828", - "flowTextColor": "#ffffff", - "toolbarBackgroundColor": "#99000000", - "sliderBorderColor": "#22ffffff", - "sliderGrooveColor": "#77000000", - "sliderHandleColor": "#55ffffff", - "editBorderColor": "#77000000", - "editBackgroundColor": "#55000000", - "editTextColor": "#ffffff", - "labelTextColor": "#ffffff", - "iconColor": "#cccccc" - }, - "helpAboutDialog": { - "headingColor": "#e0e0e0", - "linkColor": "#d4a84b" - }, "whatsNewDialog": { "backgroundColor": "#2a2a2a", - "headerTextColor": "#e0e0e0", - "versionTextColor": "#858585", - "contentTextColor": "#e0e0e0", - "linkColor": "#e8b800", "closeButtonColor": "#dddddd", - "headerDecorationColor": "#e8b800" - }, - "shortcutsIcons": { - "iconColor": "#d0d0d0" + "contentTextColor": "#e0e0e0", + "headerDecorationColor": "#e8b800", + "headerTextColor": "#e0e0e0", + "linkColor": "#e8b800", + "versionTextColor": "#858585" } } diff --git a/YACReader/themes/builtin_light.json b/YACReader/themes/builtin_light.json index 97905791..dbd77f07 100644 --- a/YACReader/themes/builtin_light.json +++ b/YACReader/themes/builtin_light.json @@ -1,17 +1,37 @@ { + "goToFlowWidget": { + "editBackgroundColor": "#22000000", + "editBorderColor": "#33000000", + "editTextColor": "#202020", + "flowBackgroundColor": "#f6f6f6", + "flowTextColor": "#202020", + "iconColor": "#404040", + "labelTextColor": "#202020", + "sliderBorderColor": "#22000000", + "sliderGrooveColor": "#33000000", + "sliderHandleColor": "#55000000", + "toolbarBackgroundColor": "#bbffffff" + }, + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, "meta": { - "id": "builtin/light", "displayName": "Default Light", + "id": "builtin/light", "variant": "light" }, + "shortcutsIcons": { + "iconColor": "#606060" + }, "toolbar": { + "backgroundColor": "#f3f3f3", + "checkedButtonColor": "#cccccc", + "iconCheckedColor": "#5a5a5a", "iconColor": "#404040", "iconDisabledColor": "#b0b0b0", - "iconCheckedColor": "#5a5a5a", - "backgroundColor": "#f3f3f3", - "separatorColor": "#cccccc", - "checkedButtonColor": "#cccccc", - "menuIndicatorColor": "#404040" + "menuIndicatorColor": "#404040", + "separatorColor": "#cccccc" }, "viewer": { "defaultBackgroundColor": "#f6f6f6", @@ -19,33 +39,13 @@ "infoBackgroundColor": "#bbffffff", "infoTextColor": "#404040" }, - "goToFlowWidget": { - "flowBackgroundColor": "#f6f6f6", - "flowTextColor": "#202020", - "toolbarBackgroundColor": "#bbffffff", - "sliderBorderColor": "#22000000", - "sliderGrooveColor": "#33000000", - "sliderHandleColor": "#55000000", - "editBorderColor": "#33000000", - "editBackgroundColor": "#22000000", - "editTextColor": "#202020", - "labelTextColor": "#202020", - "iconColor": "#404040" - }, - "helpAboutDialog": { - "headingColor": "#302f2d", - "linkColor": "#c19441" - }, "whatsNewDialog": { "backgroundColor": "#ffffff", - "headerTextColor": "#0a0a0a", - "versionTextColor": "#858585", - "contentTextColor": "#0a0a0a", - "linkColor": "#e8b800", "closeButtonColor": "#444444", - "headerDecorationColor": "#e8b800" - }, - "shortcutsIcons": { - "iconColor": "#606060" + "contentTextColor": "#0a0a0a", + "headerDecorationColor": "#e8b800", + "headerTextColor": "#0a0a0a", + "linkColor": "#e8b800", + "versionTextColor": "#858585" } } diff --git a/YACReaderLibrary/themes/builtin_classic.json b/YACReaderLibrary/themes/builtin_classic.json index b410662d..ea571a11 100644 --- a/YACReaderLibrary/themes/builtin_classic.json +++ b/YACReaderLibrary/themes/builtin_classic.json @@ -1,237 +1,237 @@ { - "meta": { - "id": "builtin/classic", - "displayName": "Default Classic", - "variant": "dark" - }, "comicFlow": { "backgroundColor": "#000000", "textColor": "#4c4c4c" }, - "metadataScraperDialog": { - "contentTextColor": "#ffffff", - "contentBackgroundColor": "#2b2b2b", - "contentAltBackgroundColor": "#2b2b2b", - "dialogBackgroundColor": "#404040", - "tableBackgroundColor": "#2b2b2b", - "tableAltBackgroundColor": "#2e2e2e", - "tableBorderColor": "#242424", - "tableSelectedColor": "#555555", - "tableHeaderBackgroundColor": "#292929", - "tableHeaderGradientColor": "#292929", - "tableHeaderBorderColor": "#1f1f1f", - "tableHeaderTextColor": "#ebebeb", - "tableScrollHandleColor": "#dddddd", - "tableScrollBackgroundColor": "#404040", - "tableSectionBorderLight": "#fefefe", - "tableSectionBorderDark": "#dfdfdf", - "labelTextColor": "#ffffff", - "labelBackgroundColor": "#2b2b2b", - "hyperlinkColor": "#ffcc00", - "buttonBackgroundColor": "#2e2e2e", - "buttonTextColor": "#ffffff", - "buttonBorderColor": "#242424", - "radioUncheckedColor": "#e5e5e5", - "radioCheckedBackgroundColor": "#e5e5e5", - "radioCheckedIndicatorColor": "#5f5f5f", - "checkBoxTickColor": "#ffffff", - "toolButtonAccentColor": "#282828", - "downArrowColor": "#9f9f9f", - "upArrowColor": "#9f9f9f", - "busyIndicatorColor": "#ffffff", - "navIconColor": "#ffffff", - "rowIconColor": "#e5e5e5" - }, - "helpAboutDialog": { - "headingColor": "#302f2d", - "linkColor": "#c19441" - }, - "whatsNewDialog": { - "backgroundColor": "#2a2a2a", - "headerTextColor": "#e0e0e0", - "versionTextColor": "#858585", - "contentTextColor": "#e0e0e0", - "linkColor": "#e8b800", - "closeButtonColor": "#dddddd", - "headerDecorationColor": "#e8b800" - }, - "emptyContainer": { - "backgroundColor": "#2a2a2a", - "titleTextColor": "#cccccc", - "textColor": "#cccccc", - "descriptionTextColor": "#aaaaaa", - "searchIconColor": "#4c4c4c" - }, - "sidebar": { - "backgroundColor": "#454545", - "separatorColor": "#bdbfbf", - "sectionSeparatorColor": "#575757", - "uppercaseLabels": true, - "titleTextColor": "#bdbfbf", - "titleDropShadowColor": "#000000", - "busyIndicatorColor": "#ffffff" - }, - "sidebarIcons": { - "iconColor": "#e0e0e0", - "shadowColor": "#000000", - "useSystemFolderIcons": false - }, - "libraryItem": { - "textColor": "#dddfdf", - "libraryIconColor": "#dddfdf", - "libraryIconShadowColor": "#000000", - "selectedTextColor": "#ffffff", - "selectedBackgroundColor": "#2e2e2e", - "libraryIconSelectedColor": "#ffffff", - "libraryOptionsIconColor": "#ffffff" - }, - "importWidget": { - "backgroundColor": "#2a2a2a", - "titleTextColor": "#cccccc", - "descriptionTextColor": "#aaaaaa", - "currentComicTextColor": "#aaaaaa", - "coversViewBackgroundColor": "#3a3a3a", - "coversLabelColor": "#aaaaaa", - "coversDecorationBgColor": "#3a3a3a", - "coversDecorationShadowColor": "#1a1a1a", - "modeIconColor": "#4a4a4a", - "iconColor": "#cccccc", - "iconCheckedColor": "#aaaaaa" - }, - "serverConfigDialog": { - "backgroundColor": "#2a2a2a", - "titleTextColor": "#474747", - "qrMessageTextColor": "#a3a3a3", - "propagandaTextColor": "#4d4d4d", - "labelTextColor": "#575757", - "checkBoxTextColor": "#262626", - "qrBackgroundColor": "#2a2a2a", - "qrForegroundColor": "#ffffff", - "decorationColor": "#f7f7f7" - }, - "mainToolbar": { - "backgroundColor": "#f0f0f0", - "folderNameColor": "#404040", - "dividerColor": "#b8bdc4", - "iconColor": "#404040", - "iconDisabledColor": "#b0b0b0" - }, - "contentSplitter": { - "handleColor": "#b8b8b8", - "horizontalHandleHeight": 4, - "verticalHandleWidth": 4 - }, - "navigationTree": { - "textColor": "#dddfdf", - "selectionBackgroundColor": "#2e2e2e", - "scrollBackgroundColor": "#404040", - "scrollHandleColor": "#dddddd", - "selectedTextColor": "#ffffff", - "folderIndicatorColor": "#edc518", - "branchIndicatorColor": "#e0e0e0", - "branchIndicatorSelectedColor": "#ffffff", - "folderIconColor": "#e0e0e0", - "folderIconShadowColor": "#000000", - "folderIconSelectedColor": "#e0e0e0", - "folderIconSelectedShadowColor": "#000000", - "folderReadOverlayColor": "#464646", - "folderReadOverlaySelectedColor": "#464646" - }, "comicsViewTable": { "alternateBackgroundColor": "#f2f2f2", "backgroundColor": "#fafafa", "headerBackgroundColor": "#f5f5f5", "headerBorderColor": "#b8bdc4", "headerGradientColor": "#d1d1d1", + "headerTextColor": "#313232", "itemBorderBottomColor": "#dfdfdf", - "itemBorderTopColor": "#fefefe", "itemBorderBottomWidth": 1, + "itemBorderTopColor": "#fefefe", "itemBorderTopWidth": 1, "itemTextColor": "#252626", "selectedColor": "#d4d4d4", "selectedTextColor": "#252626", - "headerTextColor": "#313232", "starRatingColor": "#e9be0f", "starRatingSelectedColor": "#ffffff" }, - "gridAndInfoView": { + "comicsViewToolbar": { + "backgroundColor": "#f0f0f0", + "checkedBackgroundColor": "#cccccc", + "iconColor": "#404040", + "separatorColor": "#cccccc" + }, + "contentSplitter": { + "handleColor": "#b8b8b8", + "horizontalHandleHeight": 4, + "verticalHandleWidth": 4 + }, + "dialogIcons": { + "iconColor": "#f7f7f7" + }, + "emptyContainer": { "backgroundColor": "#2a2a2a", + "descriptionTextColor": "#aaaaaa", + "searchIconColor": "#4c4c4c", + "textColor": "#cccccc", + "titleTextColor": "#cccccc" + }, + "gridAndInfoView": { + "backgroundBlurOverlayColor": "#2a2a2a", + "backgroundColor": "#2a2a2a", + "borderColor": "#121212", "cellColor": "#212121", "cellColorWithBackground": "#99212121", - "selectedColor": "#121212", - "selectedBorderColor": "#ffcc00", - "borderColor": "#121212", - "titleColor": "#ffffff", - "textColor": "#a8a8a8", - "showDropShadow": true, + "continueReadingBackgroundColor": "#88000000", + "continueReadingColor": "#ffffff", + "currentComicBackgroundColor": "#88000000", + "favCheckedColor": "#e84852", + "favUncheckedColor": "#1c1c1c", "infoBackgroundColor": "#2e2e2e", "infoBorderColor": "#404040", "infoShadowColor": "#000000", "infoTextColor": "#b0b0b0", "infoTitleColor": "#ffffff", - "ratingUnselectedColor": "#1c1c1c", "ratingSelectedColor": "#ffffff", - "favUncheckedColor": "#1c1c1c", - "favCheckedColor": "#e84852", - "readTickUncheckedColor": "#1c1c1c", + "ratingUnselectedColor": "#1c1c1c", "readTickCheckedColor": "#e84852", - "currentComicBackgroundColor": "#88000000", - "continueReadingBackgroundColor": "#88000000", - "continueReadingColor": "#ffffff", - "backgroundBlurOverlayColor": "#2a2a2a" + "readTickUncheckedColor": "#1c1c1c", + "selectedBorderColor": "#ffcc00", + "selectedColor": "#121212", + "showDropShadow": true, + "textColor": "#a8a8a8", + "titleColor": "#ffffff" }, - "comicsViewToolbar": { + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, + "importWidget": { + "backgroundColor": "#2a2a2a", + "coversDecorationBgColor": "#3a3a3a", + "coversDecorationShadowColor": "#1a1a1a", + "coversLabelColor": "#aaaaaa", + "coversViewBackgroundColor": "#3a3a3a", + "currentComicTextColor": "#aaaaaa", + "descriptionTextColor": "#aaaaaa", + "iconCheckedColor": "#aaaaaa", + "iconColor": "#cccccc", + "modeIconColor": "#4a4a4a", + "titleTextColor": "#cccccc" + }, + "libraryItem": { + "libraryIconColor": "#dddfdf", + "libraryIconSelectedColor": "#ffffff", + "libraryIconShadowColor": "#000000", + "libraryOptionsIconColor": "#ffffff", + "selectedBackgroundColor": "#2e2e2e", + "selectedTextColor": "#ffffff", + "textColor": "#dddfdf" + }, + "mainToolbar": { "backgroundColor": "#f0f0f0", - "separatorColor": "#cccccc", - "checkedBackgroundColor": "#cccccc", - "iconColor": "#404040" - }, - "searchLineEdit": { - "textColor": "#ababab", - "backgroundColor": "#404040", - "iconColor": "#f7f7f7" - }, - "readingListIcons": { - "labelColors": { - "red": "#f67a7b", - "orange": "#f5c240", - "yellow": "#f2e446", - "green": "#ade738", - "cyan": "#a0fddb", - "blue": "#82c7ff", - "violet": "#8f95ff", - "purple": "#d692fc", - "pink": "#fd9cda", - "white": "#fcfcfc", - "light": "#cbcbcb", - "dark": "#b7b7b7" - }, - "labelShadowColor": "#000000", - "labelShadowSelectedColor": "#000000", - "readingListMainColor": "#e7e7e7", - "readingListMainSelectedColor": "#e7e7e7", - "favoritesMainColor": "#e15055", - "favoritesMainSelectedColor": "#e15055", - "currentlyReadingMainColor": "#ffcc00", - "currentlyReadingMainSelectedColor": "#ffcc00", - "currentlyReadingOuterColor": "#000000", - "currentlyReadingOuterSelectedColor": "#000000", - "specialListShadowColor": "#000000", - "specialListShadowSelectedColor": "#000000", - "listMainColor": "#e7e7e7", - "listMainSelectedColor": "#e7e7e7", - "listShadowColor": "#000000", - "listShadowSelectedColor": "#000000", - "listDetailColor": "#464646", - "listDetailSelectedColor": "#464646" - }, - "dialogIcons": { - "iconColor": "#f7f7f7" + "dividerColor": "#b8bdc4", + "folderNameColor": "#404040", + "iconColor": "#404040", + "iconDisabledColor": "#b0b0b0" }, "menuIcons": { "iconColor": "#f7f7f7" }, + "meta": { + "displayName": "Default Classic", + "id": "builtin/classic", + "variant": "dark" + }, + "metadataScraperDialog": { + "busyIndicatorColor": "#ffffff", + "buttonBackgroundColor": "#2e2e2e", + "buttonBorderColor": "#242424", + "buttonTextColor": "#ffffff", + "checkBoxTickColor": "#ffffff", + "contentAltBackgroundColor": "#2b2b2b", + "contentBackgroundColor": "#2b2b2b", + "contentTextColor": "#ffffff", + "dialogBackgroundColor": "#404040", + "downArrowColor": "#9f9f9f", + "hyperlinkColor": "#ffcc00", + "labelBackgroundColor": "#2b2b2b", + "labelTextColor": "#ffffff", + "navIconColor": "#ffffff", + "radioCheckedBackgroundColor": "#e5e5e5", + "radioCheckedIndicatorColor": "#5f5f5f", + "radioUncheckedColor": "#e5e5e5", + "rowIconColor": "#e5e5e5", + "tableAltBackgroundColor": "#2e2e2e", + "tableBackgroundColor": "#2b2b2b", + "tableBorderColor": "#242424", + "tableHeaderBackgroundColor": "#292929", + "tableHeaderBorderColor": "#1f1f1f", + "tableHeaderGradientColor": "#292929", + "tableHeaderTextColor": "#ebebeb", + "tableScrollBackgroundColor": "#404040", + "tableScrollHandleColor": "#dddddd", + "tableSectionBorderDark": "#dfdfdf", + "tableSectionBorderLight": "#fefefe", + "tableSelectedColor": "#555555", + "toolButtonAccentColor": "#282828", + "upArrowColor": "#9f9f9f" + }, + "navigationTree": { + "branchIndicatorColor": "#e0e0e0", + "branchIndicatorSelectedColor": "#ffffff", + "folderIconColor": "#e0e0e0", + "folderIconSelectedColor": "#e0e0e0", + "folderIconSelectedShadowColor": "#000000", + "folderIconShadowColor": "#000000", + "folderIndicatorColor": "#edc518", + "folderReadOverlayColor": "#464646", + "folderReadOverlaySelectedColor": "#464646", + "scrollBackgroundColor": "#404040", + "scrollHandleColor": "#dddddd", + "selectedTextColor": "#ffffff", + "selectionBackgroundColor": "#2e2e2e", + "textColor": "#dddfdf" + }, + "readingListIcons": { + "currentlyReadingMainColor": "#ffcc00", + "currentlyReadingMainSelectedColor": "#ffcc00", + "currentlyReadingOuterColor": "#000000", + "currentlyReadingOuterSelectedColor": "#000000", + "favoritesMainColor": "#e15055", + "favoritesMainSelectedColor": "#e15055", + "labelColors": { + "blue": "#82c7ff", + "cyan": "#a0fddb", + "dark": "#b7b7b7", + "green": "#ade738", + "light": "#cbcbcb", + "orange": "#f5c240", + "pink": "#fd9cda", + "purple": "#d692fc", + "red": "#f67a7b", + "violet": "#8f95ff", + "white": "#fcfcfc", + "yellow": "#f2e446" + }, + "labelShadowColor": "#000000", + "labelShadowSelectedColor": "#000000", + "listDetailColor": "#464646", + "listDetailSelectedColor": "#464646", + "listMainColor": "#e7e7e7", + "listMainSelectedColor": "#e7e7e7", + "listShadowColor": "#000000", + "listShadowSelectedColor": "#000000", + "readingListMainColor": "#e7e7e7", + "readingListMainSelectedColor": "#e7e7e7", + "specialListShadowColor": "#000000", + "specialListShadowSelectedColor": "#000000" + }, + "searchLineEdit": { + "backgroundColor": "#404040", + "iconColor": "#f7f7f7", + "textColor": "#ababab" + }, + "serverConfigDialog": { + "backgroundColor": "#2a2a2a", + "checkBoxTextColor": "#262626", + "decorationColor": "#f7f7f7", + "labelTextColor": "#575757", + "propagandaTextColor": "#4d4d4d", + "qrBackgroundColor": "#2a2a2a", + "qrForegroundColor": "#ffffff", + "qrMessageTextColor": "#a3a3a3", + "titleTextColor": "#474747" + }, "shortcutsIcons": { "iconColor": "#f7f7f7" + }, + "sidebar": { + "backgroundColor": "#454545", + "busyIndicatorColor": "#ffffff", + "sectionSeparatorColor": "#575757", + "separatorColor": "#bdbfbf", + "titleDropShadowColor": "#000000", + "titleTextColor": "#bdbfbf", + "uppercaseLabels": true + }, + "sidebarIcons": { + "iconColor": "#e0e0e0", + "shadowColor": "#000000", + "useSystemFolderIcons": false + }, + "whatsNewDialog": { + "backgroundColor": "#2a2a2a", + "closeButtonColor": "#dddddd", + "contentTextColor": "#e0e0e0", + "headerDecorationColor": "#e8b800", + "headerTextColor": "#e0e0e0", + "linkColor": "#e8b800", + "versionTextColor": "#858585" } } diff --git a/YACReaderLibrary/themes/builtin_dark.json b/YACReaderLibrary/themes/builtin_dark.json index 1634400a..45fbcc64 100644 --- a/YACReaderLibrary/themes/builtin_dark.json +++ b/YACReaderLibrary/themes/builtin_dark.json @@ -1,237 +1,237 @@ { - "meta": { - "id": "builtin/dark", - "displayName": "Default Dark", - "variant": "dark" - }, "comicFlow": { "backgroundColor": "#111111", "textColor": "#888888" }, - "metadataScraperDialog": { - "contentTextColor": "#ffffff", - "contentBackgroundColor": "#2b2b2b", - "contentAltBackgroundColor": "#2e2e2e", - "dialogBackgroundColor": "#404040", - "tableBackgroundColor": "#2b2b2b", - "tableAltBackgroundColor": "#2e2e2e", - "tableBorderColor": "#242424", - "tableSelectedColor": "#555555", - "tableHeaderBackgroundColor": "#292929", - "tableHeaderGradientColor": "#292929", - "tableHeaderBorderColor": "#1f1f1f", - "tableHeaderTextColor": "#ebebeb", - "tableScrollHandleColor": "#dddddd", - "tableScrollBackgroundColor": "#404040", - "tableSectionBorderLight": "#fefefe", - "tableSectionBorderDark": "#dfdfdf", - "labelTextColor": "#ffffff", - "labelBackgroundColor": "#2b2b2b", - "hyperlinkColor": "#ffcc00", - "buttonBackgroundColor": "#2e2e2e", - "buttonTextColor": "#ffffff", - "buttonBorderColor": "#242424", - "radioUncheckedColor": "#e5e5e5", - "radioCheckedBackgroundColor": "#e5e5e5", - "radioCheckedIndicatorColor": "#5f5f5f", - "checkBoxTickColor": "#ffffff", - "toolButtonAccentColor": "#282828", - "downArrowColor": "#9f9f9f", - "upArrowColor": "#9f9f9f", - "busyIndicatorColor": "#ffffff", - "navIconColor": "#ffffff", - "rowIconColor": "#e5e5e5" - }, - "helpAboutDialog": { - "headingColor": "#e0e0e0", - "linkColor": "#d4a84b" - }, - "whatsNewDialog": { - "backgroundColor": "#2a2a2a", - "headerTextColor": "#e0e0e0", - "versionTextColor": "#858585", - "contentTextColor": "#e0e0e0", - "linkColor": "#e8b800", - "closeButtonColor": "#dddddd", - "headerDecorationColor": "#e8b800" - }, - "emptyContainer": { - "backgroundColor": "#2a2a2a", - "titleTextColor": "#cccccc", - "textColor": "#cccccc", - "descriptionTextColor": "#aaaaaa", - "searchIconColor": "#4c4c4c" - }, - "sidebar": { - "backgroundColor": "#454545", - "separatorColor": "#bdbfbf", - "sectionSeparatorColor": "#575757", - "uppercaseLabels": true, - "titleTextColor": "#bdbfbf", - "titleDropShadowColor": "#000000", - "busyIndicatorColor": "#ffffff" - }, - "sidebarIcons": { - "iconColor": "#e0e0e0", - "shadowColor": "#000000", - "useSystemFolderIcons": false - }, - "libraryItem": { - "textColor": "#dddfdf", - "libraryIconColor": "#dddfdf", - "libraryIconShadowColor": "#000000", - "selectedTextColor": "#ffffff", - "selectedBackgroundColor": "#2e2e2e", - "libraryIconSelectedColor": "#ffffff", - "libraryOptionsIconColor": "#ffffff" - }, - "importWidget": { - "backgroundColor": "#2a2a2a", - "titleTextColor": "#cccccc", - "descriptionTextColor": "#aaaaaa", - "currentComicTextColor": "#aaaaaa", - "coversViewBackgroundColor": "#3a3a3a", - "coversLabelColor": "#aaaaaa", - "coversDecorationBgColor": "#3a3a3a", - "coversDecorationShadowColor": "#1a1a1a", - "modeIconColor": "#4a4a4a", - "iconColor": "#cccccc", - "iconCheckedColor": "#aaaaaa" - }, - "serverConfigDialog": { - "backgroundColor": "#2a2a2a", - "titleTextColor": "#d0d0d0", - "qrMessageTextColor": "#a3a3a3", - "propagandaTextColor": "#b0b0b0", - "labelTextColor": "#c0c0c0", - "checkBoxTextColor": "#dddddd", - "qrBackgroundColor": "#2a2a2a", - "qrForegroundColor": "#ffffff", - "decorationColor": "#f7f7f7" - }, - "mainToolbar": { - "backgroundColor": "#2a2a2a", - "folderNameColor": "#dddddd", - "dividerColor": "#555555", - "iconColor": "#dddddd", - "iconDisabledColor": "#666666" - }, - "contentSplitter": { - "handleColor": "#1f1f1f", - "horizontalHandleHeight": 4, - "verticalHandleWidth": 4 - }, - "navigationTree": { - "textColor": "#dddfdf", - "selectionBackgroundColor": "#2e2e2e", - "scrollBackgroundColor": "#404040", - "scrollHandleColor": "#dddddd", - "selectedTextColor": "#ffffff", - "folderIndicatorColor": "#edc518", - "branchIndicatorColor": "#e0e0e0", - "branchIndicatorSelectedColor": "#ffffff", - "folderIconColor": "#e0e0e0", - "folderIconShadowColor": "#000000", - "folderIconSelectedColor": "#e0e0e0", - "folderIconSelectedShadowColor": "#000000", - "folderReadOverlayColor": "#222222", - "folderReadOverlaySelectedColor": "#222222" - }, "comicsViewTable": { "alternateBackgroundColor": "#2e2e2e", "backgroundColor": "#2a2a2a", "headerBackgroundColor": "#2a2a2a", "headerBorderColor": "#1f1f1f", "headerGradientColor": "#252525", + "headerTextColor": "#dddddd", "itemBorderBottomColor": "#1f1f1f", - "itemBorderTopColor": "#353535", "itemBorderBottomWidth": 1, + "itemBorderTopColor": "#353535", "itemBorderTopWidth": 1, "itemTextColor": "#dddddd", "selectedColor": "#555555", "selectedTextColor": "#ffffff", - "headerTextColor": "#dddddd", "starRatingColor": "#e9be0f", "starRatingSelectedColor": "#ffffff" }, - "gridAndInfoView": { + "comicsViewToolbar": { "backgroundColor": "#2a2a2a", + "checkedBackgroundColor": "#555555", + "iconColor": "#dddddd", + "separatorColor": "#444444" + }, + "contentSplitter": { + "handleColor": "#1f1f1f", + "horizontalHandleHeight": 4, + "verticalHandleWidth": 4 + }, + "dialogIcons": { + "iconColor": "#f7f7f7" + }, + "emptyContainer": { + "backgroundColor": "#2a2a2a", + "descriptionTextColor": "#aaaaaa", + "searchIconColor": "#4c4c4c", + "textColor": "#cccccc", + "titleTextColor": "#cccccc" + }, + "gridAndInfoView": { + "backgroundBlurOverlayColor": "#2a2a2a", + "backgroundColor": "#2a2a2a", + "borderColor": "#121212", "cellColor": "#212121", "cellColorWithBackground": "#99212121", - "selectedColor": "#121212", - "selectedBorderColor": "#ffcc00", - "borderColor": "#121212", - "titleColor": "#ffffff", - "textColor": "#a8a8a8", - "showDropShadow": true, + "continueReadingBackgroundColor": "#88000000", + "continueReadingColor": "#ffffff", + "currentComicBackgroundColor": "#88000000", + "favCheckedColor": "#e84852", + "favUncheckedColor": "#1c1c1c", "infoBackgroundColor": "#2e2e2e", "infoBorderColor": "#404040", "infoShadowColor": "#000000", "infoTextColor": "#b0b0b0", "infoTitleColor": "#ffffff", - "ratingUnselectedColor": "#1c1c1c", "ratingSelectedColor": "#ffffff", - "favUncheckedColor": "#1c1c1c", - "favCheckedColor": "#e84852", - "readTickUncheckedColor": "#1c1c1c", + "ratingUnselectedColor": "#1c1c1c", "readTickCheckedColor": "#e84852", - "currentComicBackgroundColor": "#88000000", - "continueReadingBackgroundColor": "#88000000", - "continueReadingColor": "#ffffff", - "backgroundBlurOverlayColor": "#2a2a2a" + "readTickUncheckedColor": "#1c1c1c", + "selectedBorderColor": "#ffcc00", + "selectedColor": "#121212", + "showDropShadow": true, + "textColor": "#a8a8a8", + "titleColor": "#ffffff" }, - "comicsViewToolbar": { + "helpAboutDialog": { + "headingColor": "#e0e0e0", + "linkColor": "#d4a84b" + }, + "importWidget": { "backgroundColor": "#2a2a2a", - "separatorColor": "#444444", - "checkedBackgroundColor": "#555555", - "iconColor": "#dddddd" + "coversDecorationBgColor": "#3a3a3a", + "coversDecorationShadowColor": "#1a1a1a", + "coversLabelColor": "#aaaaaa", + "coversViewBackgroundColor": "#3a3a3a", + "currentComicTextColor": "#aaaaaa", + "descriptionTextColor": "#aaaaaa", + "iconCheckedColor": "#aaaaaa", + "iconColor": "#cccccc", + "modeIconColor": "#4a4a4a", + "titleTextColor": "#cccccc" }, - "searchLineEdit": { - "textColor": "#ababab", - "backgroundColor": "#404040", - "iconColor": "#f7f7f7" + "libraryItem": { + "libraryIconColor": "#dddfdf", + "libraryIconSelectedColor": "#ffffff", + "libraryIconShadowColor": "#000000", + "libraryOptionsIconColor": "#ffffff", + "selectedBackgroundColor": "#2e2e2e", + "selectedTextColor": "#ffffff", + "textColor": "#dddfdf" }, - "readingListIcons": { - "labelColors": { - "red": "#f67a7b", - "orange": "#f5c240", - "yellow": "#f2e446", - "green": "#ade738", - "cyan": "#a0fddb", - "blue": "#82c7ff", - "violet": "#8f95ff", - "purple": "#d692fc", - "pink": "#fd9cda", - "white": "#fcfcfc", - "light": "#cbcbcb", - "dark": "#b7b7b7" - }, - "labelShadowColor": "#000000", - "labelShadowSelectedColor": "#000000", - "readingListMainColor": "#e7e7e7", - "readingListMainSelectedColor": "#e7e7e7", - "favoritesMainColor": "#e15055", - "favoritesMainSelectedColor": "#e15055", - "currentlyReadingMainColor": "#ffcc00", - "currentlyReadingMainSelectedColor": "#ffcc00", - "currentlyReadingOuterColor": "#000000", - "currentlyReadingOuterSelectedColor": "#000000", - "specialListShadowColor": "#000000", - "specialListShadowSelectedColor": "#000000", - "listMainColor": "#e7e7e7", - "listMainSelectedColor": "#e7e7e7", - "listShadowColor": "#000000", - "listShadowSelectedColor": "#000000", - "listDetailColor": "#464646", - "listDetailSelectedColor": "#464646" - }, - "dialogIcons": { - "iconColor": "#f7f7f7" + "mainToolbar": { + "backgroundColor": "#2a2a2a", + "dividerColor": "#555555", + "folderNameColor": "#dddddd", + "iconColor": "#dddddd", + "iconDisabledColor": "#666666" }, "menuIcons": { "iconColor": "#f7f7f7" }, + "meta": { + "displayName": "Default Dark", + "id": "builtin/dark", + "variant": "dark" + }, + "metadataScraperDialog": { + "busyIndicatorColor": "#ffffff", + "buttonBackgroundColor": "#2e2e2e", + "buttonBorderColor": "#242424", + "buttonTextColor": "#ffffff", + "checkBoxTickColor": "#ffffff", + "contentAltBackgroundColor": "#2e2e2e", + "contentBackgroundColor": "#2b2b2b", + "contentTextColor": "#ffffff", + "dialogBackgroundColor": "#404040", + "downArrowColor": "#9f9f9f", + "hyperlinkColor": "#ffcc00", + "labelBackgroundColor": "#2b2b2b", + "labelTextColor": "#ffffff", + "navIconColor": "#ffffff", + "radioCheckedBackgroundColor": "#e5e5e5", + "radioCheckedIndicatorColor": "#5f5f5f", + "radioUncheckedColor": "#e5e5e5", + "rowIconColor": "#e5e5e5", + "tableAltBackgroundColor": "#2e2e2e", + "tableBackgroundColor": "#2b2b2b", + "tableBorderColor": "#242424", + "tableHeaderBackgroundColor": "#292929", + "tableHeaderBorderColor": "#1f1f1f", + "tableHeaderGradientColor": "#292929", + "tableHeaderTextColor": "#ebebeb", + "tableScrollBackgroundColor": "#404040", + "tableScrollHandleColor": "#dddddd", + "tableSectionBorderDark": "#dfdfdf", + "tableSectionBorderLight": "#fefefe", + "tableSelectedColor": "#555555", + "toolButtonAccentColor": "#282828", + "upArrowColor": "#9f9f9f" + }, + "navigationTree": { + "branchIndicatorColor": "#e0e0e0", + "branchIndicatorSelectedColor": "#ffffff", + "folderIconColor": "#e0e0e0", + "folderIconSelectedColor": "#e0e0e0", + "folderIconSelectedShadowColor": "#000000", + "folderIconShadowColor": "#000000", + "folderIndicatorColor": "#edc518", + "folderReadOverlayColor": "#222222", + "folderReadOverlaySelectedColor": "#222222", + "scrollBackgroundColor": "#404040", + "scrollHandleColor": "#dddddd", + "selectedTextColor": "#ffffff", + "selectionBackgroundColor": "#2e2e2e", + "textColor": "#dddfdf" + }, + "readingListIcons": { + "currentlyReadingMainColor": "#ffcc00", + "currentlyReadingMainSelectedColor": "#ffcc00", + "currentlyReadingOuterColor": "#000000", + "currentlyReadingOuterSelectedColor": "#000000", + "favoritesMainColor": "#e15055", + "favoritesMainSelectedColor": "#e15055", + "labelColors": { + "blue": "#82c7ff", + "cyan": "#a0fddb", + "dark": "#b7b7b7", + "green": "#ade738", + "light": "#cbcbcb", + "orange": "#f5c240", + "pink": "#fd9cda", + "purple": "#d692fc", + "red": "#f67a7b", + "violet": "#8f95ff", + "white": "#fcfcfc", + "yellow": "#f2e446" + }, + "labelShadowColor": "#000000", + "labelShadowSelectedColor": "#000000", + "listDetailColor": "#464646", + "listDetailSelectedColor": "#464646", + "listMainColor": "#e7e7e7", + "listMainSelectedColor": "#e7e7e7", + "listShadowColor": "#000000", + "listShadowSelectedColor": "#000000", + "readingListMainColor": "#e7e7e7", + "readingListMainSelectedColor": "#e7e7e7", + "specialListShadowColor": "#000000", + "specialListShadowSelectedColor": "#000000" + }, + "searchLineEdit": { + "backgroundColor": "#404040", + "iconColor": "#f7f7f7", + "textColor": "#ababab" + }, + "serverConfigDialog": { + "backgroundColor": "#2a2a2a", + "checkBoxTextColor": "#dddddd", + "decorationColor": "#f7f7f7", + "labelTextColor": "#c0c0c0", + "propagandaTextColor": "#b0b0b0", + "qrBackgroundColor": "#2a2a2a", + "qrForegroundColor": "#ffffff", + "qrMessageTextColor": "#a3a3a3", + "titleTextColor": "#d0d0d0" + }, "shortcutsIcons": { "iconColor": "#f7f7f7" + }, + "sidebar": { + "backgroundColor": "#454545", + "busyIndicatorColor": "#ffffff", + "sectionSeparatorColor": "#575757", + "separatorColor": "#bdbfbf", + "titleDropShadowColor": "#000000", + "titleTextColor": "#bdbfbf", + "uppercaseLabels": true + }, + "sidebarIcons": { + "iconColor": "#e0e0e0", + "shadowColor": "#000000", + "useSystemFolderIcons": false + }, + "whatsNewDialog": { + "backgroundColor": "#2a2a2a", + "closeButtonColor": "#dddddd", + "contentTextColor": "#e0e0e0", + "headerDecorationColor": "#e8b800", + "headerTextColor": "#e0e0e0", + "linkColor": "#e8b800", + "versionTextColor": "#858585" } } diff --git a/YACReaderLibrary/themes/builtin_light.json b/YACReaderLibrary/themes/builtin_light.json index f1cf40e4..9d514d4b 100644 --- a/YACReaderLibrary/themes/builtin_light.json +++ b/YACReaderLibrary/themes/builtin_light.json @@ -1,237 +1,237 @@ { - "meta": { - "id": "builtin/light", - "displayName": "Default Light", - "variant": "light" - }, "comicFlow": { "backgroundColor": "#dcdcdc", "textColor": "#303030" }, - "metadataScraperDialog": { - "contentTextColor": "#000000", - "contentBackgroundColor": "#ececec", - "contentAltBackgroundColor": "#e0e0e0", - "dialogBackgroundColor": "#fbfbfb", - "tableBackgroundColor": "#f4f4f4", - "tableAltBackgroundColor": "#fafafa", - "tableBorderColor": "#cccccc", - "tableSelectedColor": "#dddddd", - "tableHeaderBackgroundColor": "#e0e0e0", - "tableHeaderGradientColor": "#e0e0e0", - "tableHeaderBorderColor": "#c0c0c0", - "tableHeaderTextColor": "#333333", - "tableScrollHandleColor": "#888888", - "tableScrollBackgroundColor": "#d0d0d0", - "tableSectionBorderLight": "#ffffff", - "tableSectionBorderDark": "#cccccc", - "labelTextColor": "#000000", - "labelBackgroundColor": "#ececec", - "hyperlinkColor": "#ffcc00", - "buttonBackgroundColor": "#e0e0e0", - "buttonTextColor": "#000000", - "buttonBorderColor": "#cccccc", - "radioUncheckedColor": "#e0e0e0", - "radioCheckedBackgroundColor": "#e0e0e0", - "radioCheckedIndicatorColor": "#222222", - "checkBoxTickColor": "#000000", - "toolButtonAccentColor": "#a0a0a0", - "downArrowColor": "#222222", - "upArrowColor": "#222222", - "busyIndicatorColor": "#000000", - "navIconColor": "#222222", - "rowIconColor": "#222222" - }, - "helpAboutDialog": { - "headingColor": "#302f2d", - "linkColor": "#c19441" - }, - "whatsNewDialog": { - "backgroundColor": "#ffffff", - "headerTextColor": "#0a0a0a", - "versionTextColor": "#858585", - "contentTextColor": "#0a0a0a", - "linkColor": "#e8b800", - "closeButtonColor": "#444444", - "headerDecorationColor": "#e8b800" - }, - "emptyContainer": { - "backgroundColor": "#ffffff", - "titleTextColor": "#888888", - "textColor": "#495252", - "descriptionTextColor": "#565959", - "searchIconColor": "#cccccc" - }, - "sidebar": { - "backgroundColor": "#fbfbfb", - "separatorColor": "#808080", - "sectionSeparatorColor": "#e0e0e0", - "uppercaseLabels": true, - "titleTextColor": "#4a494a", - "titleDropShadowColor": "#ffffff", - "busyIndicatorColor": "#808080" - }, - "sidebarIcons": { - "iconColor": "#4f4e4f", - "shadowColor": "#fbfbfb", - "useSystemFolderIcons": false - }, - "libraryItem": { - "textColor": "#000000", - "libraryIconColor": "#606060", - "libraryIconShadowColor": "#ffffff", - "selectedTextColor": "#ffffff", - "selectedBackgroundColor": "#333133", - "libraryIconSelectedColor": "#ffffff", - "libraryOptionsIconColor": "#ffffff" - }, - "importWidget": { - "backgroundColor": "#fafafa", - "titleTextColor": "#495252", - "descriptionTextColor": "#565959", - "currentComicTextColor": "#565959", - "coversViewBackgroundColor": "#e6e6e6", - "coversLabelColor": "#565959", - "coversDecorationBgColor": "#e6e6e6", - "coversDecorationShadowColor": "#a1a1a1", - "modeIconColor": "#e6e6e6", - "iconColor": "#495252", - "iconCheckedColor": "#565959" - }, - "serverConfigDialog": { - "backgroundColor": "#ffffff", - "titleTextColor": "#474747", - "qrMessageTextColor": "#a3a3a3", - "propagandaTextColor": "#4d4d4d", - "labelTextColor": "#575757", - "checkBoxTextColor": "#262626", - "qrBackgroundColor": "#ffffff", - "qrForegroundColor": "#606060", - "decorationColor": "#606060" - }, - "mainToolbar": { - "backgroundColor": "#f0f0f0", - "folderNameColor": "#333133", - "dividerColor": "#b8bdc4", - "iconColor": "#333133", - "iconDisabledColor": "#b0b0b0" - }, - "contentSplitter": { - "handleColor": "#f0f0f0", - "horizontalHandleHeight": 4, - "verticalHandleWidth": 4 - }, - "navigationTree": { - "textColor": "#000000", - "selectionBackgroundColor": "#333133", - "scrollBackgroundColor": "#e0e0e0", - "scrollHandleColor": "#888888", - "selectedTextColor": "#ffffff", - "folderIndicatorColor": "#555f7f", - "branchIndicatorColor": "#606060", - "branchIndicatorSelectedColor": "#ffffff", - "folderIconColor": "#606060", - "folderIconShadowColor": "#ffffff", - "folderIconSelectedColor": "#ffffff", - "folderIconSelectedShadowColor": "#161616", - "folderReadOverlayColor": "#ffffff", - "folderReadOverlaySelectedColor": "#161616" - }, "comicsViewTable": { "alternateBackgroundColor": "#f2f2f2", "backgroundColor": "#fafafa", "headerBackgroundColor": "#f5f5f5", "headerBorderColor": "#b8bdc4", "headerGradientColor": "#f5f5f5", + "headerTextColor": "#313232", "itemBorderBottomColor": "#dfdfdf", - "itemBorderTopColor": "#fefefe", "itemBorderBottomWidth": 0, + "itemBorderTopColor": "#fefefe", "itemBorderTopWidth": 0, "itemTextColor": "#252626", "selectedColor": "#595959", "selectedTextColor": "#ffffff", - "headerTextColor": "#313232", "starRatingColor": "#e9be0f", "starRatingSelectedColor": "#ffffff" }, + "comicsViewToolbar": { + "backgroundColor": "#f0f0f0", + "checkedBackgroundColor": "#cccccc", + "iconColor": "#404040", + "separatorColor": "#cccccc" + }, + "contentSplitter": { + "handleColor": "#f0f0f0", + "horizontalHandleHeight": 4, + "verticalHandleWidth": 4 + }, + "dialogIcons": { + "iconColor": "#606060" + }, + "emptyContainer": { + "backgroundColor": "#ffffff", + "descriptionTextColor": "#565959", + "searchIconColor": "#cccccc", + "textColor": "#495252", + "titleTextColor": "#888888" + }, "gridAndInfoView": { + "backgroundBlurOverlayColor": "#9e9e9e", "backgroundColor": "#f6f6f6", + "borderColor": "#dbdbdb", "cellColor": "#ffffff", "cellColorWithBackground": "#99ffffff", - "selectedColor": "#ffffff", - "selectedBorderColor": "#ffcc00", - "borderColor": "#dbdbdb", - "titleColor": "#121212", - "textColor": "#636363", - "showDropShadow": true, + "continueReadingBackgroundColor": "#e8e8e8", + "continueReadingColor": "#000000", + "currentComicBackgroundColor": "#88ffffff", + "favCheckedColor": "#e84852", + "favUncheckedColor": "#dedede", "infoBackgroundColor": "#ffffff", "infoBorderColor": "#808080", "infoShadowColor": "#444444", "infoTextColor": "#404040", "infoTitleColor": "#2e2e2e", - "ratingUnselectedColor": "#dedede", "ratingSelectedColor": "#2b2b2b", - "favUncheckedColor": "#dedede", - "favCheckedColor": "#e84852", - "readTickUncheckedColor": "#dedede", + "ratingUnselectedColor": "#dedede", "readTickCheckedColor": "#e84852", - "currentComicBackgroundColor": "#88ffffff", - "continueReadingBackgroundColor": "#e8e8e8", - "continueReadingColor": "#000000", - "backgroundBlurOverlayColor": "#9e9e9e" + "readTickUncheckedColor": "#dedede", + "selectedBorderColor": "#ffcc00", + "selectedColor": "#ffffff", + "showDropShadow": true, + "textColor": "#636363", + "titleColor": "#121212" }, - "comicsViewToolbar": { + "helpAboutDialog": { + "headingColor": "#302f2d", + "linkColor": "#c19441" + }, + "importWidget": { + "backgroundColor": "#fafafa", + "coversDecorationBgColor": "#e6e6e6", + "coversDecorationShadowColor": "#a1a1a1", + "coversLabelColor": "#565959", + "coversViewBackgroundColor": "#e6e6e6", + "currentComicTextColor": "#565959", + "descriptionTextColor": "#565959", + "iconCheckedColor": "#565959", + "iconColor": "#495252", + "modeIconColor": "#e6e6e6", + "titleTextColor": "#495252" + }, + "libraryItem": { + "libraryIconColor": "#606060", + "libraryIconSelectedColor": "#ffffff", + "libraryIconShadowColor": "#ffffff", + "libraryOptionsIconColor": "#ffffff", + "selectedBackgroundColor": "#333133", + "selectedTextColor": "#ffffff", + "textColor": "#000000" + }, + "mainToolbar": { "backgroundColor": "#f0f0f0", - "separatorColor": "#cccccc", - "checkedBackgroundColor": "#cccccc", - "iconColor": "#404040" - }, - "searchLineEdit": { - "textColor": "#ffffff", - "backgroundColor": "#333133", - "iconColor": "#efefef" - }, - "readingListIcons": { - "labelColors": { - "red": "#f67a7b", - "orange": "#f5c240", - "yellow": "#f2e446", - "green": "#ade738", - "cyan": "#a0fddb", - "blue": "#82c7ff", - "violet": "#8f95ff", - "purple": "#d692fc", - "pink": "#fd9cda", - "white": "#fcfcfc", - "light": "#cbcbcb", - "dark": "#b7b7b7" - }, - "labelShadowColor": "#8f8f8f", - "labelShadowSelectedColor": "#161616", - "readingListMainColor": "#808080", - "readingListMainSelectedColor": "#808080", - "favoritesMainColor": "#e15055", - "favoritesMainSelectedColor": "#e15055", - "currentlyReadingMainColor": "#ffcc00", - "currentlyReadingMainSelectedColor": "#ffcc00", - "currentlyReadingOuterColor": "#000000", - "currentlyReadingOuterSelectedColor": "#000000", - "specialListShadowColor": "#8f8f8f", - "specialListShadowSelectedColor": "#161616", - "listMainColor": "#808080", - "listMainSelectedColor": "#ffffff", - "listShadowColor": "#8f8f8f", - "listShadowSelectedColor": "#161616", - "listDetailColor": "#ffffff", - "listDetailSelectedColor": "#161616" - }, - "dialogIcons": { - "iconColor": "#606060" + "dividerColor": "#b8bdc4", + "folderNameColor": "#333133", + "iconColor": "#333133", + "iconDisabledColor": "#b0b0b0" }, "menuIcons": { "iconColor": "#606060" }, + "meta": { + "displayName": "Default Light", + "id": "builtin/light", + "variant": "light" + }, + "metadataScraperDialog": { + "busyIndicatorColor": "#000000", + "buttonBackgroundColor": "#e0e0e0", + "buttonBorderColor": "#cccccc", + "buttonTextColor": "#000000", + "checkBoxTickColor": "#000000", + "contentAltBackgroundColor": "#e0e0e0", + "contentBackgroundColor": "#ececec", + "contentTextColor": "#000000", + "dialogBackgroundColor": "#fbfbfb", + "downArrowColor": "#222222", + "hyperlinkColor": "#ffcc00", + "labelBackgroundColor": "#ececec", + "labelTextColor": "#000000", + "navIconColor": "#222222", + "radioCheckedBackgroundColor": "#e0e0e0", + "radioCheckedIndicatorColor": "#222222", + "radioUncheckedColor": "#e0e0e0", + "rowIconColor": "#222222", + "tableAltBackgroundColor": "#fafafa", + "tableBackgroundColor": "#f4f4f4", + "tableBorderColor": "#cccccc", + "tableHeaderBackgroundColor": "#e0e0e0", + "tableHeaderBorderColor": "#c0c0c0", + "tableHeaderGradientColor": "#e0e0e0", + "tableHeaderTextColor": "#333333", + "tableScrollBackgroundColor": "#d0d0d0", + "tableScrollHandleColor": "#888888", + "tableSectionBorderDark": "#cccccc", + "tableSectionBorderLight": "#ffffff", + "tableSelectedColor": "#dddddd", + "toolButtonAccentColor": "#a0a0a0", + "upArrowColor": "#222222" + }, + "navigationTree": { + "branchIndicatorColor": "#606060", + "branchIndicatorSelectedColor": "#ffffff", + "folderIconColor": "#606060", + "folderIconSelectedColor": "#ffffff", + "folderIconSelectedShadowColor": "#161616", + "folderIconShadowColor": "#ffffff", + "folderIndicatorColor": "#555f7f", + "folderReadOverlayColor": "#ffffff", + "folderReadOverlaySelectedColor": "#161616", + "scrollBackgroundColor": "#e0e0e0", + "scrollHandleColor": "#888888", + "selectedTextColor": "#ffffff", + "selectionBackgroundColor": "#333133", + "textColor": "#000000" + }, + "readingListIcons": { + "currentlyReadingMainColor": "#ffcc00", + "currentlyReadingMainSelectedColor": "#ffcc00", + "currentlyReadingOuterColor": "#000000", + "currentlyReadingOuterSelectedColor": "#000000", + "favoritesMainColor": "#e15055", + "favoritesMainSelectedColor": "#e15055", + "labelColors": { + "blue": "#82c7ff", + "cyan": "#a0fddb", + "dark": "#b7b7b7", + "green": "#ade738", + "light": "#cbcbcb", + "orange": "#f5c240", + "pink": "#fd9cda", + "purple": "#d692fc", + "red": "#f67a7b", + "violet": "#8f95ff", + "white": "#fcfcfc", + "yellow": "#f2e446" + }, + "labelShadowColor": "#8f8f8f", + "labelShadowSelectedColor": "#161616", + "listDetailColor": "#ffffff", + "listDetailSelectedColor": "#161616", + "listMainColor": "#808080", + "listMainSelectedColor": "#ffffff", + "listShadowColor": "#8f8f8f", + "listShadowSelectedColor": "#161616", + "readingListMainColor": "#808080", + "readingListMainSelectedColor": "#808080", + "specialListShadowColor": "#8f8f8f", + "specialListShadowSelectedColor": "#161616" + }, + "searchLineEdit": { + "backgroundColor": "#333133", + "iconColor": "#efefef", + "textColor": "#ffffff" + }, + "serverConfigDialog": { + "backgroundColor": "#ffffff", + "checkBoxTextColor": "#262626", + "decorationColor": "#606060", + "labelTextColor": "#575757", + "propagandaTextColor": "#4d4d4d", + "qrBackgroundColor": "#ffffff", + "qrForegroundColor": "#606060", + "qrMessageTextColor": "#a3a3a3", + "titleTextColor": "#474747" + }, "shortcutsIcons": { "iconColor": "#606060" + }, + "sidebar": { + "backgroundColor": "#fbfbfb", + "busyIndicatorColor": "#808080", + "sectionSeparatorColor": "#e0e0e0", + "separatorColor": "#808080", + "titleDropShadowColor": "#ffffff", + "titleTextColor": "#4a494a", + "uppercaseLabels": true + }, + "sidebarIcons": { + "iconColor": "#4f4e4f", + "shadowColor": "#fbfbfb", + "useSystemFolderIcons": false + }, + "whatsNewDialog": { + "backgroundColor": "#ffffff", + "closeButtonColor": "#444444", + "contentTextColor": "#0a0a0a", + "headerDecorationColor": "#e8b800", + "headerTextColor": "#0a0a0a", + "linkColor": "#e8b800", + "versionTextColor": "#858585" } } From 5058f47a20c65a774e545500fcbf338e4a10d274 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Wed, 4 Mar 2026 17:51:35 +0100 Subject: [PATCH 22/26] Tweak default dark YACReaderLibrary theme --- YACReaderLibrary/themes/builtin_dark.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/YACReaderLibrary/themes/builtin_dark.json b/YACReaderLibrary/themes/builtin_dark.json index 45fbcc64..6a9a7a28 100644 --- a/YACReaderLibrary/themes/builtin_dark.json +++ b/YACReaderLibrary/themes/builtin_dark.json @@ -4,16 +4,16 @@ "textColor": "#888888" }, "comicsViewTable": { - "alternateBackgroundColor": "#2e2e2e", - "backgroundColor": "#2a2a2a", + "alternateBackgroundColor": "#2c2c2c", + "backgroundColor": "#232323", "headerBackgroundColor": "#2a2a2a", "headerBorderColor": "#1f1f1f", "headerGradientColor": "#252525", "headerTextColor": "#dddddd", "itemBorderBottomColor": "#1f1f1f", - "itemBorderBottomWidth": 1, + "itemBorderBottomWidth": 0, "itemBorderTopColor": "#353535", - "itemBorderTopWidth": 1, + "itemBorderTopWidth": 0, "itemTextColor": "#dddddd", "selectedColor": "#555555", "selectedTextColor": "#ffffff", @@ -21,7 +21,7 @@ "starRatingSelectedColor": "#ffffff" }, "comicsViewToolbar": { - "backgroundColor": "#2a2a2a", + "backgroundColor": "#1f1f1f", "checkedBackgroundColor": "#555555", "iconColor": "#dddddd", "separatorColor": "#444444" @@ -49,7 +49,7 @@ "cellColorWithBackground": "#99212121", "continueReadingBackgroundColor": "#88000000", "continueReadingColor": "#ffffff", - "currentComicBackgroundColor": "#88000000", + "currentComicBackgroundColor": "#55000000", "favCheckedColor": "#e84852", "favUncheckedColor": "#1c1c1c", "infoBackgroundColor": "#2e2e2e", @@ -94,7 +94,7 @@ "textColor": "#dddfdf" }, "mainToolbar": { - "backgroundColor": "#2a2a2a", + "backgroundColor": "#1f1f1f", "dividerColor": "#555555", "folderNameColor": "#dddddd", "iconColor": "#dddddd", From 46661becaf0af3af7cd8c8b12d5cba2a665ce4b9 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 5 Mar 2026 08:22:04 +0100 Subject: [PATCH 23/26] Implement theme pickers + importing --- YACReader/options_dialog.cpp | 1 + YACReaderLibrary/options_dialog.cpp | 1 + common/themes/appearance_config_images.qrc | 1 + common/themes/appearance_tab_widget.cpp | 225 +++++++++++++++++- common/themes/appearance_tab_widget.h | 29 +++ common/themes/theme_manager.h | 1 + .../appearance_config/theme-mode-custom.svg | 36 +++ 7 files changed, 289 insertions(+), 5 deletions(-) create mode 100644 images/appearance_config/theme-mode-custom.svg diff --git a/YACReader/options_dialog.cpp b/YACReader/options_dialog.cpp index c39e7115..43f50e67 100644 --- a/YACReader/options_dialog.cpp +++ b/YACReader/options_dialog.cpp @@ -210,6 +210,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) auto *pageAppearance = new AppearanceTabWidget( ThemeManager::instance().getAppearanceConfiguration(), + ThemeManager::instance().getRepository(), []() { return ThemeManager::instance().getCurrentTheme().sourceJson; }, [](const QJsonObject &json) { ThemeManager::instance().setTheme(makeTheme(json)); }, this); diff --git a/YACReaderLibrary/options_dialog.cpp b/YACReaderLibrary/options_dialog.cpp index 1087d8ad..f2cdb4bf 100644 --- a/YACReaderLibrary/options_dialog.cpp +++ b/YACReaderLibrary/options_dialog.cpp @@ -419,6 +419,7 @@ QWidget *OptionsDialog::createAppearanceTab() { return new AppearanceTabWidget( ThemeManager::instance().getAppearanceConfiguration(), + ThemeManager::instance().getRepository(), []() { return ThemeManager::instance().getCurrentTheme().sourceJson; }, [](const QJsonObject &json) { ThemeManager::instance().setTheme(makeTheme(json)); }, this); diff --git a/common/themes/appearance_config_images.qrc b/common/themes/appearance_config_images.qrc index 3284bda9..b67edae7 100644 --- a/common/themes/appearance_config_images.qrc +++ b/common/themes/appearance_config_images.qrc @@ -3,5 +3,6 @@ ../../images/appearance_config/theme-mode-system.svg ../../images/appearance_config/theme-mode-light.svg ../../images/appearance_config/theme-mode-dark.svg + ../../images/appearance_config/theme-mode-custom.svg diff --git a/common/themes/appearance_tab_widget.cpp b/common/themes/appearance_tab_widget.cpp index 8563fb05..9dcb49c2 100644 --- a/common/themes/appearance_tab_widget.cpp +++ b/common/themes/appearance_tab_widget.cpp @@ -2,39 +2,58 @@ #include "appearance_configuration.h" #include "theme_editor_dialog.h" +#include "theme_repository.h" #include +#include +#include #include #include +#include #include #include #include #include +// Select the item in combo whose UserRole data matches id (no-op if not found). +static void selectInCombo(QComboBox *combo, const QString &id) +{ + for (int i = 0; i < combo->count(); ++i) { + if (combo->itemData(i).toString() == id) { + combo->setCurrentIndex(i); + return; + } + } +} + AppearanceTabWidget::AppearanceTabWidget( AppearanceConfiguration *config, + ThemeRepository *repository, std::function currentThemeJson, std::function applyTheme, QWidget *parent) - : QWidget(parent), config(config), currentThemeJson(std::move(currentThemeJson)), applyTheme(std::move(applyTheme)) + : QWidget(parent), config(config), repository(repository), currentThemeJson(std::move(currentThemeJson)), applyTheme(std::move(applyTheme)) { - // Color scheme selector + // --- Color scheme selector --- auto *modeBox = new QGroupBox(tr("Color scheme"), this); auto *modeLayout = new QHBoxLayout(); auto *sysBtn = new QToolButton(); auto *lightBtn = new QToolButton(); auto *darkBtn = new QToolButton(); + auto *customBtn = new QToolButton(); sysBtn->setText(tr("System")); lightBtn->setText(tr("Light")); darkBtn->setText(tr("Dark")); + customBtn->setText(tr("Custom")); sysBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-system.svg")); lightBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-light.svg")); darkBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-dark.svg")); + customBtn->setIcon(QIcon(":/images/appearance_config/theme-mode-custom.svg")); - for (auto *btn : { sysBtn, lightBtn, darkBtn }) { + for (auto *btn : { sysBtn, lightBtn, darkBtn, customBtn }) { btn->setCheckable(true); btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); btn->setIconSize(QSize(93, 58)); @@ -45,6 +64,7 @@ AppearanceTabWidget::AppearanceTabWidget( modeGroup->addButton(sysBtn, static_cast(ThemeMode::FollowSystem)); modeGroup->addButton(lightBtn, static_cast(ThemeMode::Light)); modeGroup->addButton(darkBtn, static_cast(ThemeMode::Dark)); + modeGroup->addButton(customBtn, static_cast(ThemeMode::ForcedTheme)); modeGroup->setExclusive(true); if (this->config) { @@ -54,18 +74,102 @@ AppearanceTabWidget::AppearanceTabWidget( } connect(modeGroup, &QButtonGroup::idClicked, this, [this](int id) { - if (this->config) + if (this->config) { this->config->setMode(static_cast(id)); + updateModeRows(); + } }); modeLayout->addStretch(); modeLayout->addWidget(sysBtn); modeLayout->addWidget(lightBtn); modeLayout->addWidget(darkBtn); + modeLayout->addWidget(customBtn); modeLayout->addStretch(); modeBox->setLayout(modeLayout); - // Theme editor + // --- Theme selection --- + // Each row: [label fixed] [combo expanding] [Remove btn] + // Rows are shown/hidden based on mode — only relevant ones are visible. + auto makeRow = [](const QString &label, QComboBox *&combo, QPushButton *&deleteBtn) { + auto *row = new QWidget(); + auto *hl = new QHBoxLayout(row); + hl->setContentsMargins(0, 0, 0, 0); + + auto *lbl = new QLabel(label); + lbl->setFixedWidth(52); + + combo = new QComboBox(); + combo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + deleteBtn = new QPushButton(tr("Remove")); + deleteBtn->setEnabled(false); + deleteBtn->setToolTip(tr("Remove this user-imported theme")); + + hl->addWidget(lbl); + hl->addWidget(combo); + hl->addWidget(deleteBtn); + return row; + }; + + lightRow = makeRow(tr("Light:"), lightCombo, lightDeleteBtn); + darkRow = makeRow(tr("Dark:"), darkCombo, darkDeleteBtn); + customRow = makeRow(tr("Custom:"), customCombo, customDeleteBtn); + + auto *importBtn = new QPushButton(tr("Import theme...")); + + auto *themeSelBox = new QGroupBox(tr("Theme"), this); + auto *themeSelLayout = new QVBoxLayout(); + themeSelLayout->addWidget(lightRow); + themeSelLayout->addWidget(darkRow); + themeSelLayout->addWidget(customRow); + themeSelLayout->addWidget(importBtn, 0, Qt::AlignRight); + themeSelBox->setLayout(themeSelLayout); + + // Populate combos and set initial row visibility + if (this->config && this->repository) { + const auto &sel = this->config->selection(); + populateCombo(lightCombo, ThemeVariant::Light, sel.lightThemeId); + populateCombo(darkCombo, ThemeVariant::Dark, sel.darkThemeId); + populateCombo(customCombo, std::nullopt, sel.fixedThemeId); + updateDeleteButton(lightCombo, lightDeleteBtn); + updateDeleteButton(darkCombo, darkDeleteBtn); + updateDeleteButton(customCombo, customDeleteBtn); + updateModeRows(); + } + + // Combo selection → update config (live theme preview via selectionChanged chain) + connect(lightCombo, &QComboBox::currentIndexChanged, this, [this](int) { + if (!this->config) + return; + this->config->setLightThemeId(lightCombo->currentData().toString()); + updateDeleteButton(lightCombo, lightDeleteBtn); + }); + connect(darkCombo, &QComboBox::currentIndexChanged, this, [this](int) { + if (!this->config) + return; + this->config->setDarkThemeId(darkCombo->currentData().toString()); + updateDeleteButton(darkCombo, darkDeleteBtn); + }); + connect(customCombo, &QComboBox::currentIndexChanged, this, [this](int) { + if (!this->config) + return; + this->config->setFixedThemeId(customCombo->currentData().toString()); + updateDeleteButton(customCombo, customDeleteBtn); + }); + + // Delete buttons + connect(lightDeleteBtn, &QPushButton::clicked, this, + [this]() { deleteTheme(lightCombo, lightDeleteBtn); }); + connect(darkDeleteBtn, &QPushButton::clicked, this, + [this]() { deleteTheme(darkCombo, darkDeleteBtn); }); + connect(customDeleteBtn, &QPushButton::clicked, this, + [this]() { deleteTheme(customCombo, customDeleteBtn); }); + + // Import + connect(importBtn, &QPushButton::clicked, this, &AppearanceTabWidget::importTheme); + + // --- Theme editor --- auto *themeEditorBox = new QGroupBox(tr("Theme editor"), this); auto *themeEditorLayout = new QVBoxLayout(); auto *openBtn = new QPushButton(tr("Open Theme Editor...")); @@ -93,6 +197,117 @@ AppearanceTabWidget::AppearanceTabWidget( auto *layout = new QVBoxLayout(this); layout->addWidget(modeBox); + layout->addWidget(themeSelBox); layout->addWidget(themeEditorBox); layout->addStretch(); } + +void AppearanceTabWidget::populateCombo(QComboBox *combo, + std::optional variantFilter, + const QString &selectedId) +{ + QSignalBlocker blocker(combo); + combo->clear(); + if (!repository) + return; + + for (const auto &entry : repository->availableThemes()) { + if (variantFilter && entry.variant != *variantFilter) + continue; + combo->addItem(entry.displayName, entry.id); + } + + // Restore selection; fall back to first item if the saved ID is no longer present + for (int i = 0; i < combo->count(); ++i) { + if (combo->itemData(i).toString() == selectedId) { + combo->setCurrentIndex(i); + return; + } + } + if (combo->count() > 0) + combo->setCurrentIndex(0); +} + +void AppearanceTabWidget::repopulateCombos() +{ + if (!config) + return; + const auto &sel = config->selection(); + populateCombo(lightCombo, ThemeVariant::Light, sel.lightThemeId); + populateCombo(darkCombo, ThemeVariant::Dark, sel.darkThemeId); + populateCombo(customCombo, std::nullopt, sel.fixedThemeId); + updateDeleteButton(lightCombo, lightDeleteBtn); + updateDeleteButton(darkCombo, darkDeleteBtn); + updateDeleteButton(customCombo, customDeleteBtn); +} + +void AppearanceTabWidget::updateDeleteButton(QComboBox *combo, QPushButton *btn) +{ + const QString id = combo->currentData().toString(); + btn->setEnabled(!id.isEmpty() && id.startsWith(QLatin1String("user/"))); +} + +void AppearanceTabWidget::updateModeRows() +{ + if (!config) + return; + const auto mode = config->selection().mode; + lightRow->setVisible(mode == ThemeMode::FollowSystem || mode == ThemeMode::Light); + darkRow->setVisible(mode == ThemeMode::FollowSystem || mode == ThemeMode::Dark); + customRow->setVisible(mode == ThemeMode::ForcedTheme); +} + +void AppearanceTabWidget::importTheme() +{ + const QString path = QFileDialog::getOpenFileName( + this, tr("Import theme"), QString(), tr("JSON files (*.json);;All files (*)")); + if (path.isEmpty() || !repository) + return; + + const QString id = repository->importThemeFromFile(path); + if (id.isEmpty()) { + QMessageBox::warning(this, tr("Import failed"), + tr("Could not import theme from:\n%1").arg(path)); + return; + } + + // Detect variant of the imported theme to auto-select it in the right combo + const QJsonObject json = repository->loadThemeJson(id); + const bool isLight = (json["meta"].toObject()["variant"].toString() == "light"); + + repopulateCombos(); + + // Select in the appropriate combo → triggers currentIndexChanged → config update + if (isLight) + selectInCombo(lightCombo, id); + else + selectInCombo(darkCombo, id); + + // If in Custom mode, also select in customCombo + if (config && config->selection().mode == ThemeMode::ForcedTheme) + selectInCombo(customCombo, id); +} + +void AppearanceTabWidget::deleteTheme(QComboBox *combo, QPushButton *deleteBtn) +{ + if (!repository) + return; + const QString id = combo->currentData().toString(); + if (!id.startsWith(QLatin1String("user/"))) + return; + + repository->deleteUserTheme(id); + repopulateCombos(); + + // repopulateCombos() blocked signals; manually push the new selection into config + // so the theme resolves correctly (important when the deleted theme was active). + const QString newId = combo->currentData().toString(); + if (combo == lightCombo && config) + config->setLightThemeId(newId); + else if (combo == darkCombo && config) + config->setDarkThemeId(newId); + else if (combo == customCombo && config) + config->setFixedThemeId(newId); + + updateDeleteButton(combo, deleteBtn); +} diff --git a/common/themes/appearance_tab_widget.h b/common/themes/appearance_tab_widget.h index cbccb88b..98195058 100644 --- a/common/themes/appearance_tab_widget.h +++ b/common/themes/appearance_tab_widget.h @@ -1,13 +1,19 @@ #ifndef APPEARANCE_TAB_WIDGET_H #define APPEARANCE_TAB_WIDGET_H +#include "theme_variant.h" + #include #include #include #include +#include class AppearanceConfiguration; +class QComboBox; +class QPushButton; class ThemeEditorDialog; +class ThemeRepository; class AppearanceTabWidget : public QWidget { @@ -15,15 +21,38 @@ class AppearanceTabWidget : public QWidget public: explicit AppearanceTabWidget( AppearanceConfiguration *config, + ThemeRepository *repository, std::function currentThemeJson, std::function applyTheme, QWidget *parent = nullptr); private: AppearanceConfiguration *config; + ThemeRepository *repository; std::function currentThemeJson; std::function applyTheme; QPointer themeEditor; + + // One row per picker; shown/hidden based on active mode + QWidget *lightRow = nullptr; + QWidget *darkRow = nullptr; + QWidget *customRow = nullptr; + + QComboBox *lightCombo = nullptr; + QComboBox *darkCombo = nullptr; + QComboBox *customCombo = nullptr; + + QPushButton *lightDeleteBtn = nullptr; + QPushButton *darkDeleteBtn = nullptr; + QPushButton *customDeleteBtn = nullptr; + + // Populate a combo with themes, filtered strictly by variant (or all if nullopt). + void populateCombo(QComboBox *combo, std::optional variantFilter, const QString &selectedId); + void repopulateCombos(); + void updateDeleteButton(QComboBox *combo, QPushButton *btn); + void updateModeRows(); + void importTheme(); + void deleteTheme(QComboBox *combo, QPushButton *deleteBtn); }; #endif // APPEARANCE_TAB_WIDGET_H diff --git a/common/themes/theme_manager.h b/common/themes/theme_manager.h index 42b8d0d0..7ffbeea7 100644 --- a/common/themes/theme_manager.h +++ b/common/themes/theme_manager.h @@ -25,6 +25,7 @@ public: const Theme &getCurrentTheme() const { return currentTheme; } AppearanceConfiguration *getAppearanceConfiguration() const { return config; } + ThemeRepository *getRepository() const { return repository; } signals: void themeChanged(); diff --git a/images/appearance_config/theme-mode-custom.svg b/images/appearance_config/theme-mode-custom.svg new file mode 100644 index 00000000..227cd5da --- /dev/null +++ b/images/appearance_config/theme-mode-custom.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From df03b1c6b0000608ce67dd9cd7bdc81b0d835187 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 5 Mar 2026 09:48:21 +0100 Subject: [PATCH 24/26] Print clang-format version in CI --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d866bd15..d3ba5313 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,9 @@ jobs: - name: Install dependencies run: brew install clang-format + - name: Print clang-format version + run: clang-format --version + - name: Run clang-format run: | find . \( -name '*.h' -or -name '*.cpp' -or -name '*.c' -or -name '*.mm' -or -name '*.m' \) -print0 | xargs -0 clang-format -style=file -i From d8678bcf95b71191cdde9a5b3ac307c163525d86 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 5 Mar 2026 10:54:03 +0100 Subject: [PATCH 25/26] Update .clang-format --- .clang-format | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index 61441ef6..d68fa440 100644 --- a/.clang-format +++ b/.clang-format @@ -5,7 +5,8 @@ Standard: Cpp11 ColumnLimit: 0 # We want a space between the type and the star for pointer types. -PointerBindsToType: false +DerivePointerAlignment: false +PointerAlignment: Right # We use template< without space. SpaceAfterTemplateKeyword: false @@ -43,7 +44,7 @@ NamespaceIndentation: None # The coding style does not specify the following, but this is what gives # results closest to the existing code. AlignAfterOpenBracket: true -AlwaysBreakTemplateDeclarations: true +BreakTemplateDeclarations: Yes # Ideally we should also allow less short function in a single line, but # clang-format does not handle that. @@ -60,3 +61,6 @@ ForEachMacros: [ foreach, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENC # Break constructor initializers before the colon and after the commas. BreakConstructorInitializers: BeforeColon + +# Empty blocks should be {} +SpaceInEmptyBraces: Always From a876f339027e8b0387082b3e17b24b9f1e44e895 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 5 Mar 2026 10:54:41 +0100 Subject: [PATCH 26/26] Format --- YACReader/themes/theme_factory.cpp | 52 +++++++------- YACReaderLibrary/db/comic_model.cpp | 2 +- YACReaderLibrary/db/folder_model.cpp | 2 +- YACReaderLibrary/db/query_lexer.h | 4 +- YACReaderLibrary/db/query_parser.cpp | 10 +-- YACReaderLibrary/db/reading_list_model.cpp | 4 +- YACReaderLibrary/themes/theme_factory.cpp | 72 +++++++++---------- common/themes/icon_utils.cpp | 4 +- common/themes/icon_utils.h | 8 +-- common/themes/theme_editor_dialog.cpp | 4 +- common/themes/theme_manager.cpp | 2 +- common/themes/theme_repository.cpp | 8 +-- .../actions_shortcuts_model.cpp | 2 +- .../concurrent_queue_test.cpp | 10 +-- 14 files changed, 92 insertions(+), 92 deletions(-) diff --git a/YACReader/themes/theme_factory.cpp b/YACReader/themes/theme_factory.cpp index 7a19d4f8..a0cb207f 100644 --- a/YACReader/themes/theme_factory.cpp +++ b/YACReader/themes/theme_factory.cpp @@ -231,11 +231,11 @@ Theme makeTheme(const QJsonObject &json) if (json.contains("toolbar")) { const auto t = json["toolbar"].toObject(); auto &tp = p.toolbarParams; - tp.iconColor = colorFromJson(t, "iconColor", tp.iconColor); - tp.iconDisabledColor = colorFromJson(t, "iconDisabledColor", tp.iconDisabledColor); - tp.iconCheckedColor = colorFromJson(t, "iconCheckedColor", tp.iconCheckedColor); - tp.backgroundColor = colorFromJson(t, "backgroundColor", tp.backgroundColor); - tp.separatorColor = colorFromJson(t, "separatorColor", tp.separatorColor); + tp.iconColor = colorFromJson(t, "iconColor", tp.iconColor); + tp.iconDisabledColor = colorFromJson(t, "iconDisabledColor", tp.iconDisabledColor); + tp.iconCheckedColor = colorFromJson(t, "iconCheckedColor", tp.iconCheckedColor); + tp.backgroundColor = colorFromJson(t, "backgroundColor", tp.backgroundColor); + tp.separatorColor = colorFromJson(t, "separatorColor", tp.separatorColor); tp.checkedButtonColor = colorFromJson(t, "checkedButtonColor", tp.checkedButtonColor); tp.menuIndicatorColor = colorFromJson(t, "menuIndicatorColor", tp.menuIndicatorColor); } @@ -244,43 +244,43 @@ Theme makeTheme(const QJsonObject &json) const auto v = json["viewer"].toObject(); auto &vp = p.viewerParams; vp.defaultBackgroundColor = colorFromJson(v, "defaultBackgroundColor", vp.defaultBackgroundColor); - vp.defaultTextColor = colorFromJson(v, "defaultTextColor", vp.defaultTextColor); - vp.infoBackgroundColor = colorFromJson(v, "infoBackgroundColor", vp.infoBackgroundColor); - vp.infoTextColor = colorFromJson(v, "infoTextColor", vp.infoTextColor); + vp.defaultTextColor = colorFromJson(v, "defaultTextColor", vp.defaultTextColor); + vp.infoBackgroundColor = colorFromJson(v, "infoBackgroundColor", vp.infoBackgroundColor); + vp.infoTextColor = colorFromJson(v, "infoTextColor", vp.infoTextColor); } if (json.contains("goToFlowWidget")) { const auto g = json["goToFlowWidget"].toObject(); auto &gp = p.goToFlowWidgetParams; - gp.flowBackgroundColor = colorFromJson(g, "flowBackgroundColor", gp.flowBackgroundColor); - gp.flowTextColor = colorFromJson(g, "flowTextColor", gp.flowTextColor); + gp.flowBackgroundColor = colorFromJson(g, "flowBackgroundColor", gp.flowBackgroundColor); + gp.flowTextColor = colorFromJson(g, "flowTextColor", gp.flowTextColor); gp.toolbarBackgroundColor = colorFromJson(g, "toolbarBackgroundColor", gp.toolbarBackgroundColor); - gp.sliderBorderColor = colorFromJson(g, "sliderBorderColor", gp.sliderBorderColor); - gp.sliderGrooveColor = colorFromJson(g, "sliderGrooveColor", gp.sliderGrooveColor); - gp.sliderHandleColor = colorFromJson(g, "sliderHandleColor", gp.sliderHandleColor); - gp.editBorderColor = colorFromJson(g, "editBorderColor", gp.editBorderColor); - gp.editBackgroundColor = colorFromJson(g, "editBackgroundColor", gp.editBackgroundColor); - gp.editTextColor = colorFromJson(g, "editTextColor", gp.editTextColor); - gp.labelTextColor = colorFromJson(g, "labelTextColor", gp.labelTextColor); - gp.iconColor = colorFromJson(g, "iconColor", gp.iconColor); + gp.sliderBorderColor = colorFromJson(g, "sliderBorderColor", gp.sliderBorderColor); + gp.sliderGrooveColor = colorFromJson(g, "sliderGrooveColor", gp.sliderGrooveColor); + gp.sliderHandleColor = colorFromJson(g, "sliderHandleColor", gp.sliderHandleColor); + gp.editBorderColor = colorFromJson(g, "editBorderColor", gp.editBorderColor); + gp.editBackgroundColor = colorFromJson(g, "editBackgroundColor", gp.editBackgroundColor); + gp.editTextColor = colorFromJson(g, "editTextColor", gp.editTextColor); + gp.labelTextColor = colorFromJson(g, "labelTextColor", gp.labelTextColor); + gp.iconColor = colorFromJson(g, "iconColor", gp.iconColor); } if (json.contains("helpAboutDialog")) { const auto h = json["helpAboutDialog"].toObject(); p.helpAboutDialogParams.headingColor = colorFromJson(h, "headingColor", p.helpAboutDialogParams.headingColor); - p.helpAboutDialogParams.linkColor = colorFromJson(h, "linkColor", p.helpAboutDialogParams.linkColor); + p.helpAboutDialogParams.linkColor = colorFromJson(h, "linkColor", p.helpAboutDialogParams.linkColor); } if (json.contains("whatsNewDialog")) { const auto w = json["whatsNewDialog"].toObject(); auto &wn = p.whatsNewDialogParams; - wn.backgroundColor = colorFromJson(w, "backgroundColor", wn.backgroundColor); - wn.headerTextColor = colorFromJson(w, "headerTextColor", wn.headerTextColor); - wn.versionTextColor = colorFromJson(w, "versionTextColor", wn.versionTextColor); - wn.contentTextColor = colorFromJson(w, "contentTextColor", wn.contentTextColor); - wn.linkColor = colorFromJson(w, "linkColor", wn.linkColor); - wn.closeButtonColor = colorFromJson(w, "closeButtonColor", wn.closeButtonColor); - wn.headerDecorationColor = colorFromJson(w, "headerDecorationColor",wn.headerDecorationColor); + wn.backgroundColor = colorFromJson(w, "backgroundColor", wn.backgroundColor); + wn.headerTextColor = colorFromJson(w, "headerTextColor", wn.headerTextColor); + wn.versionTextColor = colorFromJson(w, "versionTextColor", wn.versionTextColor); + wn.contentTextColor = colorFromJson(w, "contentTextColor", wn.contentTextColor); + wn.linkColor = colorFromJson(w, "linkColor", wn.linkColor); + wn.closeButtonColor = colorFromJson(w, "closeButtonColor", wn.closeButtonColor); + wn.headerDecorationColor = colorFromJson(w, "headerDecorationColor", wn.headerDecorationColor); } if (json.contains("shortcutsIcons")) { diff --git a/YACReaderLibrary/db/comic_model.cpp b/YACReaderLibrary/db/comic_model.cpp index b0a40129..d85339b0 100644 --- a/YACReaderLibrary/db/comic_model.cpp +++ b/YACReaderLibrary/db/comic_model.cpp @@ -378,7 +378,7 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const Qt::ItemFlags ComicModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return {}; + return { }; if (index.column() == ComicModel::Rating) return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index a160ecd6..17b70cf6 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -434,7 +434,7 @@ QVariant FolderModel::data(const QModelIndex &index, int role) const Qt::ItemFlags FolderModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return {}; + return { }; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled; } diff --git a/YACReaderLibrary/db/query_lexer.h b/YACReaderLibrary/db/query_lexer.h index d3136d0b..ece898e9 100644 --- a/YACReaderLibrary/db/query_lexer.h +++ b/YACReaderLibrary/db/query_lexer.h @@ -36,8 +36,8 @@ public: } private: - Type _type {}; - std::string _lexeme {}; + Type _type { }; + std::string _lexeme { }; }; class QueryLexer diff --git a/YACReaderLibrary/db/query_parser.cpp b/YACReaderLibrary/db/query_parser.cpp index 35fd77e3..d6691930 100644 --- a/YACReaderLibrary/db/query_parser.cpp +++ b/YACReaderLibrary/db/query_parser.cpp @@ -316,9 +316,9 @@ QueryParser::TreeNode QueryParser::expression() } auto right = token(true); - return TreeNode("expression", { TreeNode(toLower(left), {}), TreeNode(right, {}) }, expOperator); + return TreeNode("expression", { TreeNode(toLower(left), { }), TreeNode(right, { }) }, expOperator); } else { - return TreeNode("expression", { TreeNode("all", {}), TreeNode(left, {}) }); + return TreeNode("expression", { TreeNode("all", { }), TreeNode(left, { }) }); } } @@ -328,12 +328,12 @@ QueryParser::TreeNode QueryParser::expression() QueryParser::TreeNode QueryParser::baseToken() { if (tokenType() == Token::Type::quotedWord) { - return TreeNode("expression", { TreeNode("all", {}), TreeNode(token(true), {}) }); + return TreeNode("expression", { TreeNode("all", { }), TreeNode(token(true), { }) }); } if (tokenType() == Token::Type::word) { - return TreeNode("expression", { TreeNode("all", {}), TreeNode(token(true), {}) }); + return TreeNode("expression", { TreeNode("all", { }), TreeNode(token(true), { }) }); } - return TreeNode("expression", { TreeNode("all", {}), TreeNode(token(true), {}) }); + return TreeNode("expression", { TreeNode("all", { }), TreeNode(token(true), { }) }); } diff --git a/YACReaderLibrary/db/reading_list_model.cpp b/YACReaderLibrary/db/reading_list_model.cpp index 856fa87b..55aa626e 100644 --- a/YACReaderLibrary/db/reading_list_model.cpp +++ b/YACReaderLibrary/db/reading_list_model.cpp @@ -101,11 +101,11 @@ QVariant ReadingListModel::data(const QModelIndex &index, int role) const Qt::ItemFlags ReadingListModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return {}; + return { }; auto item = static_cast(index.internalPointer()); if (typeid(*item) == typeid(ReadingListSeparatorItem)) - return {}; + return { }; if (typeid(*item) == typeid(ReadingListItem) && static_cast(item)->parent->getId() != 0) return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled; // only sublists are dragable diff --git a/YACReaderLibrary/themes/theme_factory.cpp b/YACReaderLibrary/themes/theme_factory.cpp index dbe90109..eaba930d 100644 --- a/YACReaderLibrary/themes/theme_factory.cpp +++ b/YACReaderLibrary/themes/theme_factory.cpp @@ -359,20 +359,20 @@ Theme makeTheme(const ThemeParams ¶ms) theme.metadataScraperDialog.scraperScrollLabelScrollAreaQSS = t.scraperScrollLabelScrollAreaQSS.arg(msd.contentBackgroundColor.name(), msd.tableScrollHandleColor.name(), msd.tableScrollBackgroundColor.name()); theme.metadataScraperDialog.scraperTableViewQSS = t.scraperTableViewQSS - .arg(msd.tableHeaderTextColor.name(), - msd.tableAltBackgroundColor.name(), - msd.tableBackgroundColor.name(), - msd.tableSelectedColor.name(), - msd.tableHeaderBackgroundColor.name(), - msd.tableHeaderBorderColor.name(), - msd.tableHeaderTextColor.name(), - msd.tableSectionBorderDark.name(), - msd.tableSectionBorderLight.name(), - msd.tableScrollHandleColor.name(), - msd.tableScrollBackgroundColor.name(), - recolor(":/images/comic_vine/downArrow.svg", msd.downArrowColor), - recolor(":/images/comic_vine/upArrow.svg", msd.upArrowColor), - msd.tableHeaderGradientColor.name()); + .arg(msd.tableHeaderTextColor.name(), + msd.tableAltBackgroundColor.name(), + msd.tableBackgroundColor.name(), + msd.tableSelectedColor.name(), + msd.tableHeaderBackgroundColor.name(), + msd.tableHeaderBorderColor.name(), + msd.tableHeaderTextColor.name(), + msd.tableSectionBorderDark.name(), + msd.tableSectionBorderLight.name(), + msd.tableScrollHandleColor.name(), + msd.tableScrollBackgroundColor.name(), + recolor(":/images/comic_vine/downArrow.svg", msd.downArrowColor), + recolor(":/images/comic_vine/upArrow.svg", msd.upArrowColor), + msd.tableHeaderGradientColor.name()); theme.metadataScraperDialog.dialogQSS = t.dialogQSS.arg(msd.dialogBackgroundColor.name()); theme.metadataScraperDialog.dialogButtonsQSS = t.dialogButtonsQSS.arg(msd.buttonBorderColor.name(), msd.buttonBackgroundColor.name(), msd.buttonTextColor.name()); @@ -470,19 +470,19 @@ Theme makeTheme(const ThemeParams ¶ms) // ComicsViewTable const auto &cvta = params.comicsViewTableParams; theme.comicsViewTable.tableViewQSS = cvta.t.tableViewQSS - .arg(cvta.alternateBackgroundColor.name(), - cvta.backgroundColor.name(), - cvta.headerBackgroundColor.name(), - cvta.headerBorderColor.name(), - cvta.headerGradientColor.name(), - cvta.itemBorderBottomColor.name(), - cvta.itemBorderTopColor.name(), - cvta.itemTextColor.name(), - cvta.selectedColor.name(), - cvta.selectedTextColor.name(), - cvta.headerTextColor.name(), - QString::number(cvta.itemBorderBottomWidth), - QString::number(cvta.itemBorderTopWidth)); + .arg(cvta.alternateBackgroundColor.name(), + cvta.backgroundColor.name(), + cvta.headerBackgroundColor.name(), + cvta.headerBorderColor.name(), + cvta.headerGradientColor.name(), + cvta.itemBorderBottomColor.name(), + cvta.itemBorderTopColor.name(), + cvta.itemTextColor.name(), + cvta.selectedColor.name(), + cvta.selectedTextColor.name(), + cvta.headerTextColor.name(), + QString::number(cvta.itemBorderBottomWidth), + QString::number(cvta.itemBorderTopWidth)); theme.comicsViewTable.starRatingColor = cvta.starRatingColor; theme.comicsViewTable.starRatingSelectedColor = cvta.starRatingSelectedColor; // end ComicsViewTable @@ -648,15 +648,15 @@ Theme makeTheme(const ThemeParams ¶ms) theme.navigationTree.branchOpenIconSelectedPath = recoloredSvgToThemeFile(":/images/sidebar/branch-open.svg", nt.branchIndicatorSelectedColor, params.meta.id, { .suffix = "_selected" }); theme.navigationTree.navigationTreeQSS = nt.t.navigationTreeQSS - .arg(nt.textColor.name(), - nt.selectionBackgroundColor.name(), - nt.scrollBackgroundColor.name(), - nt.scrollHandleColor.name(), - nt.selectedTextColor.name(), - theme.navigationTree.branchClosedIconPath, - theme.navigationTree.branchOpenIconPath, - theme.navigationTree.branchClosedIconSelectedPath, - theme.navigationTree.branchOpenIconSelectedPath); + .arg(nt.textColor.name(), + nt.selectionBackgroundColor.name(), + nt.scrollBackgroundColor.name(), + nt.scrollHandleColor.name(), + nt.selectedTextColor.name(), + theme.navigationTree.branchClosedIconPath, + theme.navigationTree.branchOpenIconPath, + theme.navigationTree.branchClosedIconSelectedPath, + theme.navigationTree.branchOpenIconSelectedPath); theme.navigationTree.folderIndicatorColor = nt.folderIndicatorColor; // Folder icon — normal and selected states with independent colors diff --git a/common/themes/icon_utils.cpp b/common/themes/icon_utils.cpp index 680a78a8..395347dd 100644 --- a/common/themes/icon_utils.cpp +++ b/common/themes/icon_utils.cpp @@ -28,7 +28,7 @@ QString readSvg(const QString &resourcePath) QFile in(resourcePath); if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open SVG resource:" << resourcePath; - return {}; + return { }; } QString svg = QString::fromUtf8(in.readAll()); @@ -53,7 +53,7 @@ QString writeSvg(const QString &svg, const QString &resourcePath, const QString QFile out(outPath); if (!out.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { qWarning() << "Failed to write SVG:" << outPath; - return {}; + return { }; } out.write(svg.toUtf8()); diff --git a/common/themes/icon_utils.h b/common/themes/icon_utils.h index 48b4462c..aef05bd7 100644 --- a/common/themes/icon_utils.h +++ b/common/themes/icon_utils.h @@ -14,23 +14,23 @@ struct RecolorOptions { }; QString readSvg(const QString &resourcePath); -QString writeSvg(const QString &svg, const QString &resourcePath, const QString &themeName, const RecolorOptions &options = {}); +QString writeSvg(const QString &svg, const QString &resourcePath, const QString &themeName, const RecolorOptions &options = { }); QString recolorSvgXML(QString &svg, const QString &placeHolder, const QColor &color); QString recoloredSvgToThemeFile(const QString &resourcePath, const QColor &color, // #f0f (magenta) const QString &themeName, - const RecolorOptions &options = {}); + const RecolorOptions &options = { }); QString recoloredSvgToThemeFile(const QString &resourcePath, const QColor &color1, // #f0f (magenta) const QColor &color2, // #0ff (cyan) const QString &themeName, - const RecolorOptions &options = {}); + const RecolorOptions &options = { }); QString recoloredSvgToThemeFile(const QString &resourcePath, const QColor &color1, // #f0f (magenta) const QColor &color2, // #0ff (cyan) const QColor &color3, // #ff0 (yellow) const QString &themeName, - const RecolorOptions &options = {}); + const RecolorOptions &options = { }); #endif // ICON_UTILS_H diff --git a/common/themes/theme_editor_dialog.cpp b/common/themes/theme_editor_dialog.cpp index 4f4ef7d4..72d03327 100644 --- a/common/themes/theme_editor_dialog.cpp +++ b/common/themes/theme_editor_dialog.cpp @@ -133,7 +133,7 @@ ThemeEditorDialog::ThemeEditorDialog(const QJsonObject ¶ms, QWidget *parent) tree->setUniformRowHeights(true); tree->setAlternatingRowColors(true); - populate(nullptr, params, {}); + populate(nullptr, params, { }); tree->expandAll(); connect(expandBtn, &QPushButton::clicked, tree, &QTreeWidget::expandAll); @@ -425,7 +425,7 @@ void ThemeEditorDialog::loadFromFile() params = doc.object(); syncMetaFromParams(); tree->clear(); - populate(nullptr, params, {}); + populate(nullptr, params, { }); tree->expandAll(); emit themeJsonChanged(params); } diff --git a/common/themes/theme_manager.cpp b/common/themes/theme_manager.cpp index 589b201e..bf003164 100644 --- a/common/themes/theme_manager.cpp +++ b/common/themes/theme_manager.cpp @@ -59,7 +59,7 @@ Theme ThemeManager::themeFromId(const QString &id, ThemeVariant fallbackVariant) return makeTheme(json); } - return {}; + return { }; } void ThemeManager::resolveTheme() diff --git a/common/themes/theme_repository.cpp b/common/themes/theme_repository.cpp index 3290cd63..d76695c8 100644 --- a/common/themes/theme_repository.cpp +++ b/common/themes/theme_repository.cpp @@ -50,7 +50,7 @@ QJsonObject ThemeRepository::loadThemeJson(const QString &themeId) const if (u.id == themeId) return readJsonFile(u.filePath); - return {}; + return { }; } QString ThemeRepository::saveUserTheme(QJsonObject themeJson) @@ -104,7 +104,7 @@ QString ThemeRepository::importThemeFromFile(const QString &filePath) { QJsonObject json = readJsonFile(filePath); if (json.isEmpty()) - return {}; + return { }; // Force a new user id regardless of what the file contains auto metaObj = json["meta"].toObject(); @@ -189,13 +189,13 @@ QJsonObject ThemeRepository::readJsonFile(const QString &path) { QFile file(path); if (!file.open(QIODevice::ReadOnly)) - return {}; + return { }; const QByteArray data = file.readAll(); QJsonParseError error; const QJsonDocument doc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) - return {}; + return { }; return doc.object(); } diff --git a/shortcuts_management/actions_shortcuts_model.cpp b/shortcuts_management/actions_shortcuts_model.cpp index 7238b2c7..baf50c16 100644 --- a/shortcuts_management/actions_shortcuts_model.cpp +++ b/shortcuts_management/actions_shortcuts_model.cpp @@ -34,7 +34,7 @@ QModelIndex ActionsShortcutsModel::index(int row, int column, const QModelIndex Qt::ItemFlags ActionsShortcutsModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return {}; + return { }; if (index.column() == KEYS) return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; return Qt::ItemIsEnabled | Qt::ItemIsSelectable; diff --git a/tests/concurrent_queue_test/concurrent_queue_test.cpp b/tests/concurrent_queue_test/concurrent_queue_test.cpp index d9c4eb4b..ee187df9 100644 --- a/tests/concurrent_queue_test/concurrent_queue_test.cpp +++ b/tests/concurrent_queue_test/concurrent_queue_test.cpp @@ -461,8 +461,8 @@ void ConcurrentQueueTest::singleUserThread_data() using ms = chrono::milliseconds; - QTest::newRow("-") << 0 << JobDataSet {}; - QTest::newRow("0") << 7 << JobDataSet {}; + QTest::newRow("-") << 0 << JobDataSet { }; + QTest::newRow("0") << 7 << JobDataSet { }; QTest::newRow("A") << 1 << JobDataSet { { 5, ms(0) } }; QTest::newRow("B") << 5 << JobDataSet { { 12, ms(1) } }; QTest::newRow("C") << 1 << JobDataSet { { 1, ms(0) }, { 5, ms(2) }, { 3, ms(1) } }; @@ -559,9 +559,9 @@ void ConcurrentQueueTest::cancelPending1UserThread_data() const auto ms = [](int count) -> Clock::duration { return chrono::milliseconds(count); }; const auto us = [](int count) -> Clock::duration { return chrono::microseconds(count); }; - QTest::newRow("-") << 0 << JobDataSet {} << ms(0); - QTest::newRow("01") << 2 << JobDataSet {} << ms(0); - QTest::newRow("02") << 3 << JobDataSet {} << ms(1); + QTest::newRow("-") << 0 << JobDataSet { } << ms(0); + QTest::newRow("01") << 2 << JobDataSet { } << ms(0); + QTest::newRow("02") << 3 << JobDataSet { } << ms(1); QTest::newRow("A") << 1 << JobDataSet { { 5, ms(3) } } << ms(1); QTest::newRow("B") << 5 << JobDataSet { { 12, ms(1) } } << ms(1);