Files
IfcOpenShell/src/ifcviewer-full/InterfaceSettings.cpp
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

190 lines
8.7 KiB
C++
Raw Normal View History

2026-05-11 09:17:45 +10:00
// This file was generated with the assistance of an AI coding tool.
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "InterfaceSettings.h"
#include "components/Style.h"
#include <QColor>
#include <QSettings>
namespace {
constexpr const char* kThemeModeKey = "interface/theme/mode";
constexpr const char* kThemeColorPrefix = "interface/theme/colors/";
using Spec = ifcinterface::InterfaceSettings::ThemeColorSpec;
const std::vector<Spec> kThemeColorSpecs = {
{"app_background", "App Background", ifcinterface::components::style::palette::app_background, "#eef1f5"},
{"border", "Border", ifcinterface::components::style::palette::border, "#c9d1dc"},
{"selection_background", "Selection Background", ifcinterface::components::style::palette::selection_background,
"#2f9e44"},
{"tab_bar_background", "Tab Bar Background", ifcinterface::components::style::palette::tab_bar_background,
"#eef1f5"},
{"tab_background", "Tab Background", ifcinterface::components::style::palette::tab_background, "#e3e8ef"},
{"ribbon_background", "Ribbon Background", ifcinterface::components::style::palette::ribbon_background,
"#e3e8ef"},
{"ribbon_button_hover", "Ribbon Button Hover", ifcinterface::components::style::palette::ribbon_button_hover,
"#d6dde7"},
{"ribbon_button_pressed", "Ribbon Button Pressed", ifcinterface::components::style::palette::ribbon_button_pressed,
"#cad3df"},
{"viewport_shell_background", "Viewport Shell Background",
ifcinterface::components::style::palette::viewport_shell_background, "#dbe1e8"},
{"viewport_background", "Viewport Background", ifcinterface::components::style::palette::viewport_background,
"#eef2f6"},
{"panel_background", "Panel Background", ifcinterface::components::style::palette::panel_background, "#ffffff"},
{"control_background", "Control Background", ifcinterface::components::style::palette::control_background,
"#f5f7fa"},
{"control_border_focus", "Control Border Focus", ifcinterface::components::style::palette::control_border_focus,
"#7c8ca3"},
{"box_background", "Box Background", ifcinterface::components::style::palette::box_background, "#f5f7fa"},
{"scroll_handle", "Scroll Handle", ifcinterface::components::style::palette::scroll_handle, "#b1bac8"},
{"scroll_handle_hover", "Scroll Handle Hover", ifcinterface::components::style::palette::scroll_handle_hover,
"#929daf"},
{"status_background", "Status Background", ifcinterface::components::style::palette::status_background,
"#edf1f5"},
{"section_header_background", "Section Header Background",
ifcinterface::components::style::palette::section_header_background, "#eef2f6"},
{"primary_text", "Primary Text", ifcinterface::components::style::palette::primary_text, "#1f2937"},
{"secondary_text", "Secondary Text", ifcinterface::components::style::palette::secondary_text, "#5b6676"},
{"disabled_text", "Disabled Text", ifcinterface::components::style::palette::disabled_text, "#8b95a3"},
{"warning_text", "Warning Text", ifcinterface::components::style::palette::warning_text, "#b26b00"},
{"selection_text", "Selection Text", ifcinterface::components::style::palette::selection_text, "#ffffff"},
{"hover_text", "Hover Text", ifcinterface::components::style::palette::hover_text, "#0f172a"},
{"icon_color", "Icon Color", "#e7ebf2", "#445066"},
{"icon_active_color", "Icon Active Color", "#ffffff", "#101828"},
{"icon_disabled_color", "Icon Disabled Color", "#6f7988", "#98a2b3"},
{"icon_accent_color", "Accent Icon Color", "#39b54a", "#2f9e44"},
{"icon_accent_active_color", "Accent Icon Active Color", "#53c763", "#267e37"},
};
int colorIndexForKey(const QString& key) {
for (size_t i = 0; i < kThemeColorSpecs.size(); ++i) {
if (QString::fromUtf8(kThemeColorSpecs[i].key) == key) {
return static_cast<int>(i);
}
}
return -1;
}
QString normalizedColor(const QString& value, const QString& fallback) {
const QString trimmed = value.trimmed();
if (!QColor::isValidColorName(trimmed)) return fallback;
return QColor(trimmed).name(QColor::HexRgb);
}
} // namespace
namespace ifcinterface {
InterfaceSettings& InterfaceSettings::instance() {
static InterfaceSettings inst;
return inst;
}
const std::vector<InterfaceSettings::ThemeColorSpec>& InterfaceSettings::themeColorSpecs() {
return kThemeColorSpecs;
}
InterfaceSettings::InterfaceSettings() {
custom_colors_.resize(kThemeColorSpecs.size());
load();
}
InterfaceSettings::ThemeMode InterfaceSettings::themeMode() const {
return theme_mode_;
}
void InterfaceSettings::setThemeMode(ThemeMode mode) {
if (theme_mode_ == mode) return;
theme_mode_ = mode;
persist();
emit themeModeChanged(mode);
emit themeChanged();
}
QString InterfaceSettings::color(const QString& key) const {
const int index = colorIndexForKey(key);
if (index < 0) return {};
const auto& spec = kThemeColorSpecs[static_cast<size_t>(index)];
switch (theme_mode_) {
case ThemeMode::Dark:
return QString::fromUtf8(spec.dark_default);
case ThemeMode::Light:
return QString::fromUtf8(spec.light_default);
case ThemeMode::Custom:
return customColor(key);
}
return QString::fromUtf8(spec.dark_default);
}
QString InterfaceSettings::customColor(const QString& key) const {
const int index = colorIndexForKey(key);
if (index < 0) return {};
const auto& spec = kThemeColorSpecs[static_cast<size_t>(index)];
const QString& stored = custom_colors_[static_cast<size_t>(index)];
return stored.isEmpty() ? QString::fromUtf8(spec.dark_default) : stored;
}
void InterfaceSettings::setCustomColor(const QString& key, const QString& value) {
const int index = colorIndexForKey(key);
if (index < 0) return;
const auto& spec = kThemeColorSpecs[static_cast<size_t>(index)];
const QString normalized = normalizedColor(value, QString::fromUtf8(spec.dark_default));
QString& stored = custom_colors_[static_cast<size_t>(index)];
if (stored == normalized) return;
stored = normalized;
persist();
if (theme_mode_ == ThemeMode::Custom) {
emit themeChanged();
}
}
void InterfaceSettings::load() {
QSettings settings;
int raw_mode = settings.value(kThemeModeKey, static_cast<int>(ThemeMode::Dark)).toInt();
if (raw_mode < static_cast<int>(ThemeMode::Dark) || raw_mode > static_cast<int>(ThemeMode::Custom)) {
raw_mode = static_cast<int>(ThemeMode::Dark);
}
theme_mode_ = static_cast<ThemeMode>(raw_mode);
for (size_t i = 0; i < kThemeColorSpecs.size(); ++i) {
const auto& spec = kThemeColorSpecs[i];
const QString stored = settings.value(QString::fromUtf8(kThemeColorPrefix) + QString::fromUtf8(spec.key),
QString::fromUtf8(spec.dark_default))
.toString();
custom_colors_[i] = normalizedColor(stored, QString::fromUtf8(spec.dark_default));
}
}
void InterfaceSettings::persist() const {
QSettings settings;
settings.setValue(kThemeModeKey, static_cast<int>(theme_mode_));
for (size_t i = 0; i < kThemeColorSpecs.size(); ++i) {
settings.setValue(QString::fromUtf8(kThemeColorPrefix) + QString::fromUtf8(kThemeColorSpecs[i].key),
custom_colors_[i]);
}
}
} // namespace ifcinterface