336 lines
12 KiB
C++
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;
|
|
}
|
|
//==============================================================================
|