mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
Interface mockup 15
This commit is contained in:
@@ -725,7 +725,7 @@ void ViewportWindow::initGL() {
|
||||
|
||||
gl_->glEnable(GL_DEPTH_TEST);
|
||||
gl_->glEnable(GL_MULTISAMPLE);
|
||||
gl_->glClearColor(0.18f, 0.20f, 0.22f, 1.0f);
|
||||
gl_->glClearColor(background_color_.redF(), background_color_.greenF(), background_color_.blueF(), 1.0f);
|
||||
gl_->glCullFace(GL_BACK);
|
||||
if (AppSettings::instance().backfaceCulling()) gl_->glEnable(GL_CULL_FACE);
|
||||
else gl_->glDisable(GL_CULL_FACE);
|
||||
@@ -768,6 +768,18 @@ void ViewportWindow::initGL() {
|
||||
emit initialized();
|
||||
}
|
||||
|
||||
void ViewportWindow::setBackgroundColor(const QColor& color) {
|
||||
if (!color.isValid()) return;
|
||||
const QColor normalized = color.toRgb();
|
||||
if (background_color_ == normalized) return;
|
||||
background_color_ = normalized;
|
||||
if (gl_initialized_ && gl_) {
|
||||
context_->makeCurrent(this);
|
||||
gl_->glClearColor(background_color_.redF(), background_color_.greenF(), background_color_.blueF(), 1.0f);
|
||||
requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportWindow::enqueuePendingOperation(PendingOperation op) {
|
||||
pending_ops_.push_back(std::move(op));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QWindow>
|
||||
#include <QOpenGLContext>
|
||||
#include <QtOpenGL/QOpenGLFunctions_4_5_Core>
|
||||
#include <QColor>
|
||||
#include <QElapsedTimer>
|
||||
#include <QMatrix4x4>
|
||||
#include <QVector3D>
|
||||
@@ -312,6 +313,7 @@ public:
|
||||
void setFederatedFalseOrigin(const Eigen::Matrix4d& matrix_meters);
|
||||
void setModelCoordinateOperation(uint32_t model_id, const Eigen::Matrix4d& matrix_meters);
|
||||
void setModelTransformation(uint32_t model_id, const Eigen::Matrix4d& matrix_meters);
|
||||
void setBackgroundColor(const QColor& color);
|
||||
|
||||
// Selection. The viewport owns a SelectionState that tracks both
|
||||
// the multi-set and the "active" (last single-clicked) id. External
|
||||
@@ -607,6 +609,7 @@ private:
|
||||
QOpenGLContext* context_ = nullptr;
|
||||
QOpenGLFunctions_4_5_Core* gl_ = nullptr;
|
||||
bool gl_initialized_ = false;
|
||||
QColor background_color_ = QColor("#202329");
|
||||
std::deque<PendingOperation> pending_ops_;
|
||||
|
||||
// Shaders
|
||||
|
||||
@@ -27,6 +27,8 @@ set(INTERFACE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ElementRegistry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ElementRegistry.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/InterfaceSettings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/InterfaceSettings.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SessionState.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SessionState.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.cpp
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// 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
|
||||
@@ -0,0 +1,72 @@
|
||||
// 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCINTERFACE_INTERFACESETTINGS_H
|
||||
#define IFCINTERFACE_INTERFACESETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
namespace ifcinterface {
|
||||
|
||||
class InterfaceSettings : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class ThemeMode {
|
||||
Dark = 0,
|
||||
Light = 1,
|
||||
Custom = 2,
|
||||
};
|
||||
Q_ENUM(ThemeMode)
|
||||
|
||||
struct ThemeColorSpec {
|
||||
const char* key;
|
||||
const char* label;
|
||||
const char* dark_default;
|
||||
const char* light_default;
|
||||
};
|
||||
|
||||
static InterfaceSettings& instance();
|
||||
static const std::vector<ThemeColorSpec>& themeColorSpecs();
|
||||
|
||||
ThemeMode themeMode() const;
|
||||
void setThemeMode(ThemeMode mode);
|
||||
|
||||
QString color(const QString& key) const;
|
||||
QString customColor(const QString& key) const;
|
||||
void setCustomColor(const QString& key, const QString& value);
|
||||
|
||||
signals:
|
||||
void themeModeChanged(ThemeMode mode);
|
||||
void themeChanged();
|
||||
|
||||
private:
|
||||
InterfaceSettings();
|
||||
void load();
|
||||
void persist() const;
|
||||
|
||||
ThemeMode theme_mode_ = ThemeMode::Dark;
|
||||
std::vector<QString> custom_colors_;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface
|
||||
|
||||
#endif
|
||||
@@ -299,7 +299,6 @@ QWidget* MainWindow::buildPanelsRibbonPage() {
|
||||
|
||||
void MainWindow::setupRibbon() {
|
||||
auto* shell = new QFrame(this);
|
||||
shell->setObjectName("ribbonShell");
|
||||
|
||||
auto* shell_layout = new QVBoxLayout(shell);
|
||||
shell_layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@@ -36,7 +36,7 @@ QToolButton* makeButton(const QString& text,
|
||||
auto* button = new QToolButton(parent);
|
||||
button->setObjectName("ribbonButton");
|
||||
button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
||||
button->setIcon(components::icons::makeTintedSvgIcon(icon_path));
|
||||
button->setIcon(components::icons::makeAccentSvgIcon(icon_path));
|
||||
button->setIconSize(QSize(20, 20));
|
||||
button->setText(text);
|
||||
button->setMinimumSize(QSize(90, 68));
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Dialog.h"
|
||||
|
||||
#include "Style.h"
|
||||
#include "Tabs.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFrame>
|
||||
@@ -83,4 +84,60 @@ void Dialog::addFooterWidget(QWidget* widget) {
|
||||
footer_layout_->addWidget(widget);
|
||||
}
|
||||
|
||||
TabbedDialog::TabbedDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
auto* outer_layout = new QVBoxLayout(this);
|
||||
outer_layout->setContentsMargins(style::metrics::padding,
|
||||
style::metrics::padding,
|
||||
style::metrics::padding,
|
||||
style::metrics::padding);
|
||||
outer_layout->setSpacing(0);
|
||||
|
||||
auto* frame = new QFrame(this);
|
||||
frame->setObjectName("panel");
|
||||
auto* frame_layout = new QVBoxLayout(frame);
|
||||
frame_layout->setContentsMargins(0,
|
||||
style::metrics::section_body_padding,
|
||||
0,
|
||||
style::metrics::section_body_padding);
|
||||
frame_layout->setSpacing(0);
|
||||
|
||||
tabs_ = new TabWidget(frame);
|
||||
frame_layout->addWidget(tabs_, 1);
|
||||
|
||||
auto* footer = new QWidget(frame);
|
||||
footer_layout_ = new QVBoxLayout(footer);
|
||||
footer_layout_->setContentsMargins(style::metrics::section_body_padding,
|
||||
style::metrics::section_body_padding,
|
||||
style::metrics::section_body_padding,
|
||||
0);
|
||||
footer_layout_->setSpacing(style::metrics::section_body_padding);
|
||||
footer_layout_->setAlignment(Qt::AlignTop);
|
||||
frame_layout->addWidget(footer);
|
||||
|
||||
outer_layout->addWidget(frame);
|
||||
}
|
||||
|
||||
void TabbedDialog::addTab(const QString& title, QWidget* widget) {
|
||||
auto* scroll = new QScrollArea(tabs_);
|
||||
scroll->setWidgetResizable(true);
|
||||
scroll->setFrameShape(QFrame::NoFrame);
|
||||
|
||||
auto* scroll_body = new QWidget(scroll);
|
||||
scroll_body->setObjectName("panelScrollBody");
|
||||
auto* layout = new QVBoxLayout(scroll_body);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(style::metrics::section_body_padding);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
layout->addWidget(widget);
|
||||
|
||||
scroll->setWidget(scroll_body);
|
||||
tabs_->addTab(scroll, title);
|
||||
}
|
||||
|
||||
void TabbedDialog::addFooterWidget(QWidget* widget) {
|
||||
footer_layout_->addWidget(widget);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::components
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
class QVBoxLayout;
|
||||
class QWidget;
|
||||
class QTabWidget;
|
||||
|
||||
namespace ifcinterface::components {
|
||||
|
||||
@@ -43,6 +44,20 @@ private:
|
||||
QVBoxLayout* footer_layout_ = nullptr;
|
||||
};
|
||||
|
||||
class TabbedDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TabbedDialog(QWidget* parent = nullptr);
|
||||
|
||||
void addTab(const QString& title, QWidget* widget);
|
||||
void addFooterWidget(QWidget* widget);
|
||||
|
||||
private:
|
||||
QTabWidget* tabs_ = nullptr;
|
||||
QVBoxLayout* footer_layout_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::components
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
|
||||
#include "Style.h"
|
||||
|
||||
#include "../InterfaceSettings.h"
|
||||
|
||||
namespace ifcinterface::components::style {
|
||||
|
||||
QString buildAppStyleSheet() {
|
||||
const auto& theme = ifcinterface::InterfaceSettings::instance();
|
||||
QString stylesheet = QStringLiteral(R"(
|
||||
QMainWindow#appWindow {
|
||||
background: ${app_background};
|
||||
@@ -47,15 +50,11 @@ QString buildAppStyleSheet() {
|
||||
background: ${app_background};
|
||||
color: ${primary_text};
|
||||
}
|
||||
QFrame#ribbonShell {
|
||||
background: ${ribbon_shell_background};
|
||||
border-bottom: 1px solid ${border};
|
||||
}
|
||||
QTabBar#appTabBar {
|
||||
background: ${ribbon_shell_background};
|
||||
background: ${tab_bar_background};
|
||||
}
|
||||
QTabBar#appTabBar::tab {
|
||||
background: transparent;
|
||||
background: ${tab_background};
|
||||
color: ${secondary_text};
|
||||
padding: 8px 14px;
|
||||
margin-right: 2px;
|
||||
@@ -66,10 +65,10 @@ QString buildAppStyleSheet() {
|
||||
border-bottom: 2px solid ${selection_background};
|
||||
}
|
||||
QTabBar#appTabBar::tab:hover {
|
||||
color: ${ribbon_tab_hover_text};
|
||||
color: ${hover_text};
|
||||
}
|
||||
QFrame#ribbonBand {
|
||||
background: ${ribbon_band_background};
|
||||
background: ${ribbon_background};
|
||||
border-top: 1px solid ${border};
|
||||
}
|
||||
QTabWidget#appTabWidget::pane {
|
||||
@@ -107,7 +106,6 @@ QString buildAppStyleSheet() {
|
||||
border-top: none;
|
||||
}
|
||||
QFrame#viewportFrame {
|
||||
background: ${viewport_background};
|
||||
border: 1px solid ${border};
|
||||
}
|
||||
QDockWidget {
|
||||
@@ -146,13 +144,12 @@ QString buildAppStyleSheet() {
|
||||
font-weight: 600;
|
||||
}
|
||||
QToolButton#panelTitleButton {
|
||||
color: ${panel_title_button};
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
QToolButton#panelTitleButton:hover {
|
||||
color: ${ribbon_tab_hover_text};
|
||||
background: ${panel_title_button_hover};
|
||||
color: ${hover_text};
|
||||
background: ${ribbon_button_hover};
|
||||
}
|
||||
QFrame#panel {
|
||||
background: ${panel_background};
|
||||
@@ -440,7 +437,7 @@ QString buildAppStyleSheet() {
|
||||
margin: 0;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton:hover {
|
||||
color: ${ribbon_tab_hover_text};
|
||||
color: ${hover_text};
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton::menu-indicator {
|
||||
image: none;
|
||||
@@ -452,13 +449,13 @@ QString buildAppStyleSheet() {
|
||||
padding: ${section_header_padding}px;
|
||||
}
|
||||
QToolButton#panelSectionFilterToggle:hover {
|
||||
background: ${panel_title_button_hover};
|
||||
background: ${ribbon_button_hover};
|
||||
}
|
||||
QWidget#panelSectionBody {
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#keyValueValueLabel {
|
||||
color: ${key_value_value_text};
|
||||
color: ${primary_text};
|
||||
background: transparent;
|
||||
}
|
||||
)");
|
||||
@@ -468,33 +465,31 @@ QString buildAppStyleSheet() {
|
||||
stylesheet.replace("${section_header_padding}", QString::number(metrics::section_header_padding));
|
||||
stylesheet.replace("${font_small}", QString::number(typography::small));
|
||||
|
||||
stylesheet.replace("${app_background}", palette::app_background);
|
||||
stylesheet.replace("${border}", palette::border);
|
||||
stylesheet.replace("${selection_background}", palette::selection_background);
|
||||
stylesheet.replace("${selection_text}", palette::selection_text);
|
||||
stylesheet.replace("${ribbon_shell_background}", palette::ribbon_shell_background);
|
||||
stylesheet.replace("${ribbon_tab_hover_text}", palette::ribbon_tab_hover_text);
|
||||
stylesheet.replace("${ribbon_band_background}", palette::ribbon_band_background);
|
||||
stylesheet.replace("${ribbon_button_hover}", palette::ribbon_button_hover);
|
||||
stylesheet.replace("${ribbon_button_pressed}", palette::ribbon_button_pressed);
|
||||
stylesheet.replace("${viewport_shell_background}", palette::viewport_shell_background);
|
||||
stylesheet.replace("${viewport_background}", palette::viewport_background);
|
||||
stylesheet.replace("${panel_title_button}", palette::panel_title_button);
|
||||
stylesheet.replace("${panel_title_button_hover}", palette::panel_title_button_hover);
|
||||
stylesheet.replace("${panel_background}", palette::panel_background);
|
||||
stylesheet.replace("${control_background}", palette::control_background);
|
||||
stylesheet.replace("${control_border_focus}", palette::control_border_focus);
|
||||
stylesheet.replace("${box_background}", palette::box_background);
|
||||
stylesheet.replace("${scroll_handle}", palette::scroll_handle);
|
||||
stylesheet.replace("${scroll_handle_hover}", palette::scroll_handle_hover);
|
||||
stylesheet.replace("${status_background}", palette::status_background);
|
||||
stylesheet.replace("${section_header_background}", palette::section_header_background);
|
||||
stylesheet.replace("${key_value_value_text}", palette::key_value_value_text);
|
||||
stylesheet.replace("${app_background}", theme.color("app_background"));
|
||||
stylesheet.replace("${border}", theme.color("border"));
|
||||
stylesheet.replace("${selection_background}", theme.color("selection_background"));
|
||||
stylesheet.replace("${selection_text}", theme.color("selection_text"));
|
||||
stylesheet.replace("${tab_bar_background}", theme.color("tab_bar_background"));
|
||||
stylesheet.replace("${tab_background}", theme.color("tab_background"));
|
||||
stylesheet.replace("${hover_text}", theme.color("hover_text"));
|
||||
stylesheet.replace("${ribbon_background}", theme.color("ribbon_background"));
|
||||
stylesheet.replace("${ribbon_button_hover}", theme.color("ribbon_button_hover"));
|
||||
stylesheet.replace("${ribbon_button_pressed}", theme.color("ribbon_button_pressed"));
|
||||
stylesheet.replace("${viewport_shell_background}", theme.color("viewport_shell_background"));
|
||||
stylesheet.replace("${viewport_background}", theme.color("viewport_background"));
|
||||
stylesheet.replace("${panel_background}", theme.color("panel_background"));
|
||||
stylesheet.replace("${control_background}", theme.color("control_background"));
|
||||
stylesheet.replace("${control_border_focus}", theme.color("control_border_focus"));
|
||||
stylesheet.replace("${box_background}", theme.color("box_background"));
|
||||
stylesheet.replace("${scroll_handle}", theme.color("scroll_handle"));
|
||||
stylesheet.replace("${scroll_handle_hover}", theme.color("scroll_handle_hover"));
|
||||
stylesheet.replace("${status_background}", theme.color("status_background"));
|
||||
stylesheet.replace("${section_header_background}", theme.color("section_header_background"));
|
||||
|
||||
stylesheet.replace("${primary_text}", palette::primary_text);
|
||||
stylesheet.replace("${secondary_text}", palette::secondary_text);
|
||||
stylesheet.replace("${disabled_text}", palette::disabled_text);
|
||||
stylesheet.replace("${warning_text}", palette::warning_text);
|
||||
stylesheet.replace("${primary_text}", theme.color("primary_text"));
|
||||
stylesheet.replace("${secondary_text}", theme.color("secondary_text"));
|
||||
stylesheet.replace("${disabled_text}", theme.color("disabled_text"));
|
||||
stylesheet.replace("${warning_text}", theme.color("warning_text"));
|
||||
|
||||
return stylesheet;
|
||||
}
|
||||
|
||||
@@ -43,15 +43,13 @@ namespace ifcinterface::components::style::palette {
|
||||
inline constexpr auto app_background = "#26292f";
|
||||
inline constexpr auto border = "#3e444e";
|
||||
inline constexpr auto selection_background = "#39b54a";
|
||||
inline constexpr auto ribbon_shell_background = "#2d3138";
|
||||
inline constexpr auto ribbon_tab_hover_text = "#ffffff";
|
||||
inline constexpr auto ribbon_band_background = "#31353d";
|
||||
inline constexpr auto tab_bar_background = "#26292f";
|
||||
inline constexpr auto tab_background = "#31353d";
|
||||
inline constexpr auto ribbon_background = "#31353d";
|
||||
inline constexpr auto ribbon_button_hover = "#3a3f48";
|
||||
inline constexpr auto ribbon_button_pressed = "#24282f";
|
||||
inline constexpr auto viewport_shell_background = "#202329";
|
||||
inline constexpr auto viewport_background = "#1a1d22";
|
||||
inline constexpr auto panel_title_button = "#8e97a5";
|
||||
inline constexpr auto panel_title_button_hover = "#353a42";
|
||||
inline constexpr auto viewport_background = "#2e3338";
|
||||
inline constexpr auto panel_background = "#2b2f36";
|
||||
inline constexpr auto control_background = "#31353d";
|
||||
inline constexpr auto control_border_focus = "#5b6472";
|
||||
@@ -60,13 +58,13 @@ inline constexpr auto scroll_handle = "#525a67";
|
||||
inline constexpr auto scroll_handle_hover = "#697385";
|
||||
inline constexpr auto status_background = "#26292f";
|
||||
inline constexpr auto section_header_background = "#26292f";
|
||||
inline constexpr auto key_value_value_text = "#dce2eb";
|
||||
|
||||
inline constexpr auto primary_text = "#d0d5dd";
|
||||
inline constexpr auto secondary_text = "#9aa4b3";
|
||||
inline constexpr auto disabled_text = "#8f98a6";
|
||||
inline constexpr auto warning_text = "#e4b35a";
|
||||
inline constexpr auto selection_text = "#14161a";
|
||||
inline constexpr auto hover_text = "#ffffff";
|
||||
|
||||
} // namespace ifcinterface::components::style::palette
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "SvgIcon.h"
|
||||
|
||||
#include "../InterfaceSettings.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QPainter>
|
||||
#include <QRegularExpression>
|
||||
@@ -61,12 +63,24 @@ QIcon makeTintedSvgIcon(const QString& icon_path, const QString& normal,
|
||||
return icon;
|
||||
}
|
||||
|
||||
QIcon makeAccentSvgIcon(const QString& icon_path) {
|
||||
const auto& theme = ifcinterface::InterfaceSettings::instance();
|
||||
return makeTintedSvgIcon(icon_path,
|
||||
theme.color("icon_accent_color"),
|
||||
theme.color("icon_accent_active_color"),
|
||||
theme.color("icon_disabled_color"));
|
||||
}
|
||||
|
||||
QIcon makeSvgIcon(const QString& icon_path) {
|
||||
return makeTintedSvgIcon(icon_path, "#e7ebf2", "#ffffff", "#6f7988");
|
||||
const auto& theme = ifcinterface::InterfaceSettings::instance();
|
||||
return makeTintedSvgIcon(icon_path,
|
||||
theme.color("icon_color"),
|
||||
theme.color("icon_active_color"),
|
||||
theme.color("icon_disabled_color"));
|
||||
}
|
||||
|
||||
QPixmap makeSvgPixmap(const QString& icon_path, const QSize& size) {
|
||||
return renderTintedSvgPixmap(icon_path, "#e7ebf2", size);
|
||||
return renderTintedSvgPixmap(icon_path, ifcinterface::InterfaceSettings::instance().color("icon_color"), size);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::components::icons
|
||||
|
||||
@@ -33,6 +33,7 @@ QIcon makeTintedSvgIcon(const QString& icon_path,
|
||||
const QString& normal = "#39b54a",
|
||||
const QString& active = "#53c763",
|
||||
const QString& disabled = "#6f7988");
|
||||
QIcon makeAccentSvgIcon(const QString& icon_path);
|
||||
QIcon makeSvgIcon(const QString& icon_path);
|
||||
QPixmap makeSvgPixmap(const QString& icon_path, const QSize& size);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "InterfaceSettings.h"
|
||||
#include "components/Style.h"
|
||||
|
||||
#include <QApplication>
|
||||
@@ -65,7 +66,14 @@ int main(int argc, char* argv[]) {
|
||||
parser.process(app);
|
||||
|
||||
installUiFont();
|
||||
app.setStyleSheet(ifcinterface::components::style::buildAppStyleSheet());
|
||||
const auto applyStyle = [&app]() {
|
||||
app.setStyleSheet(ifcinterface::components::style::buildAppStyleSheet());
|
||||
};
|
||||
applyStyle();
|
||||
QObject::connect(&ifcinterface::InterfaceSettings::instance(),
|
||||
&ifcinterface::InterfaceSettings::themeChanged,
|
||||
&app,
|
||||
applyStyle);
|
||||
|
||||
ifcinterface::shell::MainWindow window;
|
||||
window.show();
|
||||
|
||||
@@ -65,7 +65,6 @@ AddModelDialog::AddModelDialog(QWidget* parent)
|
||||
setObjectName("appDialog");
|
||||
setWindowTitle("Add Model");
|
||||
setModal(true);
|
||||
setStyleSheet(components::style::buildAppStyleSheet());
|
||||
setupUi();
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,10 @@ ModelsPanel::ModelsPanel(QWidget* parent)
|
||||
|
||||
void ModelsPanel::setNodes(const QList<TreeNode>& nodes) {
|
||||
tree_->clear();
|
||||
const bool has_hierarchy = std::any_of(nodes.begin(), nodes.end(), [](const TreeNode& node) {
|
||||
return !node.children.isEmpty() || node.kind == ItemKind::Group;
|
||||
});
|
||||
tree_->setRootIsDecorated(has_hierarchy);
|
||||
for (const auto& node : nodes) {
|
||||
addNode(tree_->invisibleRootItem(), node);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ QLabel* makeReadOnlyValue(QWidget* parent) {
|
||||
} // namespace
|
||||
|
||||
SettingsDialog::SettingsDialog(ifcinterface::SessionState* session_state, QWidget* parent)
|
||||
: components::Dialog(parent, true)
|
||||
: components::TabbedDialog(parent)
|
||||
, session_state_(session_state)
|
||||
, federation_(session_state ? session_state->federation() : nullptr)
|
||||
, loader_(session_state ? session_state->loader() : nullptr)
|
||||
@@ -145,7 +145,6 @@ SettingsDialog::SettingsDialog(ifcinterface::SessionState* session_state, QWidge
|
||||
setWindowTitle("Model Settings");
|
||||
setModal(true);
|
||||
resize(980, 560);
|
||||
setStyleSheet(components::style::buildAppStyleSheet());
|
||||
setupUi();
|
||||
}
|
||||
|
||||
@@ -158,9 +157,7 @@ void SettingsDialog::showEvent(QShowEvent* event) {
|
||||
}
|
||||
|
||||
void SettingsDialog::setupUi() {
|
||||
auto* tabs = new components::TabWidget(this);
|
||||
|
||||
auto* federation_tab = new QWidget(tabs);
|
||||
auto* federation_tab = new QWidget(this);
|
||||
auto* federation_layout = new QVBoxLayout(federation_tab);
|
||||
federation_layout->setContentsMargins(0, 0, 0, 0);
|
||||
federation_layout->setSpacing(components::style::metrics::padding);
|
||||
@@ -213,7 +210,7 @@ void SettingsDialog::setupUi() {
|
||||
federation_layout->addWidget(origin_section);
|
||||
federation_layout->addStretch(1);
|
||||
|
||||
auto* model_tab = new QWidget(tabs);
|
||||
auto* model_tab = new QWidget(this);
|
||||
auto* model_layout = new QVBoxLayout(model_tab);
|
||||
model_layout->setContentsMargins(0, 0, 0, 0);
|
||||
model_layout->setSpacing(components::style::metrics::padding);
|
||||
@@ -324,8 +321,8 @@ void SettingsDialog::setupUi() {
|
||||
model_layout->addWidget(georef_section);
|
||||
model_layout->addWidget(table_section);
|
||||
|
||||
tabs->addTab(federation_tab, "Federation");
|
||||
tabs->addTab(model_tab, "Model");
|
||||
addTab("Federation", federation_tab);
|
||||
addTab("Model", model_tab);
|
||||
|
||||
connect(model_table_, &QTableWidget::currentCellChanged, this,
|
||||
[this](int /*current_row*/, int /*current_column*/, int /*previous_row*/, int /*previous_column*/) {
|
||||
@@ -344,7 +341,6 @@ void SettingsDialog::setupUi() {
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, [this]() { onAccepted(); });
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
addBodyWidget(tabs);
|
||||
addFooterWidget(buttons);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class SessionState;
|
||||
|
||||
namespace ifcinterface::modules::models {
|
||||
|
||||
class SettingsDialog : public components::Dialog {
|
||||
class SettingsDialog : public components::TabbedDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsDialog(ifcinterface::SessionState* session_state, QWidget* parent = nullptr);
|
||||
|
||||
@@ -20,19 +20,21 @@
|
||||
|
||||
#include "Dialog.h"
|
||||
|
||||
#include "../../InterfaceSettings.h"
|
||||
#include "../../../ifcviewer/AppSettings.h"
|
||||
#include "../../components/Dialog.h"
|
||||
#include "../../components/Section.h"
|
||||
#include "../../components/Style.h"
|
||||
#include "../../components/SvgIcon.h"
|
||||
#include "../../components/Tabs.h"
|
||||
#include "../../components/Style.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QColorDialog>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFrame>
|
||||
#include <QFormLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
@@ -43,13 +45,12 @@
|
||||
namespace ifcinterface::modules::settings {
|
||||
|
||||
SettingsDialog::SettingsDialog(QWidget* parent)
|
||||
: components::Dialog(parent)
|
||||
: components::TabbedDialog(parent)
|
||||
{
|
||||
setObjectName("appDialog");
|
||||
setWindowTitle("Settings");
|
||||
setModal(true);
|
||||
resize(520, 420);
|
||||
setStyleSheet(components::style::buildAppStyleSheet());
|
||||
setupUi();
|
||||
}
|
||||
|
||||
@@ -59,12 +60,11 @@ void SettingsDialog::showEvent(QShowEvent* event) {
|
||||
}
|
||||
|
||||
void SettingsDialog::setupUi() {
|
||||
auto* tabs = new components::TabWidget(this);
|
||||
|
||||
auto* graphics_tab = new QWidget(tabs);
|
||||
auto* graphics_tab = new QWidget(this);
|
||||
auto* graphics_layout = new QVBoxLayout(graphics_tab);
|
||||
graphics_layout->setContentsMargins(0, 0, 0, 0);
|
||||
graphics_layout->setSpacing(components::style::metrics::padding);
|
||||
graphics_layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
auto* general_section = new components::Section("General", components::SectionHeaderMode::Visible, graphics_tab);
|
||||
auto* general_body = new QWidget(general_section);
|
||||
@@ -159,14 +159,15 @@ void SettingsDialog::setupUi() {
|
||||
|
||||
// Navigation tab: orbit / pan presets. Selection always stays on
|
||||
// LMB so click + box-select keep working regardless of preset.
|
||||
auto* navigation_tab = new QWidget(tabs);
|
||||
auto* interface_tab = new QWidget(this);
|
||||
{
|
||||
auto* layout = new QVBoxLayout(navigation_tab);
|
||||
auto* layout = new QVBoxLayout(interface_tab);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(components::style::metrics::padding);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
auto* section = new components::Section(
|
||||
"Navigation", components::SectionHeaderMode::Visible, navigation_tab);
|
||||
"Navigation", components::SectionHeaderMode::Visible, interface_tab);
|
||||
auto* body = new QWidget(section);
|
||||
auto* form = new QFormLayout(body);
|
||||
form->setContentsMargins(0, 0, 0, 0);
|
||||
@@ -187,14 +188,63 @@ void SettingsDialog::setupUi() {
|
||||
|
||||
section->addBodyWidget(body);
|
||||
layout->addWidget(section);
|
||||
layout->addStretch(1);
|
||||
|
||||
auto* theme_section = new components::Section(
|
||||
"Theme", components::SectionHeaderMode::Visible, interface_tab);
|
||||
auto* theme_body = new QWidget(theme_section);
|
||||
auto* theme_layout = new QVBoxLayout(theme_body);
|
||||
theme_layout->setContentsMargins(0, 0, 0, 0);
|
||||
theme_layout->setSpacing(components::style::metrics::padding);
|
||||
|
||||
auto* theme_form = new QFormLayout();
|
||||
theme_form->setContentsMargins(0, 0, 0, 0);
|
||||
theme_form->setHorizontalSpacing(16);
|
||||
theme_form->setVerticalSpacing(10);
|
||||
|
||||
theme_mode_combo_ = new QComboBox(theme_body);
|
||||
theme_mode_combo_->addItem("Dark", static_cast<int>(ifcinterface::InterfaceSettings::ThemeMode::Dark));
|
||||
theme_mode_combo_->addItem("Light", static_cast<int>(ifcinterface::InterfaceSettings::ThemeMode::Light));
|
||||
theme_mode_combo_->addItem("Custom", static_cast<int>(ifcinterface::InterfaceSettings::ThemeMode::Custom));
|
||||
theme_form->addRow("Preset", theme_mode_combo_);
|
||||
|
||||
theme_custom_body_ = new QWidget(theme_body);
|
||||
auto* custom_grid = new QGridLayout(theme_custom_body_);
|
||||
custom_grid->setContentsMargins(0, 0, 0, 0);
|
||||
custom_grid->setHorizontalSpacing(12);
|
||||
custom_grid->setVerticalSpacing(8);
|
||||
|
||||
int row = 0;
|
||||
for (const auto& spec : ifcinterface::InterfaceSettings::themeColorSpecs()) {
|
||||
auto* label = new QLabel(QString::fromUtf8(spec.label), theme_custom_body_);
|
||||
auto* edit = new QLineEdit(theme_custom_body_);
|
||||
edit->setPlaceholderText("#000000");
|
||||
auto* pick = new QPushButton("Pick", theme_custom_body_);
|
||||
connect(pick, &QPushButton::clicked, this, [this, edit]() { pickThemeColor(edit); });
|
||||
custom_grid->addWidget(label, row, 0);
|
||||
custom_grid->addWidget(edit, row, 1);
|
||||
custom_grid->addWidget(pick, row, 2);
|
||||
theme_color_editors_.push_back({QString::fromUtf8(spec.key), edit});
|
||||
++row;
|
||||
}
|
||||
|
||||
auto* theme_form_widget = new QWidget(theme_body);
|
||||
theme_form_widget->setLayout(theme_form);
|
||||
theme_layout->addWidget(theme_form_widget);
|
||||
theme_layout->addWidget(theme_custom_body_);
|
||||
theme_section->addBodyWidget(theme_body);
|
||||
layout->addWidget(theme_section);
|
||||
|
||||
connect(theme_mode_combo_, &QComboBox::currentIndexChanged, this, [this](int) {
|
||||
updateThemeEditorEnabled();
|
||||
});
|
||||
}
|
||||
|
||||
auto make_placeholder_tab = [tabs](const QString& title, const QString& detail) {
|
||||
auto* tab = new QWidget(tabs);
|
||||
auto make_placeholder_tab = [this](const QString& title, const QString& detail) {
|
||||
auto* tab = new QWidget(this);
|
||||
auto* layout = new QVBoxLayout(tab);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(components::style::metrics::padding);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
auto* section = new components::Section(title, components::SectionHeaderMode::Visible, tab);
|
||||
auto* body = new QWidget(section);
|
||||
@@ -215,14 +265,10 @@ void SettingsDialog::setupUi() {
|
||||
return tab;
|
||||
};
|
||||
|
||||
tabs->addTab(navigation_tab, "Navigation");
|
||||
tabs->addTab(make_placeholder_tab("Keybindings", "Shortcut presets and command bindings will live here."),
|
||||
"Keybindings");
|
||||
tabs->addTab(graphics_tab, "Graphics");
|
||||
tabs->addTab(make_placeholder_tab("Theme", "Theme, density, and UI appearance settings will live here."),
|
||||
"Theme");
|
||||
tabs->addTab(make_placeholder_tab("About", "Version, credits, and environment information will live here."),
|
||||
"About");
|
||||
addTab("Interface", interface_tab);
|
||||
addTab("Keybindings", make_placeholder_tab("Keybindings", "Shortcut presets and command bindings will live here."));
|
||||
addTab("Graphics", graphics_tab);
|
||||
addTab("About", make_placeholder_tab("About", "Version, credits, and environment information will live here."));
|
||||
|
||||
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
if (auto* ok = buttons->button(QDialogButtonBox::Ok)) {
|
||||
@@ -236,7 +282,6 @@ void SettingsDialog::setupUi() {
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &SettingsDialog::onAccepted);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
addBodyWidget(tabs);
|
||||
addFooterWidget(buttons);
|
||||
}
|
||||
|
||||
@@ -253,6 +298,37 @@ void SettingsDialog::syncFromSettings() {
|
||||
hiz_enabled_check_->setChecked(AppSettings::instance().hizEnabled());
|
||||
hiz_resolution_spin_->setValue(AppSettings::instance().hizResolution());
|
||||
nav_preset_combo_->setCurrentIndex(static_cast<int>(AppSettings::instance().navPreset()));
|
||||
syncThemeSettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::syncThemeSettings() {
|
||||
const auto& settings = ifcinterface::InterfaceSettings::instance();
|
||||
const int idx = theme_mode_combo_->findData(static_cast<int>(settings.themeMode()));
|
||||
theme_mode_combo_->setCurrentIndex(idx >= 0 ? idx : 0);
|
||||
for (auto& editor : theme_color_editors_) {
|
||||
editor.edit->setText(settings.customColor(editor.key));
|
||||
}
|
||||
updateThemeEditorEnabled();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateThemeEditorEnabled() {
|
||||
if (!theme_mode_combo_ || !theme_custom_body_) return;
|
||||
const auto mode =
|
||||
static_cast<ifcinterface::InterfaceSettings::ThemeMode>(theme_mode_combo_->currentData().toInt());
|
||||
const bool is_custom = mode == ifcinterface::InterfaceSettings::ThemeMode::Custom;
|
||||
theme_custom_body_->setVisible(is_custom);
|
||||
theme_custom_body_->setEnabled(is_custom);
|
||||
}
|
||||
|
||||
void SettingsDialog::pickThemeColor(QLineEdit* edit) {
|
||||
QColorDialog dialog(QColor(edit->text()), this);
|
||||
dialog.setObjectName("appDialog");
|
||||
dialog.setWindowTitle("Choose Color");
|
||||
dialog.setOption(QColorDialog::DontUseNativeDialog, true);
|
||||
if (dialog.exec() != QDialog::Accepted) return;
|
||||
const QColor color = dialog.selectedColor();
|
||||
if (!color.isValid()) return;
|
||||
edit->setText(color.name(QColor::HexRgb));
|
||||
}
|
||||
|
||||
void SettingsDialog::onAccepted() {
|
||||
@@ -269,6 +345,12 @@ void SettingsDialog::onAccepted() {
|
||||
AppSettings::instance().setHizResolution(hiz_resolution_spin_->value());
|
||||
AppSettings::instance().setNavPreset(
|
||||
static_cast<AppSettings::NavPreset>(nav_preset_combo_->currentIndex()));
|
||||
auto& interface_settings = ifcinterface::InterfaceSettings::instance();
|
||||
interface_settings.setThemeMode(
|
||||
static_cast<ifcinterface::InterfaceSettings::ThemeMode>(theme_mode_combo_->currentData().toInt()));
|
||||
for (const auto& editor : theme_color_editors_) {
|
||||
interface_settings.setCustomColor(editor.key, editor.edit->text());
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,16 +23,20 @@
|
||||
|
||||
#include "../../components/Dialog.h"
|
||||
|
||||
#include <QString>
|
||||
#include <vector>
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
class QLineEdit;
|
||||
class QShowEvent;
|
||||
class QSpinBox;
|
||||
class QWidget;
|
||||
|
||||
namespace ifcinterface::modules::settings {
|
||||
|
||||
class SettingsDialog : public components::Dialog {
|
||||
class SettingsDialog : public components::TabbedDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsDialog(QWidget* parent = nullptr);
|
||||
@@ -43,8 +47,16 @@ protected:
|
||||
private:
|
||||
void setupUi();
|
||||
void syncFromSettings();
|
||||
void syncThemeSettings();
|
||||
void updateThemeEditorEnabled();
|
||||
void pickThemeColor(QLineEdit* edit);
|
||||
void onAccepted();
|
||||
|
||||
struct ThemeColorEditor {
|
||||
QString key;
|
||||
QLineEdit* edit = nullptr;
|
||||
};
|
||||
|
||||
QLineEdit* geometry_library_edit_ = nullptr;
|
||||
QCheckBox* show_stats_check_ = nullptr;
|
||||
QCheckBox* backface_culling_check_ = nullptr;
|
||||
@@ -57,6 +69,9 @@ private:
|
||||
QCheckBox* hiz_enabled_check_ = nullptr;
|
||||
QSpinBox* hiz_resolution_spin_ = nullptr;
|
||||
QComboBox* nav_preset_combo_ = nullptr;
|
||||
QComboBox* theme_mode_combo_ = nullptr;
|
||||
QWidget* theme_custom_body_ = nullptr;
|
||||
std::vector<ThemeColorEditor> theme_color_editors_;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::settings
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Controller.h"
|
||||
|
||||
#include "../../InterfaceSettings.h"
|
||||
#include "../../SessionState.h"
|
||||
#include "../../../ifcviewer/AppSettings.h"
|
||||
#include "../../../ifcviewer/Federation.h"
|
||||
@@ -39,6 +40,12 @@ ViewportController::ViewportController(ifcinterface::SessionState* session_state
|
||||
{
|
||||
Federation* federation = session_state_->federation();
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
connect(&ifcinterface::InterfaceSettings::instance(),
|
||||
&ifcinterface::InterfaceSettings::themeChanged,
|
||||
this, [this]() {
|
||||
viewport_->setBackgroundColor(QColor(ifcinterface::InterfaceSettings::instance().color("viewport_background")));
|
||||
});
|
||||
viewport_->setBackgroundColor(QColor(ifcinterface::InterfaceSettings::instance().color("viewport_background")));
|
||||
connect(federation, &Federation::federatedFalseOriginChanged,
|
||||
this, &ViewportController::applyFederatedFalseOrigin);
|
||||
connect(federation, &Federation::configChanged, this, [this]() {
|
||||
|
||||
Reference in New Issue
Block a user