mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
Rename interface modules
Move interface features from panels into modules, move AddModelDialog into the models module, and rename module Widget surfaces to Panel. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
// 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 "Controller.h"
|
||||
|
||||
#include "../../ElementRegistry.h"
|
||||
#include "../../SessionState.h"
|
||||
#include "../models/Controller.h"
|
||||
#include "../viewport/Controller.h"
|
||||
#include "../../../ifcviewer/Federation.h"
|
||||
#include "../../../ifcviewer/SceneLoader.h"
|
||||
#include "../../../ifcviewer/ViewportWindow.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace ifcinterface::modules::project {
|
||||
|
||||
ProjectController::ProjectController(QWidget* host,
|
||||
Federation* federation,
|
||||
ifcinterface::SessionState* session_state,
|
||||
ifcinterface::ElementRegistry* element_registry,
|
||||
ViewportWindow* viewport,
|
||||
ifcinterface::modules::models::ModelsPanelController* models_controller,
|
||||
ifcinterface::modules::viewport::ViewportController* viewport_controller,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
, host_(host)
|
||||
, federation_(federation)
|
||||
, session_state_(session_state)
|
||||
, element_registry_(element_registry)
|
||||
, viewport_(viewport)
|
||||
, models_controller_(models_controller)
|
||||
, viewport_controller_(viewport_controller)
|
||||
{
|
||||
}
|
||||
|
||||
bool ProjectController::newProject() {
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
if (loader && loader->isLoading()) {
|
||||
QMessageBox::information(
|
||||
host_, "New Project",
|
||||
"Wait until the current model load finishes before creating a new project.");
|
||||
return false;
|
||||
}
|
||||
if (!confirmDiscardIfDirty()) return false;
|
||||
|
||||
clearScene();
|
||||
federation_->clear();
|
||||
viewport_controller_->applyFederatedFalseOrigin();
|
||||
session_state_->setStatusMessage("Project", "Untitled");
|
||||
session_state_->notifyProjectReset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectController::openProject() {
|
||||
QFileDialog file_dialog(host_, "Open Project");
|
||||
file_dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
file_dialog.setNameFilter("IFC Federation (*.ifcfed);;All Files (*)");
|
||||
file_dialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||
if (file_dialog.exec() != QDialog::Accepted) return false;
|
||||
|
||||
const QString path = file_dialog.selectedFiles().value(0);
|
||||
if (path.isEmpty()) return false;
|
||||
return openProject(path);
|
||||
}
|
||||
|
||||
bool ProjectController::openProject(const QString& path) {
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
if (loader && loader->isLoading()) {
|
||||
QMessageBox::information(
|
||||
host_, "Open Project",
|
||||
"Wait until the current model load finishes before opening another project.");
|
||||
return false;
|
||||
}
|
||||
if (!confirmDiscardIfDirty()) return false;
|
||||
|
||||
QStringList warnings;
|
||||
QString err;
|
||||
if (!federation_->load(path, &warnings, &err)) {
|
||||
QMessageBox::warning(host_, "Open Project",
|
||||
QString("Could not open project:\n%1").arg(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
clearScene();
|
||||
|
||||
QStringList paths;
|
||||
QStringList fed_ids;
|
||||
for (const auto& model : federation_->models()) {
|
||||
if (model.source_kind != "local") continue;
|
||||
if (!QFileInfo::exists(model.source_path)) {
|
||||
warnings << QString("Source not found, kept in project: %1").arg(model.source_path);
|
||||
continue;
|
||||
}
|
||||
paths << model.source_path;
|
||||
fed_ids << model.id;
|
||||
}
|
||||
models_controller_->loadModels(paths, fed_ids);
|
||||
|
||||
if (!warnings.isEmpty()) {
|
||||
QMessageBox::warning(host_, "Open Project",
|
||||
"Project opened with warnings:\n\n" + warnings.join("\n"));
|
||||
}
|
||||
|
||||
federation_->markClean();
|
||||
viewport_controller_->applyFederatedFalseOrigin();
|
||||
if (federation_->hasHomeView()) {
|
||||
const auto& hv = federation_->homeView();
|
||||
viewport_->setCamera(
|
||||
hv.target.x(), hv.target.y(), hv.target.z(), hv.distance, hv.yaw, hv.pitch);
|
||||
}
|
||||
session_state_->setStatusMessage("Project", QFileInfo(path).fileName());
|
||||
session_state_->notifyProjectOpened(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectController::saveProject() {
|
||||
if (federation_->filePath().isEmpty()) return saveProjectAs();
|
||||
|
||||
QString err;
|
||||
if (!federation_->save(federation_->filePath(), &err)) {
|
||||
QMessageBox::warning(host_, "Save Project",
|
||||
QString("Could not save project:\n%1").arg(err));
|
||||
return false;
|
||||
}
|
||||
session_state_->setStatusMessage("Project", QFileInfo(federation_->filePath()).fileName());
|
||||
session_state_->notifyProjectSaved(federation_->filePath());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectController::saveProjectAs() {
|
||||
QString suggested = federation_->filePath();
|
||||
if (suggested.isEmpty()) suggested = "project.ifcfed";
|
||||
|
||||
QFileDialog file_dialog(host_, "Save Project As", suggested);
|
||||
file_dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
file_dialog.setFileMode(QFileDialog::AnyFile);
|
||||
file_dialog.setNameFilter("IFC Federation (*.ifcfed);;All Files (*)");
|
||||
file_dialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||
if (file_dialog.exec() != QDialog::Accepted) return false;
|
||||
|
||||
QString path = file_dialog.selectedFiles().value(0);
|
||||
if (path.isEmpty()) return false;
|
||||
if (!path.endsWith(".ifcfed", Qt::CaseInsensitive)) path += ".ifcfed";
|
||||
return saveProjectAs(path);
|
||||
}
|
||||
|
||||
bool ProjectController::saveProjectAs(const QString& path) {
|
||||
QString err;
|
||||
if (!federation_->save(path, &err)) {
|
||||
QMessageBox::warning(host_, "Save Project",
|
||||
QString("Could not save project:\n%1").arg(err));
|
||||
return false;
|
||||
}
|
||||
session_state_->setStatusMessage("Project", QFileInfo(path).fileName());
|
||||
session_state_->notifyProjectSaved(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProjectController::clearScene() {
|
||||
viewport_->setSelectedObjectId(0);
|
||||
session_state_->setSelectedObjectId(0);
|
||||
session_state_->notifySelectionChanged();
|
||||
|
||||
const auto model_ids = session_state_->modelIds();
|
||||
for (uint32_t mid : model_ids) {
|
||||
viewport_->removeModel(mid);
|
||||
session_state_->loader()->removeModel(mid);
|
||||
}
|
||||
|
||||
session_state_->clearModelMappings();
|
||||
element_registry_->clear();
|
||||
session_state_->notifyModelsChanged();
|
||||
}
|
||||
|
||||
bool ProjectController::confirmDiscardIfDirty() {
|
||||
if (!federation_->isDirty()) return true;
|
||||
const auto result = QMessageBox::question(
|
||||
host_, "Unsaved Project",
|
||||
"The current project has unsaved changes. Save before continuing?",
|
||||
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
|
||||
QMessageBox::Save);
|
||||
if (result == QMessageBox::Cancel) return false;
|
||||
if (result == QMessageBox::Save) return saveProject();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::project
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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_PANELS_PROJECT_CONTROLLER_H
|
||||
#define IFCINTERFACE_PANELS_PROJECT_CONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QWidget;
|
||||
class Federation;
|
||||
class ViewportWindow;
|
||||
namespace ifcinterface { class ElementRegistry; }
|
||||
namespace ifcinterface { class SessionState; }
|
||||
namespace ifcinterface::modules::models { class ModelsPanelController; }
|
||||
namespace ifcinterface::modules::viewport { class ViewportController; }
|
||||
|
||||
namespace ifcinterface::modules::project {
|
||||
|
||||
class ProjectController : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProjectController(QWidget* host,
|
||||
Federation* federation,
|
||||
ifcinterface::SessionState* session_state,
|
||||
ifcinterface::ElementRegistry* element_registry,
|
||||
ViewportWindow* viewport,
|
||||
ifcinterface::modules::models::ModelsPanelController* models_controller,
|
||||
ifcinterface::modules::viewport::ViewportController* viewport_controller,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
bool newProject();
|
||||
bool openProject();
|
||||
bool saveProject();
|
||||
bool saveProjectAs();
|
||||
|
||||
private:
|
||||
bool openProject(const QString& path);
|
||||
bool saveProjectAs(const QString& path);
|
||||
void clearScene();
|
||||
bool confirmDiscardIfDirty();
|
||||
|
||||
QWidget* host_ = nullptr;
|
||||
Federation* federation_ = nullptr;
|
||||
ifcinterface::SessionState* session_state_ = nullptr;
|
||||
ifcinterface::ElementRegistry* element_registry_ = nullptr;
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
ifcinterface::modules::models::ModelsPanelController* models_controller_ = nullptr;
|
||||
ifcinterface::modules::viewport::ViewportController* viewport_controller_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::project
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,237 @@
|
||||
// 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 "Panel.h"
|
||||
|
||||
#include "../../components/KeyValueTable.h"
|
||||
#include "../../components/Section.h"
|
||||
#include "../../components/Style.h"
|
||||
#include "../../components/SvgIcon.h"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace {
|
||||
|
||||
QWidget* makePropertySetPanel(const ifcinterface::modules::properties::PropertySet& property_set, QWidget* parent = nullptr) {
|
||||
auto* group = new QGroupBox(property_set.title, parent);
|
||||
group->setObjectName("propertySetBox");
|
||||
auto* layout = new QVBoxLayout(group);
|
||||
layout->setContentsMargins(10, 10, 10, 10);
|
||||
layout->setSpacing(0);
|
||||
|
||||
QList<ifcinterface::components::KeyValueTableRow> rows;
|
||||
for (const auto& row : property_set.rows) {
|
||||
rows.append({row.key, row.value, "keyValueValueLabel", "", "", 0});
|
||||
}
|
||||
layout->addWidget(new ifcinterface::components::KeyValueTable(rows, group));
|
||||
return group;
|
||||
}
|
||||
|
||||
QWidget* makeAttributeList(const QList<ifcinterface::modules::properties::KeyValueRow>& rows, QWidget* parent = nullptr) {
|
||||
QList<ifcinterface::components::KeyValueTableRow> table_rows;
|
||||
for (const auto& row : rows) {
|
||||
table_rows.append({row.key, row.value, "keyValueValueLabel", "", "", 0});
|
||||
}
|
||||
return new ifcinterface::components::KeyValueTable(table_rows, parent);
|
||||
}
|
||||
|
||||
QWidget* makeRelationshipList(const QList<ifcinterface::modules::properties::RelationshipRow>& rows, QWidget* parent = nullptr) {
|
||||
QList<ifcinterface::components::KeyValueTableRow> table_rows;
|
||||
for (const auto& row_data : rows) {
|
||||
table_rows.append({row_data.key,
|
||||
row_data.value,
|
||||
"keyValueValueLabel",
|
||||
":/icons/cursor-pointer.svg",
|
||||
"keyValueTrailingIconLabel",
|
||||
72});
|
||||
}
|
||||
return new ifcinterface::components::KeyValueTable(table_rows, parent);
|
||||
}
|
||||
|
||||
QWidget* makeFilterWrapper(QLineEdit** field_out, QWidget* parent = nullptr) {
|
||||
auto* wrapper = new QWidget(parent);
|
||||
wrapper->setObjectName("panelSectionFilterWrapper");
|
||||
auto* layout = new QVBoxLayout(wrapper);
|
||||
layout->setContentsMargins(ifcinterface::components::style::metrics::section_body_padding,
|
||||
0,
|
||||
ifcinterface::components::style::metrics::section_body_padding,
|
||||
0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
auto* field = new QLineEdit(wrapper);
|
||||
field->setClearButtonEnabled(true);
|
||||
field->addAction(ifcinterface::components::icons::makeSvgIcon(":/icons/filter.svg"), QLineEdit::LeadingPosition);
|
||||
field->setVisible(false);
|
||||
layout->addWidget(field);
|
||||
|
||||
if (field_out) *field_out = field;
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
QFrame* makeEntityBox(const ifcinterface::modules::properties::EntitySummary& entity, QWidget* parent = nullptr) {
|
||||
auto* entity_box = new QFrame(parent);
|
||||
entity_box->setObjectName("entityClassBox");
|
||||
auto* entity_layout = new QHBoxLayout(entity_box);
|
||||
entity_layout->setContentsMargins(10, 8, 10, 8);
|
||||
entity_layout->setSpacing(10);
|
||||
|
||||
auto* entity_icon = new QLabel(entity_box);
|
||||
entity_icon->setPixmap(ifcinterface::components::icons::makeSvgPixmap(":/icons/cube-dots.svg", QSize(28, 28)));
|
||||
entity_icon->setAlignment(Qt::AlignCenter);
|
||||
|
||||
auto* entity_text = new QWidget(entity_box);
|
||||
auto* entity_text_layout = new QVBoxLayout(entity_text);
|
||||
entity_text_layout->setContentsMargins(0, 0, 0, 0);
|
||||
entity_text_layout->setSpacing(2);
|
||||
|
||||
auto* entity_class_label = new QLabel(entity.entity_class, entity_text);
|
||||
entity_class_label->setObjectName("entityClassLabel");
|
||||
auto* entity_type_label = new QLabel(entity.predefined_type, entity_text);
|
||||
entity_type_label->setProperty("textRole", "secondary");
|
||||
|
||||
entity_text_layout->addWidget(entity_class_label);
|
||||
entity_text_layout->addWidget(entity_type_label);
|
||||
entity_layout->addWidget(entity_icon, 0, Qt::AlignVCenter);
|
||||
entity_layout->addWidget(entity_text, 1, Qt::AlignVCenter);
|
||||
return entity_box;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace ifcinterface::modules::properties {
|
||||
|
||||
PropertiesPanel::PropertiesPanel(QWidget* parent)
|
||||
: components::Panel("Properties", nullptr, parent, false, true)
|
||||
{
|
||||
}
|
||||
|
||||
void PropertiesPanel::render(const PropertiesPanelState& state) {
|
||||
clearBodyWidgets();
|
||||
|
||||
QList<QWidget*> property_set_widgets;
|
||||
for (const auto& property_set : state.property_sets) {
|
||||
property_set_widgets.append(makePropertySetPanel(property_set, this));
|
||||
}
|
||||
|
||||
QList<QWidget*> quantity_set_widgets;
|
||||
for (const auto& property_set : state.quantity_sets) {
|
||||
quantity_set_widgets.append(makePropertySetPanel(property_set, this));
|
||||
}
|
||||
|
||||
auto* entity_section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||
entity_section->addBodyWidget(makeEntityBox(state.entity, this));
|
||||
|
||||
auto* attributes_section = new components::Section("Attributes", components::SectionHeaderMode::Visible, this);
|
||||
attributes_section->addBodyWidget(makeAttributeList(state.attributes, this));
|
||||
attributes_section->setExpanded(attributes_expanded_);
|
||||
|
||||
auto* relationships_section = new components::Section("Relationships", components::SectionHeaderMode::Visible, this);
|
||||
relationships_section->addBodyWidget(makeRelationshipList(state.relationships, this));
|
||||
relationships_section->setExpanded(relationships_expanded_);
|
||||
|
||||
auto* properties_section = new components::Section("Properties", components::SectionHeaderMode::Visible, this);
|
||||
auto* properties_filter_toggle = new QToolButton(properties_section);
|
||||
properties_filter_toggle->setObjectName("panelSectionFilterToggle");
|
||||
properties_filter_toggle->setCheckable(true);
|
||||
properties_filter_toggle->setIcon(components::icons::makeSvgIcon(":/icons/filter.svg"));
|
||||
properties_filter_toggle->setAutoRaise(true);
|
||||
properties_section->addHeaderWidget(properties_filter_toggle);
|
||||
QLineEdit* properties_filter_field = nullptr;
|
||||
auto* properties_filter_wrapper = makeFilterWrapper(&properties_filter_field, properties_section);
|
||||
properties_filter_field->setPlaceholderText("Filter properties or sets");
|
||||
properties_filter_field->setText(properties_filter_text_);
|
||||
properties_filter_wrapper->setVisible(properties_filter_visible_);
|
||||
properties_filter_field->setVisible(properties_filter_visible_);
|
||||
connect(properties_filter_toggle, &QToolButton::toggled, properties_filter_field, [this, properties_filter_field, properties_filter_wrapper](bool visible) {
|
||||
properties_filter_visible_ = visible;
|
||||
properties_filter_field->setVisible(visible);
|
||||
properties_filter_wrapper->setVisible(visible);
|
||||
if (visible) properties_filter_field->setFocus();
|
||||
});
|
||||
connect(properties_filter_field, &QLineEdit::textChanged, this, [this](const QString& text) {
|
||||
properties_filter_text_ = text;
|
||||
});
|
||||
properties_section->addBodyWidget(properties_filter_wrapper);
|
||||
for (auto* widget : property_set_widgets) properties_section->addBodyWidget(widget);
|
||||
properties_section->setExpanded(properties_expanded_);
|
||||
properties_filter_toggle->setChecked(properties_filter_visible_);
|
||||
|
||||
auto* quantities_section = new components::Section("Quantities", components::SectionHeaderMode::Visible, this);
|
||||
auto* quantities_filter_toggle = new QToolButton(quantities_section);
|
||||
quantities_filter_toggle->setObjectName("panelSectionFilterToggle");
|
||||
quantities_filter_toggle->setCheckable(true);
|
||||
quantities_filter_toggle->setIcon(components::icons::makeSvgIcon(":/icons/filter.svg"));
|
||||
quantities_filter_toggle->setAutoRaise(true);
|
||||
quantities_section->addHeaderWidget(quantities_filter_toggle);
|
||||
QLineEdit* quantities_filter_field = nullptr;
|
||||
auto* quantities_filter_wrapper = makeFilterWrapper(&quantities_filter_field, quantities_section);
|
||||
quantities_filter_field->setPlaceholderText("Filter quantities or sets");
|
||||
quantities_filter_field->setText(quantities_filter_text_);
|
||||
quantities_filter_wrapper->setVisible(quantities_filter_visible_);
|
||||
quantities_filter_field->setVisible(quantities_filter_visible_);
|
||||
connect(quantities_filter_toggle, &QToolButton::toggled, quantities_filter_field, [this, quantities_filter_field, quantities_filter_wrapper](bool visible) {
|
||||
quantities_filter_visible_ = visible;
|
||||
quantities_filter_field->setVisible(visible);
|
||||
quantities_filter_wrapper->setVisible(visible);
|
||||
if (visible) quantities_filter_field->setFocus();
|
||||
});
|
||||
connect(quantities_filter_field, &QLineEdit::textChanged, this, [this](const QString& text) {
|
||||
quantities_filter_text_ = text;
|
||||
});
|
||||
quantities_section->addBodyWidget(quantities_filter_wrapper);
|
||||
for (auto* widget : quantity_set_widgets) quantities_section->addBodyWidget(widget);
|
||||
quantities_section->setExpanded(quantities_expanded_);
|
||||
quantities_filter_toggle->setChecked(quantities_filter_visible_);
|
||||
|
||||
if (auto* button = attributes_section->findChild<QToolButton*>("panelSectionHeaderButton")) {
|
||||
connect(button, &QToolButton::toggled, this, [this](bool expanded) {
|
||||
attributes_expanded_ = expanded;
|
||||
});
|
||||
}
|
||||
if (auto* button = relationships_section->findChild<QToolButton*>("panelSectionHeaderButton")) {
|
||||
connect(button, &QToolButton::toggled, this, [this](bool expanded) {
|
||||
relationships_expanded_ = expanded;
|
||||
});
|
||||
}
|
||||
if (auto* button = properties_section->findChild<QToolButton*>("panelSectionHeaderButton")) {
|
||||
connect(button, &QToolButton::toggled, this, [this](bool expanded) {
|
||||
properties_expanded_ = expanded;
|
||||
});
|
||||
}
|
||||
if (auto* button = quantities_section->findChild<QToolButton*>("panelSectionHeaderButton")) {
|
||||
connect(button, &QToolButton::toggled, this, [this](bool expanded) {
|
||||
quantities_expanded_ = expanded;
|
||||
});
|
||||
}
|
||||
|
||||
addBodyWidget(entity_section);
|
||||
addBodyWidget(attributes_section);
|
||||
addBodyWidget(relationships_section);
|
||||
addBodyWidget(properties_section);
|
||||
addBodyWidget(quantities_section);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::properties
|
||||
@@ -0,0 +1,56 @@
|
||||
// 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_MODULES_PROPERTIES_PANEL_H
|
||||
#define IFCINTERFACE_MODULES_PROPERTIES_PANEL_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include "../../components/Panel.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QToolButton;
|
||||
|
||||
namespace ifcinterface::modules::properties {
|
||||
|
||||
class PropertiesPanel : public components::Panel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PropertiesPanel(QWidget* parent = nullptr);
|
||||
|
||||
void render(const PropertiesPanelState& state);
|
||||
|
||||
private:
|
||||
bool attributes_expanded_ = true;
|
||||
bool relationships_expanded_ = true;
|
||||
bool properties_expanded_ = true;
|
||||
bool quantities_expanded_ = true;
|
||||
bool properties_filter_visible_ = false;
|
||||
bool quantities_filter_visible_ = false;
|
||||
QString properties_filter_text_;
|
||||
QString quantities_filter_text_;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::properties
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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_PANELS_PROPERTIESPANELTYPES_H
|
||||
#define IFCINTERFACE_PANELS_PROPERTIESPANELTYPES_H
|
||||
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
|
||||
namespace ifcinterface::modules::properties {
|
||||
|
||||
struct KeyValueRow {
|
||||
QString key;
|
||||
QString value;
|
||||
};
|
||||
|
||||
struct RelationshipRow {
|
||||
QString key;
|
||||
QString value;
|
||||
};
|
||||
|
||||
struct PropertySet {
|
||||
QString title;
|
||||
QList<KeyValueRow> rows;
|
||||
};
|
||||
|
||||
struct EntitySummary {
|
||||
QString entity_class;
|
||||
QString predefined_type;
|
||||
};
|
||||
|
||||
struct PropertiesPanelState {
|
||||
EntitySummary entity;
|
||||
QList<KeyValueRow> attributes;
|
||||
QList<RelationshipRow> relationships;
|
||||
QList<PropertySet> property_sets;
|
||||
QList<PropertySet> quantity_sets;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::properties
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
// 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 "View.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "../../ElementRegistry.h"
|
||||
#include "../../SessionState.h"
|
||||
#include "../../../ifcviewer/AppSettings.h"
|
||||
|
||||
namespace ifcinterface::modules::properties {
|
||||
|
||||
PropertiesPanelView::PropertiesPanelView(PropertiesPanel* widget,
|
||||
ifcinterface::SessionState* session_state,
|
||||
QObject* parent)
|
||||
: QObject(parent), widget_(widget), session_state_(session_state)
|
||||
{
|
||||
connect(session_state_, &ifcinterface::SessionState::selectionChanged, this, [this](uint32_t object_id) {
|
||||
refresh(object_id);
|
||||
});
|
||||
connect(session_state_, &ifcinterface::SessionState::projectReset, this, [this]() {
|
||||
refresh(0);
|
||||
});
|
||||
refresh(0);
|
||||
}
|
||||
|
||||
void PropertiesPanelView::refresh(uint32_t object_id) {
|
||||
auto* registry = session_state_->elementRegistry();
|
||||
PropertiesPanelState state;
|
||||
state.entity = {"IfcWall", "SOLIDWALL"};
|
||||
state.attributes = {
|
||||
{"GlobalId", "2Q$n5SLPP9Q8B7wQKjKfUQ"},
|
||||
{"Name", "Core-EXT-204"},
|
||||
{"Description", "External load-bearing wall"},
|
||||
};
|
||||
state.relationships = {
|
||||
{"Type", "Basic Wall: Exterior - 200mm"},
|
||||
{"Container", "Level 02"},
|
||||
};
|
||||
state.property_sets = {
|
||||
{"Pset_WallCommon",
|
||||
{{"Reference", "Core-EXT-204"},
|
||||
{"Status", "Reviewed"},
|
||||
{"Fire Rating", "120 min"},
|
||||
{"LoadBearing", "True"}}},
|
||||
{"Identity Data",
|
||||
{{"Type", "IfcWall"},
|
||||
{"Name", "Core-EXT-204"},
|
||||
{"Owner", "Architecture"},
|
||||
{"Phase", "Construction"}}},
|
||||
{"BIM Collaboration",
|
||||
{{"Issue Count", "2 open"},
|
||||
{"Last Review", "2026-04-30"},
|
||||
{"Assigned To", "Design Coordination"}}},
|
||||
};
|
||||
state.quantity_sets = {
|
||||
{"BaseQuantities",
|
||||
{{"Length", "6.20 m"},
|
||||
{"Height", "3.45 m"},
|
||||
{"Width", "0.30 m"},
|
||||
{"Volume", "6.42 m3"}}},
|
||||
{"Finish Quantities",
|
||||
{{"NetSideArea", "21.39 m2"},
|
||||
{"GrossArea", "22.10 m2"},
|
||||
{"Paint Coverage", "42.78 m2"}}},
|
||||
};
|
||||
|
||||
if (!registry) {
|
||||
widget_->render(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppSettings::instance().loadDataSource()) {
|
||||
auto info = registry->findBasicElementInfo(object_id);
|
||||
if (info && !info->type.isEmpty()) {
|
||||
state.entity.entity_class = info->type;
|
||||
if (!state.property_sets.isEmpty() && !state.property_sets[1].rows.isEmpty()) {
|
||||
state.property_sets[1].rows[0].value = info->type;
|
||||
}
|
||||
}
|
||||
if (info && !info->name.isEmpty()) {
|
||||
state.attributes[1].value = info->name;
|
||||
if (state.property_sets.size() > 1 && state.property_sets[1].rows.size() > 1) {
|
||||
state.property_sets[1].rows[1].value = info->name;
|
||||
}
|
||||
}
|
||||
if (info && !info->guid.isEmpty()) {
|
||||
state.attributes[0].value = info->guid;
|
||||
}
|
||||
|
||||
widget_->render(state);
|
||||
return;
|
||||
}
|
||||
|
||||
auto entity = registry->findEntity(object_id);
|
||||
if (entity) {
|
||||
state.entity.entity_class = QString::fromStdString(entity->declaration().name());
|
||||
if (!state.property_sets.isEmpty() && !state.property_sets[1].rows.isEmpty()) {
|
||||
state.property_sets[1].rows[0].value = state.entity.entity_class;
|
||||
}
|
||||
}
|
||||
widget_->render(state);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::properties
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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_PANELS_PROPERTIESPANELVIEW_H
|
||||
#define IFCINTERFACE_PANELS_PROPERTIESPANELVIEW_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace ifcinterface { class SessionState; }
|
||||
namespace ifcinterface::modules::properties {
|
||||
|
||||
class PropertiesPanel;
|
||||
|
||||
class PropertiesPanelView : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PropertiesPanelView(PropertiesPanel* widget,
|
||||
ifcinterface::SessionState* session_state,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
private:
|
||||
void refresh(uint32_t object_id);
|
||||
|
||||
PropertiesPanel* widget_ = nullptr;
|
||||
ifcinterface::SessionState* session_state_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::properties
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
// 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 "Dialog.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 <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFrame>
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QShowEvent>
|
||||
#include <QSpinBox>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace ifcinterface::modules::settings {
|
||||
|
||||
SettingsDialog::SettingsDialog(QWidget* parent)
|
||||
: components::Dialog(parent)
|
||||
{
|
||||
setObjectName("appDialog");
|
||||
setWindowTitle("Settings");
|
||||
setModal(true);
|
||||
resize(520, 420);
|
||||
setStyleSheet(components::style::buildAppStyleSheet());
|
||||
setupUi();
|
||||
}
|
||||
|
||||
void SettingsDialog::showEvent(QShowEvent* event) {
|
||||
syncFromSettings();
|
||||
QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void SettingsDialog::setupUi() {
|
||||
auto* tabs = new components::TabWidget(this);
|
||||
|
||||
auto* graphics_tab = new QWidget(tabs);
|
||||
auto* graphics_layout = new QVBoxLayout(graphics_tab);
|
||||
graphics_layout->setContentsMargins(0, 0, 0, 0);
|
||||
graphics_layout->setSpacing(components::style::metrics::padding);
|
||||
|
||||
auto* general_section = new components::Section("General", components::SectionHeaderMode::Visible, graphics_tab);
|
||||
auto* general_body = new QWidget(general_section);
|
||||
auto* general_form = new QFormLayout(general_body);
|
||||
general_form->setContentsMargins(0, 0, 0, 0);
|
||||
general_form->setHorizontalSpacing(16);
|
||||
general_form->setVerticalSpacing(10);
|
||||
|
||||
geometry_library_edit_ = new QLineEdit(general_body);
|
||||
geometry_library_edit_->setMinimumWidth(300);
|
||||
general_form->addRow("Geometry Library", geometry_library_edit_);
|
||||
|
||||
show_stats_check_ = new QCheckBox(general_body);
|
||||
general_form->addRow("Show Performance Stats", show_stats_check_);
|
||||
|
||||
backface_culling_check_ = new QCheckBox(general_body);
|
||||
backface_culling_check_->setToolTip(
|
||||
"Skip triangles facing away from the camera. Big FPS win on closed solids; "
|
||||
"disable if you see holes in open geometry.");
|
||||
general_form->addRow("Backface Culling", backface_culling_check_);
|
||||
|
||||
general_section->addBodyWidget(general_body);
|
||||
|
||||
auto* loading_section = new components::Section("Loading", components::SectionHeaderMode::Visible, graphics_tab);
|
||||
auto* loading_body = new QWidget(loading_section);
|
||||
auto* loading_form = new QFormLayout(loading_body);
|
||||
loading_form->setContentsMargins(0, 0, 0, 0);
|
||||
loading_form->setHorizontalSpacing(16);
|
||||
loading_form->setVerticalSpacing(10);
|
||||
|
||||
load_data_source_checkbox_ = new QCheckBox(loading_body);
|
||||
load_data_source_checkbox_->setToolTip(
|
||||
"Keep the .ifc/.rdb open after loading so element properties can be queried. "
|
||||
"Disable for geometry-only viewing.");
|
||||
loading_form->addRow("Load Property Data Source", load_data_source_checkbox_);
|
||||
|
||||
apply_coordinate_operation_check_ = new QCheckBox(loading_body);
|
||||
apply_coordinate_operation_check_->setToolTip(
|
||||
"Apply each model's IfcCoordinateOperation after load so it lands in "
|
||||
"georeferenced map coordinates.");
|
||||
loading_form->addRow("Apply Coordinate Operation", apply_coordinate_operation_check_);
|
||||
|
||||
void_limit_spin_ = new QSpinBox(loading_body);
|
||||
void_limit_spin_->setRange(0, 100000);
|
||||
loading_form->addRow("Void Limit", void_limit_spin_);
|
||||
|
||||
deflection_tolerance_spin_ = new QDoubleSpinBox(loading_body);
|
||||
deflection_tolerance_spin_->setRange(0.000001, 1000.0);
|
||||
deflection_tolerance_spin_->setDecimals(6);
|
||||
deflection_tolerance_spin_->setSingleStep(0.001);
|
||||
loading_form->addRow("Deflection Tolerance", deflection_tolerance_spin_);
|
||||
|
||||
angular_tolerance_spin_ = new QDoubleSpinBox(loading_body);
|
||||
angular_tolerance_spin_->setRange(0.000001, 3.141592);
|
||||
angular_tolerance_spin_->setDecimals(6);
|
||||
angular_tolerance_spin_->setSingleStep(0.05);
|
||||
loading_form->addRow("Angular Tolerance", angular_tolerance_spin_);
|
||||
|
||||
auto* description = new QLabel(
|
||||
"These settings are shared with the viewer backend and persist via QSettings.",
|
||||
loading_body);
|
||||
description->setProperty("textRole", "secondary");
|
||||
description->setWordWrap(true);
|
||||
loading_form->addRow(QString(), description);
|
||||
|
||||
loading_section->addBodyWidget(loading_body);
|
||||
graphics_layout->addWidget(general_section);
|
||||
graphics_layout->addWidget(loading_section);
|
||||
graphics_layout->addStretch(1);
|
||||
|
||||
auto make_placeholder_tab = [tabs](const QString& title, const QString& detail) {
|
||||
auto* tab = new QWidget(tabs);
|
||||
auto* layout = new QVBoxLayout(tab);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(components::style::metrics::padding);
|
||||
|
||||
auto* section = new components::Section(title, components::SectionHeaderMode::Visible, tab);
|
||||
auto* body = new QWidget(section);
|
||||
auto* body_layout = new QVBoxLayout(body);
|
||||
body_layout->setContentsMargins(0, 0, 0, 0);
|
||||
body_layout->setSpacing(8);
|
||||
|
||||
auto* heading = new QLabel(title, body);
|
||||
auto* content = new QLabel(detail, body);
|
||||
content->setProperty("textRole", "secondary");
|
||||
content->setWordWrap(true);
|
||||
|
||||
body_layout->addWidget(heading);
|
||||
body_layout->addWidget(content);
|
||||
section->addBodyWidget(body);
|
||||
layout->addWidget(section);
|
||||
layout->addStretch(1);
|
||||
return tab;
|
||||
};
|
||||
|
||||
tabs->addTab(make_placeholder_tab("Navigation", "Navigation preferences and interaction modes will live here."),
|
||||
"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");
|
||||
|
||||
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
if (auto* ok = buttons->button(QDialogButtonBox::Ok)) {
|
||||
ok->setText("OK");
|
||||
ok->setIcon(components::icons::makeSvgIcon(":/icons/check.svg"));
|
||||
}
|
||||
if (auto* cancel = buttons->button(QDialogButtonBox::Cancel)) {
|
||||
cancel->setText("Cancel");
|
||||
cancel->setIcon(components::icons::makeSvgIcon(":/icons/xmark-circle.svg"));
|
||||
}
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &SettingsDialog::onAccepted);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
auto* actions_section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||
actions_section->addBodyWidget(buttons);
|
||||
|
||||
addBodyWidget(tabs);
|
||||
addBodyWidget(actions_section);
|
||||
}
|
||||
|
||||
void SettingsDialog::syncFromSettings() {
|
||||
geometry_library_edit_->setText(AppSettings::instance().geometryLibrary());
|
||||
show_stats_check_->setChecked(AppSettings::instance().showStats());
|
||||
backface_culling_check_->setChecked(AppSettings::instance().backfaceCulling());
|
||||
load_data_source_checkbox_->setChecked(AppSettings::instance().loadDataSource());
|
||||
apply_coordinate_operation_check_->setChecked(AppSettings::instance().applyCoordinateOperation());
|
||||
void_limit_spin_->setValue(AppSettings::instance().voidLimit());
|
||||
deflection_tolerance_spin_->setValue(AppSettings::instance().deflectionTolerance());
|
||||
angular_tolerance_spin_->setValue(AppSettings::instance().angularTolerance());
|
||||
}
|
||||
|
||||
void SettingsDialog::onAccepted() {
|
||||
AppSettings::instance().setGeometryLibrary(geometry_library_edit_->text());
|
||||
AppSettings::instance().setShowStats(show_stats_check_->isChecked());
|
||||
AppSettings::instance().setBackfaceCulling(backface_culling_check_->isChecked());
|
||||
AppSettings::instance().setLoadDataSource(load_data_source_checkbox_->isChecked());
|
||||
AppSettings::instance().setApplyCoordinateOperation(apply_coordinate_operation_check_->isChecked());
|
||||
AppSettings::instance().setVoidLimit(void_limit_spin_->value());
|
||||
AppSettings::instance().setDeflectionTolerance(deflection_tolerance_spin_->value());
|
||||
AppSettings::instance().setAngularTolerance(angular_tolerance_spin_->value());
|
||||
accept();
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::settings
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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_PANELS_SETTINGSDIALOG_H
|
||||
#define IFCINTERFACE_PANELS_SETTINGSDIALOG_H
|
||||
|
||||
#include "../../components/Dialog.h"
|
||||
|
||||
class QCheckBox;
|
||||
class QDoubleSpinBox;
|
||||
class QLineEdit;
|
||||
class QShowEvent;
|
||||
class QSpinBox;
|
||||
|
||||
namespace ifcinterface::modules::settings {
|
||||
|
||||
class SettingsDialog : public components::Dialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsDialog(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
private:
|
||||
void setupUi();
|
||||
void syncFromSettings();
|
||||
void onAccepted();
|
||||
|
||||
QLineEdit* geometry_library_edit_ = nullptr;
|
||||
QCheckBox* show_stats_check_ = nullptr;
|
||||
QCheckBox* backface_culling_check_ = nullptr;
|
||||
QCheckBox* load_data_source_checkbox_ = nullptr;
|
||||
QCheckBox* apply_coordinate_operation_check_ = nullptr;
|
||||
QSpinBox* void_limit_spin_ = nullptr;
|
||||
QDoubleSpinBox* deflection_tolerance_spin_ = nullptr;
|
||||
QDoubleSpinBox* angular_tolerance_spin_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::settings
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
// 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 "Panel.h"
|
||||
|
||||
#include "../../components/Section.h"
|
||||
#include "../../components/SvgIcon.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
namespace ifcinterface::modules::spatial_hierarchy {
|
||||
|
||||
SpatialHierarchyPanel::SpatialHierarchyPanel(QWidget* parent)
|
||||
: components::Panel("Spatial Hierarchy", nullptr, parent)
|
||||
{
|
||||
auto* section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||
|
||||
tree_ = new QTreeWidget(section);
|
||||
tree_->setColumnCount(2);
|
||||
tree_->setHeaderLabels({"Spatial Item", ""});
|
||||
tree_->setIconSize(QSize(16, 16));
|
||||
tree_->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
tree_->setUniformRowHeights(true);
|
||||
tree_->header()->setStretchLastSection(false);
|
||||
tree_->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
tree_->header()->setSectionResizeMode(1, QHeaderView::Fixed);
|
||||
tree_->header()->resizeSection(1, 28);
|
||||
tree_->header()->hide();
|
||||
section->addBodyWidget(tree_);
|
||||
addBodyWidget(section);
|
||||
|
||||
connect(tree_, &QTreeWidget::itemClicked, this, [this](QTreeWidgetItem* item, int column) {
|
||||
if (!item || column != 1) return;
|
||||
emit visibilityToggleRequested(itemPath(item));
|
||||
});
|
||||
}
|
||||
|
||||
void SpatialHierarchyPanel::setNodes(const QList<TreeNode>& nodes) {
|
||||
tree_->clear();
|
||||
for (const auto& node : nodes) {
|
||||
addNode(tree_->invisibleRootItem(), node);
|
||||
}
|
||||
tree_->expandAll();
|
||||
}
|
||||
|
||||
void SpatialHierarchyPanel::addNode(QTreeWidgetItem* parent, const TreeNode& node) {
|
||||
auto* item = new QTreeWidgetItem(parent, {node.name, ""});
|
||||
item->setData(1, Qt::UserRole, node.visible);
|
||||
item->setSizeHint(0, QSize(0, 24));
|
||||
item->setIcon(0, components::icons::makeSvgIcon(iconPath(node.kind)));
|
||||
item->setIcon(1, components::icons::makeSvgIcon(node.visible ? ":/icons/eye.svg" : ":/icons/eye-closed.svg"));
|
||||
for (const auto& child : node.children) {
|
||||
addNode(item, child);
|
||||
}
|
||||
}
|
||||
|
||||
NodePath SpatialHierarchyPanel::itemPath(QTreeWidgetItem* item) const {
|
||||
NodePath path;
|
||||
while (item) {
|
||||
path.prepend(item->text(0));
|
||||
item = item->parent();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
QString SpatialHierarchyPanel::iconPath(ItemKind kind) const {
|
||||
switch (kind) {
|
||||
case ItemKind::Site: return ":/icons/frame-alt.svg";
|
||||
case ItemKind::Building: return ":/icons/city.svg";
|
||||
case ItemKind::Storey: return ":/icons/planimetry.svg";
|
||||
case ItemKind::Space: return ":/icons/square3d-from-center.svg";
|
||||
}
|
||||
return ":/icons/frame-alt.svg";
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::spatial_hierarchy
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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_MODULES_SPATIAL_HIERARCHY_PANEL_H
|
||||
#define IFCINTERFACE_MODULES_SPATIAL_HIERARCHY_PANEL_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include "../../components/Panel.h"
|
||||
|
||||
class QTreeWidget;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
namespace ifcinterface::modules::spatial_hierarchy {
|
||||
|
||||
class SpatialHierarchyPanel : public components::Panel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpatialHierarchyPanel(QWidget* parent = nullptr);
|
||||
|
||||
void setNodes(const QList<TreeNode>& nodes);
|
||||
|
||||
signals:
|
||||
void visibilityToggleRequested(const NodePath& path);
|
||||
|
||||
private:
|
||||
void addNode(QTreeWidgetItem* parent, const TreeNode& node);
|
||||
NodePath itemPath(QTreeWidgetItem* item) const;
|
||||
QString iconPath(ItemKind kind) const;
|
||||
|
||||
QTreeWidget* tree_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::spatial_hierarchy
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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_PANELS_SPATIALHIERARCHYPANELTYPES_H
|
||||
#define IFCINTERFACE_PANELS_SPATIALHIERARCHYPANELTYPES_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
namespace ifcinterface::modules::spatial_hierarchy {
|
||||
|
||||
enum class ItemKind {
|
||||
Site,
|
||||
Building,
|
||||
Storey,
|
||||
Space,
|
||||
};
|
||||
|
||||
struct TreeNode {
|
||||
QString name;
|
||||
ItemKind kind = ItemKind::Space;
|
||||
bool visible = true;
|
||||
QList<TreeNode> children;
|
||||
};
|
||||
|
||||
using NodePath = QStringList;
|
||||
|
||||
} // namespace ifcinterface::modules::spatial_hierarchy
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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 "View.h"
|
||||
|
||||
#include "Panel.h"
|
||||
|
||||
#include "../../SessionState.h"
|
||||
|
||||
namespace ifcinterface::modules::spatial_hierarchy {
|
||||
|
||||
namespace {
|
||||
|
||||
TreeNode* findNodeRecursive(QList<TreeNode>& nodes, const NodePath& path, int depth) {
|
||||
for (auto& node : nodes) {
|
||||
if (node.name != path.at(depth)) continue;
|
||||
if (depth == path.size() - 1) return &node;
|
||||
return findNodeRecursive(node.children, path, depth + 1);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SpatialHierarchyPanelView::SpatialHierarchyPanelView(SpatialHierarchyPanel* widget,
|
||||
ifcinterface::SessionState* session_state,
|
||||
QObject* parent)
|
||||
: QObject(parent), widget_(widget), session_state_(session_state)
|
||||
{
|
||||
nodes_ = {
|
||||
{"Site A", ItemKind::Site, true,
|
||||
{{"Building 01", ItemKind::Building, true,
|
||||
{{"Level 02", ItemKind::Storey, true,
|
||||
{{"Lobby", ItemKind::Space, true, {}},
|
||||
{"Core", ItemKind::Space, true, {}}}}}}}},
|
||||
};
|
||||
|
||||
connect(widget_, &SpatialHierarchyPanel::visibilityToggleRequested, this, [this](const NodePath& path) {
|
||||
if (auto* node = findNode(path)) {
|
||||
node->visible = !node->visible;
|
||||
reload();
|
||||
session_state_->setStatusMessage("Spatial", node->visible ? "Item shown" : "Item hidden");
|
||||
}
|
||||
});
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
void SpatialHierarchyPanelView::reload() {
|
||||
widget_->setNodes(nodes_);
|
||||
}
|
||||
|
||||
TreeNode* SpatialHierarchyPanelView::findNode(const NodePath& path) {
|
||||
if (path.isEmpty()) return nullptr;
|
||||
return findNodeRecursive(nodes_, path, 0);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::spatial_hierarchy
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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_PANELS_SPATIALHIERARCHYPANELVIEW_H
|
||||
#define IFCINTERFACE_PANELS_SPATIALHIERARCHYPANELVIEW_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace ifcinterface { class SessionState; }
|
||||
namespace ifcinterface::modules::spatial_hierarchy {
|
||||
|
||||
class SpatialHierarchyPanel;
|
||||
|
||||
class SpatialHierarchyPanelView : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpatialHierarchyPanelView(SpatialHierarchyPanel* widget,
|
||||
ifcinterface::SessionState* session_state,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
private:
|
||||
void reload();
|
||||
TreeNode* findNode(const NodePath& path);
|
||||
|
||||
SpatialHierarchyPanel* widget_ = nullptr;
|
||||
ifcinterface::SessionState* session_state_ = nullptr;
|
||||
QList<TreeNode> nodes_;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::spatial_hierarchy
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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 "Panel.h"
|
||||
|
||||
#include "../../components/Section.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace ifcinterface::modules::todo {
|
||||
|
||||
TodoPanel::TodoPanel(const QString& title, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
auto* section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||
|
||||
auto* body = new QWidget(section);
|
||||
auto* body_layout = new QVBoxLayout(body);
|
||||
body_layout->setContentsMargins(0, 12, 0, 12);
|
||||
body_layout->setSpacing(12);
|
||||
|
||||
auto* heading = new QLabel(title, body);
|
||||
|
||||
auto* content = new QLabel("Coming soon", body);
|
||||
content->setProperty("textRole", "disabled");
|
||||
content->setAlignment(Qt::AlignCenter);
|
||||
|
||||
body_layout->addWidget(heading);
|
||||
body_layout->addStretch(1);
|
||||
body_layout->addWidget(content);
|
||||
body_layout->addStretch(1);
|
||||
|
||||
section->addBodyWidget(body);
|
||||
layout->addWidget(section);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::todo
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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_MODULES_TODO_PANEL_H
|
||||
#define IFCINTERFACE_MODULES_TODO_PANEL_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace ifcinterface::modules::todo {
|
||||
|
||||
class TodoPanel : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TodoPanel(const QString& title, QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::todo
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,194 @@
|
||||
// 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 "Controller.h"
|
||||
|
||||
#include "../../SessionState.h"
|
||||
#include "../../../ifcviewer/AppSettings.h"
|
||||
#include "../../../ifcviewer/Federation.h"
|
||||
#include "../../../ifcviewer/SceneLoader.h"
|
||||
#include "../../../ifcviewer/ViewportWindow.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace ifcinterface::modules::viewport {
|
||||
|
||||
ViewportController::ViewportController(ifcinterface::SessionState* session_state,
|
||||
ViewportWindow* viewport,
|
||||
QObject* parent)
|
||||
: QObject(parent)
|
||||
, session_state_(session_state)
|
||||
, viewport_(viewport)
|
||||
{
|
||||
Federation* federation = session_state_->federation();
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
connect(federation, &Federation::federatedFalseOriginChanged,
|
||||
this, &ViewportController::applyFederatedFalseOrigin);
|
||||
connect(federation, &Federation::configChanged, this, [this]() {
|
||||
applyFederatedFalseOrigin();
|
||||
for (uint32_t mid : session_state_->modelIds()) {
|
||||
applyModelTransformation(mid);
|
||||
}
|
||||
});
|
||||
connect(federation, &Federation::modelTransformationChanged,
|
||||
this, [this](const QString& fed_id) {
|
||||
const uint32_t mid = session_state_->modelIdForFedId(fed_id);
|
||||
if (mid != 0) applyModelTransformation(mid);
|
||||
});
|
||||
connect(federation, &Federation::modelVisibilityChanged,
|
||||
this, [this](const QString& fed_id, bool /*visible*/) {
|
||||
const uint32_t mid = session_state_->modelIdForFedId(fed_id);
|
||||
if (mid != 0) applyModelVisibility(mid);
|
||||
});
|
||||
connect(federation, &Federation::modelGroupChanged,
|
||||
this, [this](const QString& fed_id, const QString& /*group_id*/) {
|
||||
const uint32_t mid = session_state_->modelIdForFedId(fed_id);
|
||||
if (mid != 0) applyModelVisibility(mid);
|
||||
});
|
||||
connect(federation, &Federation::groupVisibilityChanged,
|
||||
this, [this](const QString&, bool /*visible*/) {
|
||||
for (uint32_t mid : session_state_->modelIds()) {
|
||||
applyModelVisibility(mid);
|
||||
}
|
||||
});
|
||||
connect(loader, &SceneLoader::loadedFromSidecar, this,
|
||||
[this](uint32_t mid, qint64 /*elapsed_ms*/) {
|
||||
applyCoordinateOperation(mid);
|
||||
applyModelVisibility(mid);
|
||||
maybeGuessFederatedFalseOrigin(mid);
|
||||
});
|
||||
connect(loader, &SceneLoader::dataSourceReady, this,
|
||||
[this](uint32_t mid) {
|
||||
applyCoordinateOperation(mid);
|
||||
});
|
||||
connect(loader, &SceneLoader::loadedFromStream, this,
|
||||
[this](uint32_t mid, qint64 /*elapsed_ms*/) {
|
||||
applyCoordinateOperation(mid);
|
||||
applyModelVisibility(mid);
|
||||
maybeGuessFederatedFalseOrigin(mid);
|
||||
});
|
||||
connect(&AppSettings::instance(),
|
||||
&AppSettings::applyCoordinateOperationChanged,
|
||||
this, [this](bool /*enabled*/) {
|
||||
for (uint32_t mid : session_state_->modelIds()) {
|
||||
applyCoordinateOperation(mid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ViewportController::applyCoordinateOperation(uint32_t mid) {
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
Eigen::Matrix4d matrix = Eigen::Matrix4d::Identity();
|
||||
if (AppSettings::instance().applyCoordinateOperation()) {
|
||||
if (const ModelGeoref* georef = loader->modelGeoref(mid)) {
|
||||
if (georef->has_coordinate_operation) {
|
||||
matrix = georef->coordinate_operation_meters;
|
||||
}
|
||||
}
|
||||
}
|
||||
viewport_->setModelCoordinateOperation(mid, matrix);
|
||||
applyModelTransformation(mid);
|
||||
}
|
||||
|
||||
void ViewportController::applyModelTransformation(uint32_t mid) {
|
||||
Federation* federation = session_state_->federation();
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
Eigen::Matrix4d matrix = Eigen::Matrix4d::Identity();
|
||||
const QString fed_id = session_state_->fedIdForModelId(mid);
|
||||
if (!fed_id.isEmpty()) {
|
||||
if (const Federation::Model* model = federation->findById(fed_id)) {
|
||||
ModelUnits units;
|
||||
Eigen::Matrix4d coordinate_operation = Eigen::Matrix4d::Identity();
|
||||
if (const ModelGeoref* georef = loader->modelGeoref(mid)) {
|
||||
units = georef->units;
|
||||
if (AppSettings::instance().applyCoordinateOperation() &&
|
||||
georef->has_coordinate_operation) {
|
||||
coordinate_operation = georef->coordinate_operation_meters;
|
||||
}
|
||||
}
|
||||
matrix = composeModelTransformation(
|
||||
model->model_transformation, federation->config(), units, coordinate_operation);
|
||||
}
|
||||
}
|
||||
viewport_->setModelTransformation(mid, matrix);
|
||||
}
|
||||
|
||||
void ViewportController::applyModelVisibility(uint32_t mid) {
|
||||
Federation* federation = session_state_->federation();
|
||||
const QString fed_id = session_state_->fedIdForModelId(mid);
|
||||
if (fed_id.isEmpty()) return;
|
||||
|
||||
if (federation->isModelEffectivelyVisible(fed_id)) {
|
||||
viewport_->showModel(mid);
|
||||
} else {
|
||||
viewport_->hideModel(mid);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportController::applyFederatedFalseOrigin() {
|
||||
Federation* federation = session_state_->federation();
|
||||
viewport_->setFederatedFalseOrigin(
|
||||
composeFederatedFalseOrigin(federation->federatedFalseOrigin(), federation->config()));
|
||||
}
|
||||
|
||||
void ViewportController::setHomeView() {
|
||||
auto camera = viewport_->cameraState();
|
||||
Federation::HomeView home_view;
|
||||
home_view.target = camera.target;
|
||||
home_view.distance = camera.distance;
|
||||
home_view.yaw = camera.yaw;
|
||||
home_view.pitch = camera.pitch;
|
||||
session_state_->federation()->setHomeView(home_view);
|
||||
session_state_->setStatusMessage("Camera", "Home view updated");
|
||||
}
|
||||
|
||||
void ViewportController::goHomeView() {
|
||||
Federation* federation = session_state_->federation();
|
||||
if (!federation->hasHomeView()) {
|
||||
session_state_->setStatusMessage("Camera", "No home view set for this project");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& home_view = federation->homeView();
|
||||
viewport_->setCamera(
|
||||
home_view.target.x(), home_view.target.y(), home_view.target.z(),
|
||||
home_view.distance, home_view.yaw, home_view.pitch);
|
||||
session_state_->setStatusMessage("Camera", "Home view restored");
|
||||
}
|
||||
|
||||
void ViewportController::maybeGuessFederatedFalseOrigin(uint32_t mid) {
|
||||
Federation* federation = session_state_->federation();
|
||||
SceneLoader* loader = session_state_->loader();
|
||||
if (!federation->filePath().isEmpty()) return;
|
||||
|
||||
const FederatedFalseOrigin& current = federation->federatedFalseOrigin();
|
||||
const FederatedFalseOrigin defaults;
|
||||
if (current.xyz != defaults.xyz || current.rz_deg != defaults.rz_deg) return;
|
||||
|
||||
const Eigen::Matrix4d* placement = loader->firstPlacement(mid);
|
||||
const ModelGeoref* georef = loader->modelGeoref(mid);
|
||||
if (placement == nullptr || georef == nullptr) return;
|
||||
|
||||
federation->setFederatedFalseOrigin(guessFederatedFalseOrigin(
|
||||
*placement, *georef, federation->config(),
|
||||
AppSettings::instance().applyCoordinateOperation()));
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::viewport
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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_PANELS_VIEWPORT_CONTROLLER_H
|
||||
#define IFCINTERFACE_PANELS_VIEWPORT_CONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace ifcinterface { class SessionState; }
|
||||
class ViewportWindow;
|
||||
|
||||
namespace ifcinterface::modules::viewport {
|
||||
|
||||
class ViewportController : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewportController(ifcinterface::SessionState* session_state,
|
||||
ViewportWindow* viewport,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
void applyFederatedFalseOrigin();
|
||||
void setHomeView();
|
||||
void goHomeView();
|
||||
|
||||
private:
|
||||
void applyCoordinateOperation(uint32_t mid);
|
||||
void applyModelTransformation(uint32_t mid);
|
||||
void applyModelVisibility(uint32_t mid);
|
||||
void maybeGuessFederatedFalseOrigin(uint32_t mid);
|
||||
|
||||
ifcinterface::SessionState* session_state_ = nullptr;
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::viewport
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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 "Panel.h"
|
||||
|
||||
#include "../../../ifcviewer/ViewportWindow.h"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
namespace ifcinterface::modules::viewport {
|
||||
|
||||
ViewportPanel::ViewportPanel(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(0, 0, 0, 0);
|
||||
root->setSpacing(0);
|
||||
|
||||
auto* shell = new QFrame(this);
|
||||
shell->setObjectName("viewportShell");
|
||||
auto* shell_layout = new QVBoxLayout(shell);
|
||||
shell_layout->setContentsMargins(10, 10, 10, 10);
|
||||
shell_layout->setSpacing(0);
|
||||
|
||||
auto* frame = new QFrame(shell);
|
||||
frame->setObjectName("viewportFrame");
|
||||
auto* frame_layout = new QVBoxLayout(frame);
|
||||
frame_layout->setContentsMargins(0, 0, 0, 0);
|
||||
frame_layout->setSpacing(0);
|
||||
|
||||
viewport_ = new ViewportWindow();
|
||||
viewport_container_ = QWidget::createWindowContainer(viewport_, frame);
|
||||
viewport_container_->setMinimumSize(400, 300);
|
||||
viewport_container_->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
frame_layout->addWidget(viewport_container_);
|
||||
shell_layout->addWidget(frame);
|
||||
root->addWidget(shell);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::modules::viewport
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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_MODULES_VIEWPORT_PANEL_H
|
||||
#define IFCINTERFACE_MODULES_VIEWPORT_PANEL_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class ViewportWindow;
|
||||
|
||||
namespace ifcinterface::modules::viewport {
|
||||
|
||||
class ViewportPanel : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ViewportPanel(QWidget* parent = nullptr);
|
||||
|
||||
ViewportWindow* viewport() const { return viewport_; }
|
||||
|
||||
private:
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
QWidget* viewport_container_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::modules::viewport
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user