// SPDX-FileCopyrightText: 2022 Gary Wang // // SPDX-License-Identifier: MIT #include "settings.h" #include #include #include #include #include #include #include #include Settings *Settings::instance() { // SAFETY: // This is a global singleton and it is leaked by design. static Settings* INSTANCE = new Settings(nullptr); return INSTANCE; } namespace QEnumHelper { template E fromString(const QString &text, const E defaultValue) { bool ok; E result = static_cast(QMetaEnum::fromType().keyToValue(text.toUtf8(), &ok)); if (!ok) { return defaultValue; } return result; } template QString toString(E value) { const int intValue = static_cast(value); return QString::fromUtf8(QMetaEnum::fromType().valueToKey(intValue)); } } bool Settings::useLightCheckerboard() const { return m_qsettings->value("use_light_checkerboard", false).toBool(); } bool Settings::loopGallery() const { return m_qsettings->value("loop_gallery", true).toBool(); } bool Settings::svgTiny12Only() const { // Qt 6.7.0's SVG support is terrible caused by huge memory usage, see QTBUG-124287 // Qt 6.7.1's is somewhat better, memory issue seems fixed, but still laggy when zoom in, see QTBUG-126771. // Qt 6.9.3 and Qt 6.10.1 seems no longer have the laggy issue, so let's make the default value different // based on Qt version. #if QT_VERSION < QT_VERSION_CHECK(6, 9, 3) return m_qsettings->value("svg_tiny12_only", true).toBool(); #else return m_qsettings->value("svg_tiny12_only", false).toBool(); #endif // QT_VERSION < QT_VERSION_CHECK(6, 9, 3) } Settings::DoubleClickBehavior Settings::doubleClickBehavior() const { QString result = m_qsettings->value("double_click_behavior", "").toString(); return QEnumHelper::fromString(result, DoubleClickBehavior::Ignore); } Settings::MouseWheelBehavior Settings::mouseWheelBehavior() const { QString result = m_qsettings->value("mouse_wheel_behavior", "").toString(); return QEnumHelper::fromString(result, MouseWheelBehavior::Zoom); } Settings::WindowSizeBehavior Settings::initWindowSizeBehavior() const { QString result = m_qsettings->value("init_window_size_behavior", "").toString(); return QEnumHelper::fromString(result, WindowSizeBehavior::Maximized); } Qt::HighDpiScaleFactorRoundingPolicy Settings::hiDpiScaleFactorBehavior() const { QString result = m_qsettings->value("hidpi_scale_factor_behavior", "").toString(); return QEnumHelper::fromString(result, Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); } void Settings::setUseLightCheckerboard(bool light) { m_qsettings->setValue("use_light_checkerboard", light); m_qsettings->sync(); } void Settings::setLoopGallery(bool on) { m_qsettings->setValue("loop_gallery", on); m_qsettings->sync(); } void Settings::setSvgTiny12Only(bool on) { m_qsettings->setValue("svg_tiny12_only", on); m_qsettings->sync(); } void Settings::setDoubleClickBehavior(DoubleClickBehavior dcb) { m_qsettings->setValue("double_click_behavior", QEnumHelper::toString(dcb)); m_qsettings->sync(); } void Settings::setMouseWheelBehavior(MouseWheelBehavior mwb) { m_qsettings->setValue("mouse_wheel_behavior", QEnumHelper::toString(mwb)); m_qsettings->sync(); } void Settings::setInitWindowSizeBehavior(WindowSizeBehavior wsb) { m_qsettings->setValue("init_window_size_behavior", QEnumHelper::toString(wsb)); m_qsettings->sync(); } void Settings::setHiDpiScaleFactorBehavior(Qt::HighDpiScaleFactorRoundingPolicy hidpi) { m_qsettings->setValue("hidpi_scale_factor_behavior", QEnumHelper::toString(hidpi)); m_qsettings->sync(); } #if defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN) #include // QCoreApplication::applicationDirPath() parses the "applicationDirPath" from arg0, which... // 1. rely on a QApplication object instance // but we need to call QGuiApplication::setHighDpiScaleFactorRoundingPolicy() before QApplication get created // 2. arg0 is NOT garanteed to be the path of execution // see also: https://stackoverflow.com/questions/383973/is-args0-guaranteed-to-be-the-path-of-execution // This function is here mainly for #1. QString getApplicationDirPath() { WCHAR buffer[MAX_PATH]; GetModuleFileNameW(NULL, buffer, MAX_PATH); QString appPath = QString::fromWCharArray(buffer); return appPath.left(appPath.lastIndexOf('\\')); } #endif // defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN) Settings::Settings(QObject *parent) : QObject(parent) { QString configPath; #if defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN) QString portableConfigDirPath = QDir(getApplicationDirPath()).absoluteFilePath("data"); QFileInfo portableConfigDirInfo(portableConfigDirPath); if (portableConfigDirInfo.exists() && portableConfigDirInfo.isDir() && portableConfigDirInfo.isWritable()) { // we can use it. configPath = portableConfigDirPath; } #endif // defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN) if (configPath.isEmpty()) { // Should be %LOCALAPPDATA%\ under Windows, ~/.config/ under Linux. configPath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); } m_qsettings = new QSettings(QDir(configPath).absoluteFilePath("config.ini"), QSettings::IniFormat, this); qRegisterMetaType>(); }