Interface mockup 6

This commit is contained in:
Dion Moult
2026-05-06 12:36:28 +10:00
parent 802ddf8ff9
commit 0d5fa0c20c
12 changed files with 90 additions and 62 deletions
+20 -1
View File
@@ -32,18 +32,37 @@ ElementRegistry::ElementRegistry(QObject* parent)
} }
void ElementRegistry::bindLoader(SceneLoader* loader) { void ElementRegistry::bindLoader(SceneLoader* loader) {
loader_ = loader;
connect(loader, &SceneLoader::sidecarElementsReady, connect(loader, &SceneLoader::sidecarElementsReady,
this, &ElementRegistry::onSidecarElementsReady); this, &ElementRegistry::onSidecarElementsReady);
connect(loader, &SceneLoader::streamedElementsReady, connect(loader, &SceneLoader::streamedElementsReady,
this, &ElementRegistry::onStreamedElementsReady); this, &ElementRegistry::onStreamedElementsReady);
} }
std::optional<BasicElementInfo> ElementRegistry::find(uint32_t object_id) const { std::optional<BasicElementInfo> ElementRegistry::findBasicElementInfo(uint32_t object_id) const {
auto it = elements_.find(object_id); auto it = elements_.find(object_id);
if (it == elements_.end()) return std::nullopt; if (it == elements_.end()) return std::nullopt;
return it->second; return it->second;
} }
std::optional<express::Base> ElementRegistry::findEntity(uint32_t object_id) const {
if (!loader_) return std::nullopt;
auto info = findBasicElementInfo(object_id);
if (!info) return std::nullopt;
auto* file = loader_->ifcFile(info->model_id);
if (!file) return std::nullopt;
try {
auto instance = file->instance_by_id(info->ifc_id);
if (!instance) return std::nullopt;
return instance;
} catch (...) {
return std::nullopt;
}
}
void ElementRegistry::onSidecarElementsReady(uint32_t /*mid*/, void ElementRegistry::onSidecarElementsReady(uint32_t /*mid*/,
std::vector<PackedElementInfo> elements, std::vector<PackedElementInfo> elements,
std::string string_table) { std::string string_table) {
+5 -2
View File
@@ -23,10 +23,11 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include "../ifcparse/express.h"
#include <optional> #include <optional>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <string>
class SceneLoader; class SceneLoader;
struct PackedElementInfo; struct PackedElementInfo;
@@ -50,7 +51,8 @@ public:
explicit ElementRegistry(QObject* parent = nullptr); explicit ElementRegistry(QObject* parent = nullptr);
void bindLoader(SceneLoader* loader); void bindLoader(SceneLoader* loader);
std::optional<BasicElementInfo> find(uint32_t object_id) const; std::optional<BasicElementInfo> findBasicElementInfo(uint32_t object_id) const;
std::optional<express::Base> findEntity(uint32_t object_id) const;
private: private:
void onSidecarElementsReady(uint32_t mid, void onSidecarElementsReady(uint32_t mid,
@@ -58,6 +60,7 @@ private:
std::string string_table); std::string string_table);
void onStreamedElementsReady(uint32_t mid, std::vector<ElementInfo> elements); void onStreamedElementsReady(uint32_t mid, std::vector<ElementInfo> elements);
SceneLoader* loader_ = nullptr;
std::unordered_map<uint32_t, BasicElementInfo> elements_; std::unordered_map<uint32_t, BasicElementInfo> elements_;
}; };
+1 -1
View File
@@ -388,7 +388,7 @@ void MainWindow::setupPanels() {
models_panel_ = new components::Panel("Models", models_widget, this, true); models_panel_ = new components::Panel("Models", models_widget, this, true);
spatial_panel_ = new components::Panel("Spatial Hierarchy", spatial_widget, this); spatial_panel_ = new components::Panel("Spatial Hierarchy", spatial_widget, this);
properties_panel_ = new components::Panel("Properties", properties_widget, this); properties_panel_ = new components::Panel("Properties", properties_widget, this, false, true);
layers_panel_ = new components::Panel("Layers", new panels::todo::TodoPanelWidget("Layers", this), this); layers_panel_ = new components::Panel("Layers", new panels::todo::TodoPanelWidget("Layers", this), this);
stored_views_panel_ = new components::Panel( stored_views_panel_ = new components::Panel(
"Stored Views", new panels::todo::TodoPanelWidget("Stored Views", this), this); "Stored Views", new panels::todo::TodoPanelWidget("Stored Views", this), this);
+2 -2
View File
@@ -31,7 +31,7 @@ namespace ifcinterface::components {
KeyValueTable::KeyValueTable(const QList<KeyValueTableRow>& rows, QWidget* parent) KeyValueTable::KeyValueTable(const QList<KeyValueTableRow>& rows, QWidget* parent)
: QWidget(parent) : QWidget(parent)
{ {
setObjectName("attributeList"); setObjectName("keyValueTable");
auto* layout = new QVBoxLayout(this); auto* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
@@ -57,7 +57,7 @@ KeyValueTable::KeyValueTable(const QList<KeyValueTableRow>& rows, QWidget* paren
auto* value = new QLabel(row_data.value, row); auto* value = new QLabel(row_data.value, row);
value->setObjectName(row_data.value_object_name.isEmpty() value->setObjectName(row_data.value_object_name.isEmpty()
? "propertyValueLabel" ? "keyValueValueLabel"
: row_data.value_object_name); : row_data.value_object_name);
value->setWordWrap(true); value->setWordWrap(true);
value->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); value->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+1 -1
View File
@@ -30,7 +30,7 @@ namespace ifcinterface::components {
struct KeyValueTableRow { struct KeyValueTableRow {
QString key; QString key;
QString value; QString value;
QString value_object_name = "propertyValueLabel"; QString value_object_name = "keyValueValueLabel";
QString trailing_icon_path; QString trailing_icon_path;
QString trailing_icon_object_name; QString trailing_icon_object_name;
int key_minimum_width = 0; int key_minimum_width = 0;
+20 -2
View File
@@ -28,6 +28,7 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QMenu> #include <QMenu>
#include <QScrollArea>
#include <QToolButton> #include <QToolButton>
#include <QVBoxLayout> #include <QVBoxLayout>
@@ -70,7 +71,7 @@ public:
} // namespace } // namespace
Panel::Panel(const QString& title, QWidget* content, QWidget* parent, bool has_settings) Panel::Panel(const QString& title, QWidget* content, QWidget* parent, bool has_settings, bool scrollable)
: QDockWidget(title, parent) : QDockWidget(title, parent)
{ {
auto* outer = new QFrame(); auto* outer = new QFrame();
@@ -86,7 +87,24 @@ Panel::Panel(const QString& title, QWidget* content, QWidget* parent, bool has_s
auto* frame_layout = new QVBoxLayout(frame); auto* frame_layout = new QVBoxLayout(frame);
frame_layout->setContentsMargins(0, style::metrics::padding, 0, style::metrics::padding); frame_layout->setContentsMargins(0, style::metrics::padding, 0, style::metrics::padding);
frame_layout->setSpacing(0); frame_layout->setSpacing(0);
frame_layout->addWidget(content);
if (scrollable) {
auto* scroll = new QScrollArea(frame);
scroll->setWidgetResizable(true);
scroll->setFrameShape(QFrame::NoFrame);
auto* scroll_body = new QWidget(scroll);
scroll_body->setObjectName("panelScrollBody");
auto* scroll_body_layout = new QVBoxLayout(scroll_body);
scroll_body_layout->setContentsMargins(0, 0, 0, 0);
scroll_body_layout->setSpacing(0);
scroll_body_layout->addWidget(content);
scroll->setWidget(scroll_body);
frame_layout->addWidget(scroll);
} else {
frame_layout->addWidget(content);
}
outer_layout->addWidget(frame); outer_layout->addWidget(frame);
setObjectName(title); setObjectName(title);
+5 -1
View File
@@ -31,7 +31,11 @@ class Panel : public QDockWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit Panel(const QString& title, QWidget* content, QWidget* parent = nullptr, bool has_settings = false); explicit Panel(const QString& title,
QWidget* content,
QWidget* parent = nullptr,
bool has_settings = false,
bool scrollable = false);
}; };
} // namespace ifcinterface::components } // namespace ifcinterface::components
+3 -17
View File
@@ -164,7 +164,7 @@ QString buildAppStyleSheet() {
color: #9aa4b3; color: #9aa4b3;
background: transparent; background: transparent;
} }
QWidget#attributeList { QWidget#keyValueTable {
background: transparent; background: transparent;
} }
QTreeView::item, QListView::item, QTableView::item { QTreeView::item, QListView::item, QTableView::item {
@@ -237,7 +237,7 @@ QString buildAppStyleSheet() {
QLabel#relationshipIconLabel { QLabel#relationshipIconLabel {
background: transparent; background: transparent;
} }
QWidget#inspectorPanel { QWidget#panelScrollBody {
background: #2b2f36; background: #2b2f36;
} }
QFrame#panelSectionHeader { QFrame#panelSectionHeader {
@@ -274,24 +274,10 @@ QString buildAppStyleSheet() {
color: #9aa4b3; color: #9aa4b3;
background: transparent; background: transparent;
} }
QLabel#propertyValueLabel { QLabel#keyValueValueLabel {
color: #dce2eb; color: #dce2eb;
background: transparent; background: transparent;
} }
QLabel#relationshipValueLabel {
color: #dce2eb;
background: transparent;
}
QLabel#todoPanelTitle {
font-size: 14px;
font-weight: 600;
color: #e1e6ee;
background: transparent;
}
QLabel#todoPanelBody {
color: #8f98a6;
background: transparent;
}
)") )")
.arg(metrics::panel_radius) .arg(metrics::panel_radius)
.arg(metrics::control_padding_y) .arg(metrics::control_padding_y)
@@ -23,6 +23,7 @@
#include "PropertiesPanelWidget.h" #include "PropertiesPanelWidget.h"
#include "../../ElementRegistry.h" #include "../../ElementRegistry.h"
#include "../../../ifcviewer/AppSettings.h"
#include "../../../ifcviewer/ViewportWindow.h" #include "../../../ifcviewer/ViewportWindow.h"
namespace ifcinterface::panels::properties { namespace ifcinterface::panels::properties {
@@ -79,8 +80,13 @@ void PropertiesPanelView::refresh(uint32_t object_id) {
{"Paint Coverage", "42.78 m2"}}}, {"Paint Coverage", "42.78 m2"}}},
}; };
if (registry_) { if (!registry_) {
auto info = registry_->find(object_id); widget_->render(state);
return;
}
if (!AppSettings::instance().loadDataSource()) {
auto info = registry_->findBasicElementInfo(object_id);
if (info && !info->type.isEmpty()) { if (info && !info->type.isEmpty()) {
state.entity.entity_class = info->type; state.entity.entity_class = info->type;
if (!state.property_sets.isEmpty() && !state.property_sets[1].rows.isEmpty()) { if (!state.property_sets.isEmpty() && !state.property_sets[1].rows.isEmpty()) {
@@ -96,6 +102,17 @@ void PropertiesPanelView::refresh(uint32_t object_id) {
if (info && !info->guid.isEmpty()) { if (info && !info->guid.isEmpty()) {
state.attributes[0].value = info->guid; 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); widget_->render(state);
} }
@@ -28,7 +28,6 @@
#include <QGroupBox> #include <QGroupBox>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QLabel> #include <QLabel>
#include <QScrollArea>
#include <QVBoxLayout> #include <QVBoxLayout>
namespace { namespace {
@@ -42,7 +41,7 @@ QWidget* makePropertySetPanel(const ifcinterface::panels::properties::PropertySe
QList<ifcinterface::components::KeyValueTableRow> rows; QList<ifcinterface::components::KeyValueTableRow> rows;
for (const auto& row : property_set.rows) { for (const auto& row : property_set.rows) {
rows.append({row.key, row.value, "propertyValueLabel", "", "", 0}); rows.append({row.key, row.value, "keyValueValueLabel", "", "", 0});
} }
layout->addWidget(new ifcinterface::components::KeyValueTable(rows, group)); layout->addWidget(new ifcinterface::components::KeyValueTable(rows, group));
return group; return group;
@@ -51,7 +50,7 @@ QWidget* makePropertySetPanel(const ifcinterface::panels::properties::PropertySe
QWidget* makeAttributeList(const QList<ifcinterface::panels::properties::KeyValueRow>& rows, QWidget* parent = nullptr) { QWidget* makeAttributeList(const QList<ifcinterface::panels::properties::KeyValueRow>& rows, QWidget* parent = nullptr) {
QList<ifcinterface::components::KeyValueTableRow> table_rows; QList<ifcinterface::components::KeyValueTableRow> table_rows;
for (const auto& row : rows) { for (const auto& row : rows) {
table_rows.append({row.key, row.value, "propertyValueLabel", "", "", 0}); table_rows.append({row.key, row.value, "keyValueValueLabel", "", "", 0});
} }
return new ifcinterface::components::KeyValueTable(table_rows, parent); return new ifcinterface::components::KeyValueTable(table_rows, parent);
} }
@@ -61,7 +60,7 @@ QWidget* makeRelationshipList(const QList<ifcinterface::panels::properties::Rela
for (const auto& row_data : rows) { for (const auto& row_data : rows) {
table_rows.append({row_data.key, table_rows.append({row_data.key,
row_data.value, row_data.value,
"relationshipValueLabel", "keyValueValueLabel",
":/icons/cursor-pointer.svg", ":/icons/cursor-pointer.svg",
"relationshipIconLabel", "relationshipIconLabel",
72}); 72});
@@ -76,22 +75,9 @@ namespace ifcinterface::panels::properties {
PropertiesPanelWidget::PropertiesPanelWidget(QWidget* parent) PropertiesPanelWidget::PropertiesPanelWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
{ {
auto* root = new QVBoxLayout(this); content_layout_ = new QVBoxLayout(this);
root->setContentsMargins(0, 0, 0, 0);
root->setSpacing(0);
scroll_ = new QScrollArea(this);
scroll_->setWidgetResizable(true);
scroll_->setFrameShape(QFrame::NoFrame);
content_ = new QWidget(scroll_);
content_->setObjectName("inspectorPanel");
content_layout_ = new QVBoxLayout(content_);
content_layout_->setContentsMargins(0, 0, 0, 0); content_layout_->setContentsMargins(0, 0, 0, 0);
content_layout_->setSpacing(12); content_layout_->setSpacing(12);
scroll_->setWidget(content_);
root->addWidget(scroll_);
} }
void PropertiesPanelWidget::render(const PropertiesPanelState& state) { void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
@@ -100,7 +86,7 @@ void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
delete item; delete item;
} }
auto* entity_card = new QFrame(content_); auto* entity_card = new QFrame(this);
entity_card->setObjectName("entityClassCard"); entity_card->setObjectName("entityClassCard");
auto* entity_layout = new QHBoxLayout(entity_card); auto* entity_layout = new QHBoxLayout(entity_card);
entity_layout->setContentsMargins(10, 8, 10, 8); entity_layout->setContentsMargins(10, 8, 10, 8);
@@ -123,23 +109,23 @@ void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
QList<QWidget*> property_set_widgets; QList<QWidget*> property_set_widgets;
for (const auto& property_set : state.property_sets) { for (const auto& property_set : state.property_sets) {
property_set_widgets.append(makePropertySetPanel(property_set, content_)); property_set_widgets.append(makePropertySetPanel(property_set, this));
} }
QList<QWidget*> quantity_set_widgets; QList<QWidget*> quantity_set_widgets;
for (const auto& property_set : state.quantity_sets) { for (const auto& property_set : state.quantity_sets) {
quantity_set_widgets.append(makePropertySetPanel(property_set, content_)); quantity_set_widgets.append(makePropertySetPanel(property_set, this));
} }
auto* entity_section = new components::Section("", components::SectionHeaderMode::Hidden, "", content_); auto* entity_section = new components::Section("", components::SectionHeaderMode::Hidden, "", this);
entity_section->addBodyWidget(entity_card); entity_section->addBodyWidget(entity_card);
auto* attributes_section = new components::Section("Attributes", components::SectionHeaderMode::Visible, "", content_); auto* attributes_section = new components::Section("Attributes", components::SectionHeaderMode::Visible, "", this);
attributes_section->addBodyWidget(makeAttributeList(state.attributes, content_)); attributes_section->addBodyWidget(makeAttributeList(state.attributes, this));
auto* relationships_section = new components::Section("Relationships", components::SectionHeaderMode::Visible, "", content_); auto* relationships_section = new components::Section("Relationships", components::SectionHeaderMode::Visible, "", this);
relationships_section->addBodyWidget(makeRelationshipList(state.relationships, content_)); relationships_section->addBodyWidget(makeRelationshipList(state.relationships, this));
auto* properties_section = new components::Section("Properties", components::SectionHeaderMode::Visible, "Filter properties or sets", content_); auto* properties_section = new components::Section("Properties", components::SectionHeaderMode::Visible, "Filter properties or sets", this);
for (auto* widget : property_set_widgets) properties_section->addBodyWidget(widget); for (auto* widget : property_set_widgets) properties_section->addBodyWidget(widget);
auto* quantities_section = new components::Section("Quantities", components::SectionHeaderMode::Visible, "Filter quantities or sets", content_); auto* quantities_section = new components::Section("Quantities", components::SectionHeaderMode::Visible, "Filter quantities or sets", this);
for (auto* widget : quantity_set_widgets) quantities_section->addBodyWidget(widget); for (auto* widget : quantity_set_widgets) quantities_section->addBodyWidget(widget);
content_layout_->addWidget(entity_section); content_layout_->addWidget(entity_section);
@@ -25,7 +25,6 @@
#include <QWidget> #include <QWidget>
class QScrollArea;
class QVBoxLayout; class QVBoxLayout;
namespace ifcinterface::panels::properties { namespace ifcinterface::panels::properties {
@@ -38,8 +37,6 @@ public:
void render(const PropertiesPanelState& state); void render(const PropertiesPanelState& state);
private: private:
QScrollArea* scroll_ = nullptr;
QWidget* content_ = nullptr;
QVBoxLayout* content_layout_ = nullptr; QVBoxLayout* content_layout_ = nullptr;
}; };
@@ -42,10 +42,8 @@ TodoPanelWidget::TodoPanelWidget(const QString& title, QWidget* parent)
body_layout->setSpacing(12); body_layout->setSpacing(12);
auto* heading = new QLabel(title, body); auto* heading = new QLabel(title, body);
heading->setObjectName("todoPanelTitle");
auto* content = new QLabel("Coming soon", body); auto* content = new QLabel("Coming soon", body);
content->setObjectName("todoPanelBody");
content->setAlignment(Qt::AlignCenter); content->setAlignment(Qt::AlignCenter);
body_layout->addWidget(heading); body_layout->addWidget(heading);