view src/gui/theme.cc @ 187:9613d72b097e

*: multiple performance improvements like marking `static const` when it makes sense... date: change old stupid heap-based method to a structure which should make copying the thing actually make a copy. also many performance-based changes, like removing the std::tie dependency and forward-declaring nlohmann json *: replace every instance of QString::fromUtf8 to Strings::ToQString. the main difference is that our function will always convert exactly what is in the string, while some other times it would only convert up to the nearest NUL byte
author Paper <mrpapersonic@gmail.com>
date Wed, 06 Dec 2023 13:43:54 -0500
parents 01d259b9c89f
children adc20fa321c1
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

/* This is, believe it or not, one of the hardest things I've implemented :/
     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
     3. I don't want to use the Fusion style on every single platform
     4. Windows dark mode support in Qt 6.5 (with Fusion) is completely unavoidable
        (not a joke btw, it's retarded)
   These four already make it really difficult, but along with that, I don't even remember if
   OS X dark mode support even works still; I remember the background of some of the widgets
   would refuse to update for whatever reason. */

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

			QFile f(":dark.qss");
			if (!f.exists())
				break; // how?
			f.open(QFile::ReadOnly | QFile::Text);
			QTextStream ts(&f);
			qApp->setStyleSheet(ts.readAll());
			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