Mercurial > minori
changeset 105:6d8da6e64d61
theme: add dark stylesheet, make it actually usable
win32: make the titlebar black where available
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 05 Nov 2023 03:54:26 -0500 |
parents | 27455104ea37 |
children | c8c72278f6fd |
files | CMakeLists.txt include/core/strings.h include/gui/theme.h include/gui/window.h include/sys/win32/dark_theme.h rc/dark.qrc rc/dark.qss rc/icons.qrc src/gui/dialog/about.cc src/gui/dialog/information.cc src/gui/dialog/settings/application.cc src/gui/pages/anime_list.cc src/gui/pages/now_playing.cc src/gui/pages/statistics.cc src/gui/theme.cc src/gui/widgets/text.cc src/gui/window.cc src/sys/osx/dark_theme.mm src/sys/win32/dark_theme.cc |
diffstat | 19 files changed, 520 insertions(+), 56 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sun Nov 05 02:35:27 2023 -0500 +++ b/CMakeLists.txt Sun Nov 05 03:54:26 2023 -0500 @@ -102,6 +102,7 @@ # Qt resources rc/icons.qrc + rc/dark.qrc ) set(RC_INFO_STRING "A lightweight anime tracker built with Qt.")
--- a/include/core/strings.h Sun Nov 05 02:35:27 2023 -0500 +++ b/include/core/strings.h Sun Nov 05 03:54:26 2023 -0500 @@ -3,11 +3,73 @@ #include <string> #include <vector> +#include <array> class QString; namespace Strings { +template<unsigned...>struct seq{using type=seq;}; +template<unsigned N, unsigned... Is> +struct gen_seq_x : gen_seq_x<N-1, N-1, Is...>{}; +template<unsigned... Is> +struct gen_seq_x<0, Is...> : seq<Is...>{}; +template<unsigned N> +using gen_seq=typename gen_seq_x<N>::type; + +template<size_t S> +using size=std::integral_constant<size_t, S>; + +template<class T, size_t N> +constexpr size<N> length( T const(&)[N] ) { return {}; } +template<class T, size_t N> +constexpr size<N> length( std::array<T, N> const& ) { return {}; } + +template<class T> +using length_t = decltype(length(std::declval<T>())); + +constexpr size_t string_size() { return 0; } +template<class...Ts> +constexpr size_t string_size( size_t i, Ts... ts ) { + return (i?i-1:0) + string_size(ts...); +} +template<class...Ts> +using string_length=size< string_size( length_t<Ts>{}... )>; + +template<class...Ts> +using combined_string = std::array<char, string_length<Ts...>{}+1>; + +template<class Lhs, class Rhs, unsigned...I1, unsigned...I2> +constexpr const combined_string<Lhs,Rhs> +concat_impl( Lhs const& lhs, Rhs const& rhs, seq<I1...>, seq<I2...>) +{ + return {{ lhs[I1]..., rhs[I2]..., '\0' }}; +} + +template<class Lhs, class Rhs> +constexpr const combined_string<Lhs,Rhs> +concat(Lhs const& lhs, Rhs const& rhs) +{ + return concat_impl(lhs, rhs, gen_seq<string_length<Lhs>{}>{}, gen_seq<string_length<Rhs>{}>{}); +} + +template<class T0, class T1, class... Ts> +constexpr const combined_string<T0, T1, Ts...> +concat(T0 const&t0, T1 const&t1, Ts const&...ts) +{ + return concat(t0, concat(t1, ts...)); +} + +template<class T> +constexpr const combined_string<T> +concat(T const&t) { + return concat(t, ""); +} +constexpr const combined_string<> +concat() { + return concat(""); +} + /* Implode function: takes a vector of strings and turns it into a string, separated by delimiters. */ std::string Implode(const std::vector<std::string>& vector, const std::string& delimiter);
--- a/include/gui/theme.h Sun Nov 05 02:35:27 2023 -0500 +++ b/include/gui/theme.h Sun Nov 05 03:54:26 2023 -0500 @@ -16,9 +16,10 @@ Theme(Themes theme = Themes::OS); void SetTheme(Themes theme); Themes GetTheme(); + bool IsInDarkMode(); + void RepaintCurrentTheme(); private: - bool IsInDarkMode(); void SetToDarkTheme(); void SetToLightTheme(); void SetStyleSheet(Themes theme);
--- a/include/gui/window.h Sun Nov 05 02:35:27 2023 -0500 +++ b/include/gui/window.h Sun Nov 05 03:54:26 2023 -0500 @@ -15,6 +15,7 @@ MainWindow(QWidget* parent = nullptr); void SetActivePage(QWidget* page); void CreateBars(); + void showEvent(QShowEvent* event) override; void closeEvent(QCloseEvent* event) override; private:
--- a/include/sys/win32/dark_theme.h Sun Nov 05 02:35:27 2023 -0500 +++ b/include/sys/win32/dark_theme.h Sun Nov 05 03:54:26 2023 -0500 @@ -1,11 +1,15 @@ #ifndef __sys__win32__dark_theme_h #define __sys__win32__dark_theme_h +class QWidget; + namespace win32 { +bool SetTitleBarToBlack(QWidget* win, bool enabled); +void SetTitleBarsToBlack(bool enabled); bool DarkThemeAvailable(); bool IsInDarkTheme(); } // namespace win32 -#endif // __sys__win32__dark_theme_h \ No newline at end of file +#endif // __sys__win32__dark_theme_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc/dark.qrc Sun Nov 05 03:54:26 2023 -0500 @@ -0,0 +1,5 @@ +<!DOCTYPE rcc><RCC version="1.0"> + <qresource> + <file>dark.qss</file> + </qresource> +</RCC>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc/dark.qss Sun Nov 05 03:54:26 2023 -0500 @@ -0,0 +1,286 @@ +/* +Much of this is taken from the Breeze Style Sheets, +which is under the MIT license: + +Copyright © `<2013-2014>` `<Colin Duquesnoy>` +Copyright © `<2015-2016>` `<Alex Huszagh>` + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* Colors should be the same as the QPalette in gui/theme.cc, i.e.: + window == darkgray == #353535; + ??? == gray == #808080; + base == black == #191919; + highlighted == blue = #2A82DA; + + It's a shame Qt stylesheets don't properly support variables :') + Maybe we could configure it with cmake? +*/ + +AnimeListPage::pane { + margin: 0.04em; +} + +AnimeListPage::pane, +QTabWidget::pane:top { + border: 0.04em solid #808080; + top: -0.04em; +} + +AnimeListPage::pane, +QTabWidget::pane:bottom { + border: 0.04em solid #808080; + bottom: -0.04em; +} + +AnimeListPage::pane, +QTabWidget::pane:left { + border: 0.04em solid #808080; + left: -0.04em; +} + +AnimeListPage::pane, +QTabWidget::pane:right { + border: 0.04em solid #808080; + right: -0.04em; +} + +QTabBar { + qproperty-drawBase: 0; + left: 0.23em; + border-radius: 0.13em; + selection-color: transparent; +} + +QTabBar:focus { + border: 0em transparent black; +} + +QTabBar::tab:top, +QTabBar::tab:top:last, +QTabBar::tab:top:only-one { + color: white; + border: 0.04em transparent black; + border-left: 0.04em solid #808080; + border-right: 0.04em solid #808080; + border-top: 0.04em solid #808080; + background-color: #353535; + min-width: 50px; + padding-top: 0.23em; + padding-bottom: 0.23em; + padding-left: 0.46em; + padding-right: 0.46em; + border-radius: 0.09em; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; +} + +QTabBar::tab:top:!selected { + color: white; + background-color: #353535; + border: 0.04em solid #808080; + border-radius: 0.09em; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; + margin-top: 0.13em; +} + +QTabBar::tab:top:next-selected { + border-right: 0.04em transparent #353535; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; +} + +QTabBar::tab:top:previous-selected { + border-left: 0.04em transparent #353535; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; +} + +QTabBar::tab:top:!selected:hover { + background-color: rgba(42, 130, 218, 0.1); + border-radius: 0.09em; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; +} + +QTabBar::tab:top:!selected:first:hover { + background-color: rgba(42, 130, 218, 0.1); + border-radius: 0.09em; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; +} + +QGroupBox::title { + color: white; +} + +QComboBox, +QPushButton, +QDateEdit, +QSpinBox { + background-color: #353535; + color: white; +} + +/* + * QLineEdit + */ + +QLineEdit:!read-only { + background-color: #191919; + padding: 0.23em; + border-style: solid; + border: 0.04em solid #808080; + border-radius: 0.09em; +} + +Line { + background: transparent; +} + +/* QMenuBar */ + +QMenuBar { + background-color: #353535; + color: white; +} + +QMenuBar::item { + background: transparent; +} + +QMenuBar::item:selected { + background: transparent; + border: 0.04em solid #2A82DA; +} + +QMenuBar::item:disabled { + color: #808080; +} + +QMenuBar::item:pressed { + background-color: #2A82DA; + color: white; + margin-bottom: -0.09em; + padding-bottom: 0.09em; +} + +/* QMenu */ + +QMenu { + color: white; + background-color: #353535; + margin: 0.09em; +} + +QMenu::icon { + margin: 0.23em; +} + +QMenu::item { + /* Add extra padding on the right for the QMenu arrow */ + padding: 0.23em 1.5em 0.23em 1.3em; + border: 0.09em solid transparent; + background: transparent; +} + +QMenu::item:selected { + color: white; + background-color: #2A82DA; +} + +QMenu::item:selected:disabled { + background-color: #353535; +} + +QMenu::item:disabled { + color: #808080; +} + +QMenu::indicator { + width: 0.8em; + height: 0.8em; + /* To align with QMenu::icon, which has a 0.23em margin. */ + margin-left: 0.3em; + subcontrol-position: center left; +} + +/* + * QHeaderView: + * Need this for the anime list, on Windows it gets screwed up. +*/ + +QHeaderView { + background-color: #353535; + border: 0.04em transparent; + border-radius: 0em; + margin: 0em; + padding: 0em; +} + +QHeaderView::section { + background-color: #353535; + border: 0.04em solid #808080; + color: #eff0f1; + border-radius: 0em; + padding: 0em 0.23em 0em 0.23em; + text-align: center; +} + +QHeaderView::section::vertical::first, +QHeaderView::section::vertical::only-one { + border-top: 0.04em solid #808080; +} + +QHeaderView::section::vertical { + border-top: transparent; +} + +QHeaderView::section::horizontal::first, +QHeaderView::section::horizontal::only-one { + border-left: 0.04em solid #808080; +} + +QHeaderView::section::horizontal { + border-left: transparent; +} + +QHeaderView[showSortIndicator="true"]::section::horizontal { + /* Same as the width of the arrow subcontrols below. */ + padding-right: 0.8em; +} + +QHeaderView::section:checked { + color: white; + background-color: #2A82DA; +} + +/* Note that this doesn't work for QTreeView unless the header is clickable */ +QHeaderView::section:hover, +QHeaderView::section::horizontal::first:hover, +QHeaderView::section::horizontal::only-one:hover, +QHeaderView::section::vertical::first:hover, +QHeaderView::section::vertical::only-one:hover { + border: 0.04em solid #2A82DA; +}
--- a/rc/icons.qrc Sun Nov 05 02:35:27 2023 -0500 +++ b/rc/icons.qrc Sun Nov 05 03:54:26 2023 -0500 @@ -19,4 +19,4 @@ <file>icons/24x24/megaphone.png</file> <file>icons/24x24/question.png</file> </qresource> -</RCC> \ No newline at end of file +</RCC>
--- a/src/gui/dialog/about.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/dialog/about.cc Sun Nov 05 03:54:26 2023 -0500 @@ -67,6 +67,7 @@ " <li><strong>Alex Huszagh</strong> and <strong>Colin Duquesnoy</strong> for " "creating BreezeStyleSheets, on which the dark theme in this program is " "based off of</li>" + " <li><strong>Andy Brice</strong> for making " " </ul>" "</body>";
--- a/src/gui/dialog/information.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/dialog/information.cc Sun Nov 05 03:54:26 2023 -0500 @@ -42,7 +42,7 @@ setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); { - QPalette pal(palette()); + QPalette pal; pal.setColor(QPalette::Window, pal.color(QPalette::Base)); setPalette(pal); } @@ -73,12 +73,6 @@ /* main info tab */ AnimeInfoWidget* main_information_widget = new AnimeInfoWidget(anime, tabbed_widget); - { - QPalette pal(main_information_widget->palette()); - pal.setColor(QPalette::Base, pal.color(QPalette::Window)); - main_information_widget->setPalette(pal); - } - QWidget* settings_widget = new QWidget(tabbed_widget); settings_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
--- a/src/gui/dialog/settings/application.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/dialog/settings/application.cc Sun Nov 05 03:54:26 2023 -0500 @@ -12,6 +12,7 @@ QWidget* SettingsPageApplication::CreateAnimeListWidget() { QWidget* result = new QWidget(this); + result->setAutoFillBackground(true); result->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); QGroupBox* actions_group_box = new QGroupBox(tr("Actions"), result);
--- a/src/gui/pages/anime_list.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/pages/anime_list.cc Sun Nov 05 03:54:26 2023 -0500 @@ -282,14 +282,13 @@ } menu->addSeparator(); - QAction* resetAction = menu->addAction(tr("Reset to defaults"), this, [this]() { + menu->addAction(tr("Reset to defaults"), this, [this]() { for (int i = 0, count = tree_view->header()->count(); i < count; ++i) { SetColumnDefaults(); } // SaveSettings(); }); menu->popup(QCursor::pos()); - (void)(resetAction); } void AnimeListPage::DisplayListMenu() { @@ -312,7 +311,7 @@ animes.insert(anime); } - QAction* action = menu->addAction(tr("Information"), [this, animes] { + menu->addAction(tr("Information"), [this, animes] { for (auto& anime : animes) { InformationDialog* dialog = new InformationDialog( *anime, [this, anime] { UpdateAnime(anime->GetId()); }, this); @@ -323,7 +322,7 @@ } }); menu->addSeparator(); - action = menu->addAction(tr("Delete from list..."), [this, animes] { + menu->addAction(tr("Delete from list..."), [this, animes] { for (auto& anime : animes) { RemoveAnime(anime->GetId()); } @@ -387,7 +386,6 @@ InitBasicStyle(option); - // int exth = style()->pixelMetric(QStyle::PM_TabBarBaseHeight, nullptr, this); QSize t(0, tree_view->frameWidth()); if (tab_bar->isVisibleTo(this)) { t = tab_bar->sizeHint(); @@ -421,12 +419,6 @@ tab_bar = new QTabBar(this); tab_bar->setExpanding(false); tab_bar->setDrawBase(false); - tab_bar->setAutoFillBackground(true); - - if (parent) { - QPalette pal(parent->palette()); - setPalette(pal); - } /* Tree view... */ QWidget* tree_widget = new QWidget(this);
--- a/src/gui/pages/now_playing.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/pages/now_playing.cc Sun Nov 05 03:54:26 2023 -0500 @@ -108,10 +108,6 @@ setFrameShape(QFrame::Box); setFrameShadow(QFrame::Sunken); - - QPalette pal = QPalette(); - pal.setColor(QPalette::Window, pal.color(QPalette::Base)); - setPalette(pal); setAutoFillBackground(true); stack = new QStackedWidget(this);
--- a/src/gui/pages/statistics.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/pages/statistics.cc Sun Nov 05 03:54:26 2023 -0500 @@ -18,9 +18,6 @@ setFrameShape(QFrame::Box); setFrameShadow(QFrame::Sunken); - QPalette pal = QPalette(); - pal.setColor(QPalette::Window, pal.color(QPalette::Base)); - setPalette(pal); setAutoFillBackground(true); _anime_list.reset(new TextWidgets::LabelledSection(
--- a/src/gui/theme.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/theme.cc Sun Nov 05 03:54:26 2023 -0500 @@ -7,7 +7,7 @@ #include <QStyleFactory> #ifdef MACOSX # include "sys/osx/dark_theme.h" -#else +#elif WIN32 # include "sys/win32/dark_theme.h" #endif @@ -47,25 +47,31 @@ void Theme::SetToDarkTheme() { /* macOS >= 10.14 has its own global dark theme, use it :) */ -#if MACOSX +#ifdef MACOSX if (osx::DarkThemeAvailable()) osx::SetToDarkTheme(); else +#elif defined(WIN32) + if (win32::DarkThemeAvailable()) + win32::SetTitleBarsToBlack(true); #endif SetStyleSheet(Themes::DARK); } void Theme::SetToLightTheme() { -#if MACOSX +#ifdef MACOSX if (osx::DarkThemeAvailable()) osx::SetToLightTheme(); else +#elif defined(WIN32) + if (win32::DarkThemeAvailable()) + win32::SetTitleBarsToBlack(false); #endif SetStyleSheet(Themes::LIGHT); } Themes Theme::GetCurrentOSTheme() { -#if MACOSX +#ifdef MACOSX if (osx::DarkThemeAvailable()) return osx::IsInDarkTheme() ? Themes::DARK : Themes::LIGHT; #elif defined(WIN32) @@ -87,30 +93,47 @@ QColor black(25, 25, 25); QColor blue(42, 130, 218); - QPalette darkPalette; - darkPalette.setColor(QPalette::Window, darkGray); - darkPalette.setColor(QPalette::WindowText, Qt::white); - darkPalette.setColor(QPalette::Base, black); - darkPalette.setColor(QPalette::AlternateBase, darkGray); - darkPalette.setColor(QPalette::ToolTipBase, blue); - darkPalette.setColor(QPalette::ToolTipText, Qt::white); - darkPalette.setColor(QPalette::Text, Qt::white); - darkPalette.setColor(QPalette::Button, darkGray); - darkPalette.setColor(QPalette::ButtonText, Qt::white); - darkPalette.setColor(QPalette::Link, blue); - darkPalette.setColor(QPalette::Highlight, blue); - darkPalette.setColor(QPalette::HighlightedText, Qt::black); + QPalette pal(QApplication::style()->standardPalette()); + pal.setColor(QPalette::Window, darkGray); + pal.setColor(QPalette::WindowText, Qt::white); + pal.setColor(QPalette::Base, black); + pal.setColor(QPalette::AlternateBase, darkGray); + pal.setColor(QPalette::ToolTipBase, blue); + pal.setColor(QPalette::ToolTipText, Qt::white); + pal.setColor(QPalette::Text, Qt::white); + pal.setColor(QPalette::Button, darkGray); + pal.setColor(QPalette::ButtonText, Qt::white); + pal.setColor(QPalette::Link, blue); + pal.setColor(QPalette::Highlight, blue); + pal.setColor(QPalette::HighlightedText, Qt::black); - darkPalette.setColor(QPalette::Active, QPalette::Button, gray.darker()); - darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray); - darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray); - darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray); - darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray); - qApp->setPalette(darkPalette); + pal.setColor(QPalette::Active, QPalette::Button, gray.darker()); + pal.setColor(QPalette::Disabled, QPalette::ButtonText, gray); + pal.setColor(QPalette::Disabled, QPalette::WindowText, gray); + pal.setColor(QPalette::Disabled, QPalette::Text, gray); + pal.setColor(QPalette::Disabled, QPalette::Light, darkGray); + qApp->setPalette(pal); + + QFile f(":dark.qss"); + if (!f.exists()) + break; // how? + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); break; } default: - qApp->setPalette(QApplication::style()->standardPalette()); + QPalette pal(QApplication::style()->standardPalette()); +#ifdef WIN32 /* fuck you Qt 6 */ + pal.setColor(QPalette::Window, QColor(0xF0, 0xF0, 0xF0)); +#endif + pal.setColor(QPalette::WindowText, Qt::black); + pal.setColor(QPalette::ToolTipText, Qt::black); + pal.setColor(QPalette::Text, Qt::black); + pal.setColor(QPalette::ButtonText, Qt::black); + qApp->setPalette(pal); + + qApp->setStyleSheet(""); break; } } @@ -133,4 +156,8 @@ this->theme = theme; } +void Theme::RepaintCurrentTheme() { + Theme::SetTheme(theme); +} + } // namespace DarkTheme
--- a/src/gui/widgets/text.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/widgets/text.cc Sun Nov 05 03:54:26 2023 -0500 @@ -80,6 +80,7 @@ setCursor(Qt::IBeamCursor); QPalette pal; + pal.setColor(QPalette::Window, Qt::transparent); pal.setColor(QPalette::Base, Qt::transparent); setPalette(pal); @@ -101,7 +102,7 @@ setFont(fnt); QPalette pal(palette()); - pal.setColor(QPalette::Text, Qt::blue); + pal.setColor(QPalette::Text, pal.color(QPalette::Highlight)); setPalette(pal); }
--- a/src/gui/window.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/gui/window.cc Sun Nov 05 03:54:26 2023 -0500 @@ -272,6 +272,13 @@ this->setCentralWidget(page); } +void MainWindow::showEvent(QShowEvent* event) { + QMainWindow::showEvent(event); +#ifdef WIN32 + win32::SetTitleBarToBlack(this, session.config.theme.IsInDarkMode()); +#endif +} + void MainWindow::closeEvent(QCloseEvent* event) { session.config.Save(); event->accept();
--- a/src/sys/osx/dark_theme.mm Sun Nov 05 02:35:27 2023 -0500 +++ b/src/sys/osx/dark_theme.mm Sun Nov 05 03:54:26 2023 -0500 @@ -3,6 +3,8 @@ namespace osx { +/* I remember clang giving a hissy fit when I tried simplifying this to just + a return; does it still do that? */ bool DarkThemeAvailable() { if (@available(macOS 10.14, *)) return true; @@ -28,7 +30,7 @@ void SetToLightTheme() { // https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code - if (__builtin_available(macOS 10.14, *)) { + if (@available(macOS 10.14, *)) { [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]]; } }
--- a/src/sys/win32/dark_theme.cc Sun Nov 05 02:35:27 2023 -0500 +++ b/src/sys/win32/dark_theme.cc Sun Nov 05 03:54:26 2023 -0500 @@ -1,12 +1,98 @@ #include "sys/win32/dark_theme.h" +#include <QApplication> +#include <QDebug> #include <QOperatingSystemVersion> #include <QSettings> +#include <QWidget> +#include <iostream> +#include <dwmapi.h> + +/* let's make a class wrapper around HINSTANCE, + so we don't fuck anything up :). */ +class Library { + public: + Library() {} + ~Library() { + Unload(); + } + void Unload() { + if (hInstance) + FreeLibrary(hInstance); + loaded = false; + } + void Load(LPCWSTR name) { + if (loaded) + Unload(); + hInstance = LoadLibraryW(name); + if (hInstance) + loaded = true; + } + HINSTANCE GetInstance() { + return hInstance; + } + bool IsLoaded() { + return loaded; + } + private: + HINSTANCE hInstance = nullptr; + bool loaded = false; +}; + +Library dwmapi; namespace win32 { +#define GET_FUNCTION(f, i) \ + reinterpret_cast<decltype(::f)*>(GetProcAddress(i, #f)) + +static HRESULT SetWindowAttribute(HWND hWnd, DWORD key, LPCVOID data, DWORD sz_data) { + if (!dwmapi.IsLoaded()) { + dwmapi.Load(L"dwmapi.dll"); + if (!dwmapi.IsLoaded()) + return false; + } + + HINSTANCE hInstance = dwmapi.GetInstance(); + if (!hInstance) + return false; + + auto set_wind_attrib = GET_FUNCTION(DwmSetWindowAttribute, hInstance); + if (!set_wind_attrib) + return false; + + return set_wind_attrib(hWnd, key, data, sz_data); +} + +/* Ok, so this doesn't work. Woohoo! :) */ +bool SetTitleBarToBlack(QWidget* win, bool enabled) { + BOOL b = enabled; + + /* MAGIC NUMBERS: 19 and 20 are both DWMWA_USE_IMMERSIVE_DARK_MODE. + clarification: it's 20 on newer versions of windows (i.e. win11 and late win10), + but it's 19 on very old versions of win10 nobody ought to be using. */ + { + HRESULT result = SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 20, &b, sizeof(b)); + if (result == S_OK) + return b; + } + + { + /* It's 19 in older Windows 10 versions. Yeah, stupid. */ + HRESULT result = SetWindowAttribute(reinterpret_cast<HWND>(win->winId()), 19, &b, sizeof(b)); + if (result == S_OK) + return b; + } + + return b; +} + +void SetTitleBarsToBlack(bool enabled) { + for (QWidget* widget : qApp->topLevelWidgets()) { + SetTitleBarToBlack(widget, enabled); + } +} + bool DarkThemeAvailable() { - // dark mode supported Windows 10 1809 10.0.17763 onward - // https://stackoverflow.com/questions/53501268/win10-dark-theme-how-to-use-in-winapi const auto& ver = QOperatingSystemVersion::current(); return (ver.majorVersion() > 10) ? true : (ver.majorVersion() == 10 && ver.microVersion() >= 17763); }