view src/gui/theme.cc @ 229:adc20fa321c1

theme: force Fusion style on platforms other than Win32 or OS X I was reluctant to do this, but most of the other styles just look like pure shite regardless of whether I force a stylesheet on them or not. KDE's style is actually hilariously bad paired with my stylesheet, so I've decided to also make the stylesheet Windows-specific as well, because that's really the only platform where it makes sense in the first place.
author Paper <paper@paper.us.eu.org>
date Wed, 10 Jan 2024 21:23:57 -0500
parents 01d259b9c89f
children 2f5a9247e501
line wrap: on
line source

#include "core/config.h"
#include "core/session.h"
#include <QApplication>
#include <QFile>
#include <QDebug>
#include <QTextStream>
#include <QStyleFactory>
#ifdef MACOSX
#	include "sys/osx/dark_theme.h"
#elif WIN32
#	include "sys/win32/dark_theme.h"
#endif

/* Weird quirks of this implementation:
 *   1. Dark mode stuff in Qt changes a lot and Qt 5 and Qt 6 are massively different
 *   2. Some widgets, i.e. QTabWidget, QTabBar, etc., just completely IGNORE the QPalette setting
 *      on different platforms and the only way to fix it is by using Fusion
 *   3. Windows dark mode support in Qt 6.5 (with Fusion) is completely unavoidable
 * I think what I might end up doing is forcing the Fusion style on any platforms that isn't
 * Windows or Mac. I'm not really fond of doing that, but it's the best way to achieve a "good"
 * visual style without a substaintial amount of fucking around and subsequent finding out.
*/

namespace Theme {

Theme::Theme(Themes theme) {
	this->theme = theme;
}

Themes Theme::GetTheme() const {
	return theme;
}

bool Theme::IsInDarkTheme() const {
	if (theme != Themes::OS)
		return (theme == Themes::DARK);
#ifdef MACOSX
	if (osx::DarkThemeAvailable())
		return osx::IsInDarkTheme();
#elif defined(WIN32)
	if (win32::DarkThemeAvailable())
		return win32::IsInDarkTheme();
#endif
	return (theme == Themes::DARK);
}

void Theme::SetToDarkTheme() {
	/* macOS >= 10.14 has its own global dark theme,
	   use it :) */
#ifdef MACOSX
	if (osx::DarkThemeAvailable())
		osx::SetToDarkTheme();
	else
#elif defined(WIN32)
	if (win32::DarkThemeAvailable())
		win32::SetTitleBarsToBlack(true);
#endif
		SetStyleSheet(Themes::DARK);
}

void Theme::SetToLightTheme() {
#ifdef MACOSX
	if (osx::DarkThemeAvailable())
		osx::SetToLightTheme();
	else
#elif defined(WIN32)
	if (win32::DarkThemeAvailable())
		win32::SetTitleBarsToBlack(false);
#endif
		SetStyleSheet(Themes::LIGHT);
}

Themes Theme::GetCurrentOSTheme() const {
#ifdef MACOSX
	if (osx::DarkThemeAvailable())
		return osx::IsInDarkTheme() ? Themes::DARK : Themes::LIGHT;
#elif defined(WIN32)
	if (win32::DarkThemeAvailable())
		return win32::IsInDarkTheme() ? Themes::DARK : Themes::LIGHT;
#endif
	/* Currently OS detection only supports Windows and macOS.
	   Please don't be shy if you're willing to port it to other OSes
	   (or desktop environments, or window managers) */
	return Themes::LIGHT;
}

/* this function is private, and should stay that way */
void Theme::SetStyleSheet(Themes theme) {
	switch (theme) {
		case Themes::DARK: {
			QColor darkGray(53, 53, 53);
			QColor gray(128, 128, 128);
			QColor black(25, 25, 25);
			QColor blue(42, 130, 218);

			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);

			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);

#ifdef WIN32
			/* This is a dark style sheet that makes things look
			 * marginally better on Windows.
			 *
			 * I'm very close to just giving up and using Fusion
			 * everywhere.
			*/
			QFile f(":dark.qss");
			if (!f.exists())
				break; // how?
			f.open(QFile::ReadOnly | QFile::Text);
			QTextStream ts(&f);
			qApp->setStyleSheet(ts.readAll());
#endif
			break;
		}
		default:
			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;
	}
}

void Theme::SetTheme(Themes theme) {
	switch (theme) {
		case Themes::LIGHT:
			SetToLightTheme();
			break;
		case Themes::DARK:
			SetToDarkTheme();
			break;
		case Themes::OS:
			if (GetCurrentOSTheme() == Themes::LIGHT)
				SetToLightTheme();
			else
				SetToDarkTheme();
			break;
	}
	this->theme = theme;
}

void Theme::RepaintCurrentTheme() {
	Theme::SetTheme(theme);
}

} // namespace DarkTheme