Qt_Custom_Style_Example/_include/application_config.cpp

336 lines
12 KiB
C++

/****************************************************************************
** Copyright (c) 2025 Evgeny Teterin (nayk) <nayk@nxt.ru>
** All right reserved.
**
** 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.
**
****************************************************************************/
#include "application_config.h"
#include "config.h"
#include <QtWidgets/QApplication>
#include <QtWidgets/QStyleFactory>
#include <QtCore/QTranslator>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QStringList>
#include <QtWidgets/QStyle>
#include <QtGui/QStyleHints>
#include <QtGui/QPalette>
#include <QtCore/QSettings>
#include <QtGui/QScreen>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
# include <QtCore/QTextCodec>
#endif
//==============================================================================
bool systemUseDarkTheme()
{
QApplication *application = qobject_cast<QApplication*>( QApplication::instance() );
if (!application) return false;
QPalette appPalette = application->palette();
bool darkTheme {false};
int n = -1;
#if QT_VERSION > QT_VERSION_CHECK(6, 5, 0)
if (application->styleHints()->colorScheme() == Qt::ColorScheme::Light) n = 1;
else if (application->styleHints()->colorScheme() == Qt::ColorScheme::Dark) n = 0;
#endif
#ifdef Q_OS_WIN
if (n < 0) {
QSettings registry(R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)",
QSettings::NativeFormat);
//n = registry.value("SystemUsesLightTheme",-1).toInt();
n = registry.value("AppsUseLightTheme", -1).toInt();
}
#endif
if (n < 0) {
QRgb c1 = appPalette.color(QPalette::Window).rgb();
QRgb c2 = appPalette.color(QPalette::WindowText).rgb();
darkTheme = ((qRed(c1) * 11 + qGreen(c1) * 16 + qBlue(c1) * 5) / 32)
< ((qRed(c2) * 11 + qGreen(c2) * 16 + qBlue(c2) * 5) / 32);
}
else {
darkTheme = (n == 0);
}
return darkTheme;
}
//==============================================================================
void Application::initialize()
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
#endif
#if defined (PROG_NAME)
QApplication::setApplicationName( QString(PROG_NAME) );
#endif
#if defined (SOFT_DEVELOPER)
QApplication::setOrganizationName( QString(SOFT_DEVELOPER) );
#endif
#if defined (DEVELOPER_DOMAIN)
QApplication::setOrganizationDomain( QString(DEVELOPER_DOMAIN) );
#endif
#if defined (PROG_VERSION)
QApplication::setApplicationVersion( QString(PROG_VERSION) );
#endif
#if defined (BUILD_DATE)
qApp->setProperty( "buildDate", QString(BUILD_DATE) );
#endif
}
//==============================================================================
QString Application::applicationRootPath()
{
QString path { QApplication::applicationDirPath() };
if ( path.right(1) != "/" ) {
path += "/";
}
if (path.right(5) == "/bin/") {
path.remove( path.length() - 4, 4 );
}
return path;
}
//==============================================================================
void Application::installTranslations(const QString &lng)
{
const QString dirName { applicationRootPath() + "translations/" };
QDir translationsDir { dirName };
QStringList filesList = translationsDir.entryList(
QStringList() << QString("*_%1.qm").arg(lng),
QDir::Files
);
for (const QString &fileName: std::as_const(filesList)) {
QTranslator *translator = new QTranslator(QApplication::instance());
if (translator->load( dirName + fileName )) {
QApplication::instance()->installTranslator( translator );
}
else {
delete translator;
}
}
}
//==============================================================================
bool Application::updateApplicationStyle(AppTheme appTheme)
{
QApplication *application = qobject_cast<QApplication*>( QApplication::instance() );
if (!application) return false;
application->setStyleSheet("");
if (QStyleFactory::keys().contains("Fusion")) {
application->setStyle( QStyleFactory::create("Fusion") );
}
bool darkTheme = (appTheme == SystemTheme) ? systemUseDarkTheme() : appTheme == DarkTheme;
QPalette appPalette = application->palette();
appPalette.setColor( QPalette::Highlight, QColor(55, 174, 254));
appPalette.setColor( QPalette::HighlightedText, QColor(245, 250, 255));
appPalette.setColor( QPalette::Link, QColor(55, 174, 254));
appPalette.setColor( QPalette::LinkVisited, QColor(52, 103, 146));
appPalette.setColor( QPalette::Disabled, QPalette::Link, QColor(52, 103, 146));
appPalette.setColor( QPalette::Disabled, QPalette::LinkVisited, QColor(40, 90, 130));
if (darkTheme) {
appPalette.setColor( QPalette::Window, QColor(30, 35, 40));
appPalette.setColor( QPalette::WindowText, QColor(245, 250, 255));
appPalette.setColor( QPalette::Base, QColor(45, 50, 55));
appPalette.setColor( QPalette::AlternateBase, QColor(48, 53, 58));
appPalette.setColor( QPalette::ToolTipBase, QColor(60, 65, 70));
appPalette.setColor( QPalette::ToolTipText, QColor(200, 205, 210));
appPalette.setColor( QPalette::Text, QColor(245, 250, 255));
appPalette.setColor( QPalette::Button, QColor(55, 60, 65));
appPalette.setColor( QPalette::ButtonText, QColor(245, 250, 255));
appPalette.setColor( QPalette::BrightText, QColor(194, 232, 255));
appPalette.setColor( QPalette::PlaceholderText, QColor(200, 205, 210));
appPalette.setColor( QPalette::Disabled, QPalette::WindowText, QColor(157, 157, 157));
appPalette.setColor( QPalette::Disabled, QPalette::Base, QColor(30, 35, 40));
appPalette.setColor( QPalette::Disabled, QPalette::AlternateBase, QColor(33, 38, 43));
appPalette.setColor( QPalette::Disabled, QPalette::ToolTipBase, QColor(200, 205, 210));
appPalette.setColor( QPalette::Disabled, QPalette::ToolTipText, QColor(5, 10, 15));
appPalette.setColor( QPalette::Disabled, QPalette::Text, QColor(150, 155, 160));
appPalette.setColor( QPalette::Disabled, QPalette::ButtonText, QColor(150, 155, 160));
appPalette.setColor( QPalette::Disabled, QPalette::BrightText, QColor(150, 193, 218));
}
else { // light theme
appPalette.setColor( QPalette::Window, QColor(230, 235, 240));
appPalette.setColor( QPalette::WindowText, QColor(0, 3, 5));
appPalette.setColor( QPalette::Base, QColor(245, 250, 255));
appPalette.setColor( QPalette::AlternateBase, QColor(242, 247, 252));
appPalette.setColor( QPalette::ToolTipBase, QColor(255, 255, 220));
appPalette.setColor( QPalette::ToolTipText, QColor(0, 0, 0));
appPalette.setColor( QPalette::Text, QColor(0, 3, 5));
appPalette.setColor( QPalette::Button, QColor(225, 230, 235));
appPalette.setColor( QPalette::ButtonText, QColor(0, 3, 5));
appPalette.setColor( QPalette::BrightText, QColor(255, 255, 255));
appPalette.setColor( QPalette::PlaceholderText, QColor(5, 10, 15));
appPalette.setColor( QPalette::Disabled, QPalette::WindowText, QColor(120, 120, 120));
appPalette.setColor( QPalette::Disabled, QPalette::Base, QColor(240, 240, 240));
appPalette.setColor( QPalette::Disabled, QPalette::AlternateBase, QColor(247, 247, 247));
appPalette.setColor( QPalette::Disabled, QPalette::ToolTipBase, QColor(255, 255, 220));
appPalette.setColor( QPalette::Disabled, QPalette::ToolTipText, QColor(0, 0, 0));
appPalette.setColor( QPalette::Disabled, QPalette::Text, QColor(120, 120, 120));
appPalette.setColor( QPalette::Disabled, QPalette::ButtonText, QColor(120, 120, 120));
appPalette.setColor( QPalette::Disabled, QPalette::BrightText, QColor(255, 255, 255));
}
application->setPalette(appPalette);
QString qssFile {":/qss/style.qss"};
QString qss;
if (QFile::exists(qssFile)) {
QFile file(qssFile);
if (!file.open(QFile::ReadOnly)) return false;
QByteArray buf;
while (!file.atEnd()) {
buf.append( file.read(1024) );
}
file.close();
qss = QString(buf);
QRgb rgb = appPalette.color(QPalette::Highlight).rgb();
QString clStr = QString("rgb(%1, %2, %3)").arg(qRed(rgb)).arg(qGreen(rgb)).arg(qBlue(rgb));
qss.replace("$MENU_ITEM_SELECT_COLOR", clStr);
rgb = appPalette.color(QPalette::LinkVisited).rgb();
clStr = QString("rgb(%1, %2, %3)").arg(qRed(rgb)).arg(qGreen(rgb)).arg(qBlue(rgb));
qss.replace("$MENU_ITEM_SELECT_BORDER", clStr);
double checkBoxMetric = QApplication::primaryScreen()->logicalDotsPerInch() / 4.3;
double toggleMetric = checkBoxMetric * 1.2;
clStr = QString("%1px").arg(qRound( checkBoxMetric ));
qss.replace("$CHECKBOX_SIZE", clStr);
clStr = QString("%1px").arg(qRound( toggleMetric ));
qss.replace("$TOGGLE_HEIGHT", clStr);
clStr = QString("%1px").arg(qRound( toggleMetric * 1.5 ));
qss.replace("$TOGGLE_WIDTH", clStr);
clStr = darkTheme ? "dark" : "light";
qss.replace("$THEME", clStr);
if (toggleMetric > 32) {
qss.replace("toggle_checked.png", "toggle_checked@2x.png");
qss.replace("toggle_unchecked.png", "toggle_unchecked@2x.png");
qss.replace("toggle_checked_disabled.png", "toggle_checked_disabled@2x.png");
qss.replace("toggle_unchecked_disabled.png", "toggle_unchecked_disabled@2x.png");
qss.replace("toggle_checked_focus.png", "toggle_checked_focus@2x.png");
qss.replace("toggle_unchecked_focus.png", "toggle_unchecked_focus@2x.png");
qss.replace("toggle_pressed.png", "toggle_pressed@2x.png");
}
if (checkBoxMetric > 32) {
qss.replace("_checked.png", "_checked@2x.png");
qss.replace("_unchecked.png", "_unchecked@2x.png");
qss.replace("_indeterminate.png", "_indeterminate@2x.png");
qss.replace("_disabled.png", "_disabled@2x.png");
qss.replace("_focus.png", "_focus@2x.png");
qss.replace("_pressed.png", "_pressed@2x.png");
}
}
qssFile = applicationRootPath() + "style.qss";
if (QFile::exists(qssFile)) {
QFile file(qssFile);
if (!file.open(QFile::ReadOnly)) return false;
QByteArray buf;
while (!file.atEnd()) {
buf.append( file.read(1024) );
}
file.close();
qss += "\n" + QString(buf);
}
application->setStyleSheet(qss);
application->setProperty("AppsUseDarkTheme", darkTheme);
return true;
}
//==============================================================================
bool Application::applicationUseDarkTheme()
{
QApplication *application = qobject_cast<QApplication*>( QApplication::instance() );
if (!application) return false;
if (!application->property("AppsUseDarkTheme").isNull()) {
return application->property("AppsUseDarkTheme").toBool();
}
bool darkTheme = systemUseDarkTheme();
application->setProperty("AppsUseDarkTheme", darkTheme);
return darkTheme;
}
//==============================================================================