view src/gui/theme.cc @ 351:c844f8bb87ce

gui/theme: add xsettings backend this also adds newly-necessary endianness methods in core/endian.h which just so happen to be constexpr as well
author Paper <paper@paper.us.eu.org>
date Sun, 14 Jul 2024 23:23:56 -0400
parents 91ac90a34003
children
line wrap: on
line source

#include "core/config.h"
#include "core/session.h"
#include "gui/theme.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QStyleFactory>
#include <QTextStream>
#include <QStyle>
#include <QtGlobal>
#ifdef MACOSX
#	include "sys/osx/dark_theme.h"
#elif defined(WIN32)
#	include "sys/win32/dark_theme.h"
#else
#	ifdef GLIB
#		include "sys/glib/dark_theme.h"
#	endif
#	ifdef HAVE_XCB
#		include "sys/x11/dark_theme.h"
#	endif
#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
 */

namespace Theme {

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

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

bool ThemeManager::IsInDarkTheme() const {
	switch (theme) {
		case Theme::Default:
#ifdef MACOSX
			if (osx::DarkThemeAvailable())
				return osx::IsInDarkTheme();
#elif defined(WIN32)
			if (win32::DarkThemeAvailable())
				return win32::IsInDarkTheme();
#else
#	ifdef HAVE_XCB
			if (x11::IsInDarkTheme())
				return true;
#	endif
#	ifdef GLIB
			if (glib::IsInDarkTheme())
				return true;
#	endif
			break;
#endif
		default:
			break;
	}
	return (theme == Theme::Dark);
}

void ThemeManager::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(Theme::Dark);
}

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

Theme ThemeManager::GetCurrentOSTheme() const {
	return IsInDarkTheme() ? Theme::Dark : Theme::Light;
}

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

			QPalette pal;

			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
			qApp->setStyleSheet([] {
				QFile f(":/dark.qss");
				if (!f.exists())
					return QStringLiteral("");
				f.open(QFile::ReadOnly | QFile::Text);
				QTextStream ts(&f);
				return ts.readAll();
			}());
#endif
			break;
		}
		default:
			/* this sucks */
			QPalette pal(QApplication::style()->standardPalette());
#ifdef WIN32 /* fuck you Qt 6 */
			pal.setColor(QPalette::Window, QColor(0xF0, 0xF0, 0xF0));
#endif
			qApp->setPalette(pal);

			qApp->setStyleSheet("");
			break;
	}
}

void ThemeManager::SetTheme(Theme theme) {
	switch (theme) {
		case Theme::Light: SetToLightTheme(); break;
		case Theme::Dark: SetToDarkTheme(); break;
		case Theme::Default:
			if (GetCurrentOSTheme() == Theme::Light)
				SetToLightTheme();
			else
				SetToDarkTheme();
			break;
	}
	this->theme = theme;
}

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

} // namespace Theme