mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Interface mockup 5
This commit is contained in:
@@ -25,14 +25,20 @@ find_package(Qt${QT_VERSION} COMPONENTS Core Gui Widgets Svg REQUIRED PATHS ${QT
|
||||
|
||||
set(INTERFACE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ElementRegistry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ElementRegistry.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/SvgIcon.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/SvgIcon.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/Style.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/Style.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/KeyValueTable.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/KeyValueTable.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/Section.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/Section.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/PanelChrome.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/PanelChrome.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/Panel.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/components/Panel.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/panels/models/ModelsPanelTypes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/panels/models/ModelsPanelWidget.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/panels/models/ModelsPanelWidget.h
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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 "ElementRegistry.h"
|
||||
|
||||
#include "../ifcviewer/GeometryStreamer.h"
|
||||
#include "../ifcviewer/SceneLoader.h"
|
||||
#include "../ifcviewer/SidecarCache.h"
|
||||
|
||||
namespace ifcinterface {
|
||||
|
||||
ElementRegistry::ElementRegistry(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ElementRegistry::bindLoader(SceneLoader* loader) {
|
||||
connect(loader, &SceneLoader::sidecarElementsReady,
|
||||
this, &ElementRegistry::onSidecarElementsReady);
|
||||
connect(loader, &SceneLoader::streamedElementsReady,
|
||||
this, &ElementRegistry::onStreamedElementsReady);
|
||||
}
|
||||
|
||||
std::optional<BasicElementInfo> ElementRegistry::find(uint32_t object_id) const {
|
||||
auto it = elements_.find(object_id);
|
||||
if (it == elements_.end()) return std::nullopt;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void ElementRegistry::onSidecarElementsReady(uint32_t /*mid*/,
|
||||
std::vector<PackedElementInfo> elements,
|
||||
std::string string_table) {
|
||||
auto str = [&](uint32_t offset, uint32_t length) -> QString {
|
||||
if (length == 0 || offset + length > string_table.size()) return {};
|
||||
return QString::fromStdString(string_table.substr(offset, length));
|
||||
};
|
||||
|
||||
for (const auto& pe : elements) {
|
||||
BasicElementInfo info;
|
||||
info.object_id = pe.object_id;
|
||||
info.model_id = pe.model_id;
|
||||
info.ifc_id = pe.ifc_id;
|
||||
info.parent_id = pe.parent_id;
|
||||
info.guid = str(pe.guid_offset, pe.guid_length);
|
||||
info.name = str(pe.name_offset, pe.name_length);
|
||||
info.type = str(pe.type_offset, pe.type_length);
|
||||
elements_[info.object_id] = info;
|
||||
}
|
||||
}
|
||||
|
||||
void ElementRegistry::onStreamedElementsReady(uint32_t /*mid*/, std::vector<ElementInfo> elements) {
|
||||
for (const auto& e : elements) {
|
||||
BasicElementInfo info;
|
||||
info.object_id = e.object_id;
|
||||
info.model_id = e.model_id;
|
||||
info.ifc_id = e.ifc_id;
|
||||
info.parent_id = e.parent_id;
|
||||
info.guid = QString::fromStdString(e.guid);
|
||||
info.name = QString::fromStdString(e.name);
|
||||
info.type = QString::fromStdString(e.type);
|
||||
elements_[info.object_id] = info;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ifcinterface
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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_ELEMENTREGISTRY_H
|
||||
#define IFCINTERFACE_ELEMENTREGISTRY_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class SceneLoader;
|
||||
struct PackedElementInfo;
|
||||
struct ElementInfo;
|
||||
|
||||
namespace ifcinterface {
|
||||
|
||||
struct BasicElementInfo {
|
||||
uint32_t object_id = 0;
|
||||
uint32_t model_id = 0;
|
||||
int ifc_id = 0;
|
||||
int parent_id = 0;
|
||||
QString guid;
|
||||
QString name;
|
||||
QString type;
|
||||
};
|
||||
|
||||
class ElementRegistry : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ElementRegistry(QObject* parent = nullptr);
|
||||
|
||||
void bindLoader(SceneLoader* loader);
|
||||
std::optional<BasicElementInfo> find(uint32_t object_id) const;
|
||||
|
||||
private:
|
||||
void onSidecarElementsReady(uint32_t mid,
|
||||
std::vector<PackedElementInfo> elements,
|
||||
std::string string_table);
|
||||
void onStreamedElementsReady(uint32_t mid, std::vector<ElementInfo> elements);
|
||||
|
||||
std::unordered_map<uint32_t, BasicElementInfo> elements_;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface
|
||||
|
||||
#endif
|
||||
+69
-342
@@ -23,7 +23,9 @@
|
||||
#include "../ifcviewer/AppSettings.h"
|
||||
#include "../ifcviewer/SceneLoader.h"
|
||||
#include "../ifcviewer/ViewportWindow.h"
|
||||
#include "components/PanelChrome.h"
|
||||
#include "ElementRegistry.h"
|
||||
#include "components/Panel.h"
|
||||
#include "components/Style.h"
|
||||
#include "components/SvgIcon.h"
|
||||
#include "panels/todo/TodoPanelWidget.h"
|
||||
#include "panels/models/ModelsPanelView.h"
|
||||
@@ -52,9 +54,10 @@ namespace ifcinterface::shell {
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
element_registry_ = new ifcinterface::ElementRegistry(this);
|
||||
setupChrome();
|
||||
setupViewport();
|
||||
setupDocks();
|
||||
setupPanels();
|
||||
setupStatus();
|
||||
setupLoader();
|
||||
setupRibbon();
|
||||
@@ -66,280 +69,7 @@ void MainWindow::setupChrome() {
|
||||
setDockOptions(QMainWindow::AllowNestedDocks |
|
||||
QMainWindow::AllowTabbedDocks |
|
||||
QMainWindow::GroupedDragging);
|
||||
|
||||
setStyleSheet(R"(
|
||||
QMainWindow {
|
||||
background: #26292f;
|
||||
}
|
||||
QWidget {
|
||||
color: #d0d5dd;
|
||||
background: #26292f;
|
||||
selection-background-color: #39b54a;
|
||||
selection-color: #14161a;
|
||||
}
|
||||
QFrame#ribbonShell {
|
||||
background: #2d3138;
|
||||
border-bottom: 1px solid #1b1d22;
|
||||
}
|
||||
QTabBar::tab {
|
||||
background: transparent;
|
||||
color: #8d97a7;
|
||||
padding: 8px 14px;
|
||||
margin-right: 2px;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
QTabBar::tab:selected {
|
||||
color: #f2f5fa;
|
||||
border-bottom: 2px solid #39b54a;
|
||||
}
|
||||
QTabBar::tab:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
QFrame#ribbonBand {
|
||||
background: #31353d;
|
||||
border-top: 1px solid #3b4048;
|
||||
}
|
||||
QFrame#ribbonPage {
|
||||
background: transparent;
|
||||
}
|
||||
QFrame#ribbonGroup {
|
||||
background: transparent;
|
||||
border-right: 1px solid #434852;
|
||||
}
|
||||
QLabel#ribbonGroupLabel {
|
||||
color: #7f8796;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
QToolButton#ribbonButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 6px 4px 4px 4px;
|
||||
font-size: 11px;
|
||||
color: #d6dce6;
|
||||
}
|
||||
QToolButton#ribbonButton:hover {
|
||||
background: #3a3f48;
|
||||
}
|
||||
QToolButton#ribbonButton:pressed {
|
||||
background: #24282f;
|
||||
}
|
||||
QFrame#viewportShell {
|
||||
background: #202329;
|
||||
border-top: 1px solid #1d2025;
|
||||
}
|
||||
QFrame#viewportFrame {
|
||||
background: #1a1d22;
|
||||
border: 1px solid #333942;
|
||||
}
|
||||
QDockWidget {
|
||||
color: #d0d5dd;
|
||||
}
|
||||
QLabel#dockTitleText {
|
||||
color: #dfe4ec;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
QToolButton#dockTitleButton {
|
||||
color: #8e97a5;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
QToolButton#dockTitleButton:hover {
|
||||
color: #ffffff;
|
||||
background: #353a42;
|
||||
}
|
||||
QFrame#panelFrame {
|
||||
background: #2b2f36;
|
||||
border: 1px solid #3e444e;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QWidget#panelBody {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QTreeWidget, QListWidget, QTableWidget, QAbstractScrollArea {
|
||||
background: #2b2f36;
|
||||
border: none;
|
||||
outline: none;
|
||||
gridline-color: #333842;
|
||||
}
|
||||
QTreeWidget::viewport, QListWidget::viewport, QTableWidget::viewport {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QHeaderView::section {
|
||||
background: #31353d;
|
||||
color: #b5becc;
|
||||
border: none;
|
||||
border-bottom: 1px solid #434a55;
|
||||
padding: 7px 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
QTableCornerButton::section {
|
||||
background: #31353d;
|
||||
border: none;
|
||||
}
|
||||
QScrollArea {
|
||||
background: #2b2f36;
|
||||
border: none;
|
||||
}
|
||||
QScrollArea > QWidget > QWidget {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QLineEdit {
|
||||
background: #31353d;
|
||||
border: 1px solid #434a55;
|
||||
border-radius: 3px;
|
||||
padding: 6px 8px;
|
||||
color: #d9dfeb;
|
||||
}
|
||||
QLineEdit:focus {
|
||||
border: 1px solid #5b6472;
|
||||
}
|
||||
QFrame#entityClassCard {
|
||||
background: #26292f;
|
||||
border: 1px solid #404650;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QLabel#entityClassLabel {
|
||||
color: #eef2f8;
|
||||
font-weight: 700;
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#entityTypeLabel {
|
||||
color: #9aa4b3;
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#attributeList {
|
||||
background: transparent;
|
||||
}
|
||||
QTreeView::item, QListView::item, QTableView::item {
|
||||
padding: 4px;
|
||||
}
|
||||
QScrollBar:vertical {
|
||||
background: transparent;
|
||||
width: 10px;
|
||||
margin: 2px 2px 2px 0;
|
||||
}
|
||||
QScrollBar:horizontal {
|
||||
background: transparent;
|
||||
height: 10px;
|
||||
margin: 0 2px 2px 2px;
|
||||
}
|
||||
QScrollBar::handle:vertical, QScrollBar::handle:horizontal {
|
||||
background: #525a67;
|
||||
border-radius: 3px;
|
||||
min-height: 24px;
|
||||
min-width: 24px;
|
||||
}
|
||||
QScrollBar::handle:vertical:hover, QScrollBar::handle:horizontal:hover {
|
||||
background: #697385;
|
||||
}
|
||||
QScrollBar::add-line, QScrollBar::sub-line,
|
||||
QScrollBar::add-page, QScrollBar::sub-page {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
QStatusBar {
|
||||
background: #24272c;
|
||||
border-top: 1px solid #1a1c20;
|
||||
}
|
||||
QStatusBar QLabel {
|
||||
color: #97a1af;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
QGroupBox {
|
||||
background: transparent;
|
||||
border: 1px solid #404650;
|
||||
border-radius: 3px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox#propertySetCard {
|
||||
background: #26292f;
|
||||
border: 1px solid #404650;
|
||||
border-radius: 3px;
|
||||
}
|
||||
QGroupBox#propertySetCard::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 4px;
|
||||
color: #d5dbe5;
|
||||
}
|
||||
QGroupBox#propertySetCard > QWidget {
|
||||
background: #26292f;
|
||||
}
|
||||
QWidget#panelSection {
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#panelSectionFilterWrapper {
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#relationshipRow {
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#relationshipIconLabel {
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#inspectorPanel {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QFrame#panelSectionHeader {
|
||||
background: #26292f;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #e1e7f0;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton::menu-indicator {
|
||||
image: none;
|
||||
width: 0;
|
||||
}
|
||||
QToolButton#panelSectionFilterToggle {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
}
|
||||
QToolButton#panelSectionFilterToggle:hover {
|
||||
background: #353a42;
|
||||
}
|
||||
QWidget#panelSectionBody {
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#propertyKeyLabel {
|
||||
color: #9aa4b3;
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#propertyValueLabel {
|
||||
color: #dce2eb;
|
||||
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;
|
||||
}
|
||||
)");
|
||||
setStyleSheet(components::style::buildAppStyleSheet());
|
||||
}
|
||||
|
||||
QToolButton* MainWindow::makeRibbonAction(const QString& text, const QString& icon_path) {
|
||||
@@ -376,17 +106,13 @@ QWidget* MainWindow::makeRibbonGroup(const QString& title, const QList<QToolButt
|
||||
return group;
|
||||
}
|
||||
|
||||
QWidget* MainWindow::makeComingSoonPanel(const QString& title) {
|
||||
return new panels::todo::TodoPanelWidget(title, this);
|
||||
}
|
||||
|
||||
void MainWindow::setStatusMessage(const QString& mode, const QString& detail) {
|
||||
status_mode_label_->setText(mode);
|
||||
status_selection_label_->setText(detail);
|
||||
}
|
||||
|
||||
QToolButton* MainWindow::makePanelToggle(const QString& text, QDockWidget* dock) {
|
||||
auto* button = makeRibbonAction(text, ":/icons/dm_toggle_openings.png");
|
||||
auto* button = makeRibbonAction(text, ":/icons/sidebar-expand.svg");
|
||||
button->setCheckable(true);
|
||||
button->setChecked(dock->isVisible());
|
||||
connect(button, &QToolButton::toggled, dock, [dock](bool checked) {
|
||||
@@ -565,19 +291,20 @@ QWidget* MainWindow::buildPanelsRibbonPage() {
|
||||
row->setSpacing(0);
|
||||
|
||||
row->addWidget(makeRibbonGroup("DATA", {
|
||||
makePanelToggle("Models", models_dock_),
|
||||
makePanelToggle("Spatial", spatial_dock_),
|
||||
makePanelToggle("Layers", layers_dock_),
|
||||
makePanelToggle("Properties", properties_dock_)
|
||||
makePanelToggle("Models", models_panel_),
|
||||
makePanelToggle("Spatial", spatial_panel_),
|
||||
makePanelToggle("Layers", layers_panel_),
|
||||
makePanelToggle("Properties", properties_panel_)
|
||||
}));
|
||||
row->addWidget(makeRibbonGroup("QUERY", {
|
||||
makePanelToggle("Views", stored_views_dock_),
|
||||
makePanelToggle("Search", search_dock_),
|
||||
makePanelToggle("Sheets", spreadsheet_dock_)
|
||||
makePanelToggle("Views", stored_views_panel_),
|
||||
makePanelToggle("Search", search_panel_),
|
||||
makePanelToggle("Sheets", spreadsheet_panel_),
|
||||
makePanelToggle("Audit", audit_panel_)
|
||||
}));
|
||||
row->addWidget(makeRibbonGroup("COLLABORATE", {
|
||||
makePanelToggle("Clash", clash_dock_),
|
||||
makePanelToggle("Issues", issues_dock_)
|
||||
makePanelToggle("Clash", clash_panel_),
|
||||
makePanelToggle("Issues", issues_panel_)
|
||||
}));
|
||||
row->addStretch(1);
|
||||
return page;
|
||||
@@ -644,68 +371,67 @@ void MainWindow::setupViewport() {
|
||||
setCentralWidget(shell);
|
||||
}
|
||||
|
||||
void MainWindow::setupDocks() {
|
||||
auto* models_panel = new panels::models::ModelsPanelWidget(this);
|
||||
auto* spatial_panel = new panels::spatial_hierarchy::SpatialHierarchyPanelWidget(this);
|
||||
auto* properties_panel = new panels::properties::PropertiesPanelWidget(this);
|
||||
void MainWindow::setupPanels() {
|
||||
auto* models_widget = new panels::models::ModelsPanelWidget(this);
|
||||
auto* spatial_widget = new panels::spatial_hierarchy::SpatialHierarchyPanelWidget(this);
|
||||
auto* properties_widget = new panels::properties::PropertiesPanelWidget(this);
|
||||
|
||||
models_panel_view_ = new panels::models::ModelsPanelView(models_panel, this);
|
||||
spatial_panel_view_ = new panels::spatial_hierarchy::SpatialHierarchyPanelView(spatial_panel, this);
|
||||
properties_panel_view_ = new panels::properties::PropertiesPanelView(properties_panel, this);
|
||||
models_view_ = new panels::models::ModelsPanelView(models_widget, this);
|
||||
spatial_view_ = new panels::spatial_hierarchy::SpatialHierarchyPanelView(spatial_widget, this);
|
||||
properties_view_ = new panels::properties::PropertiesPanelView(
|
||||
properties_widget, viewport_, element_registry_, this);
|
||||
|
||||
connect(models_panel_view_, &panels::models::ModelsPanelView::statusMessageRequested,
|
||||
connect(models_view_, &panels::models::ModelsPanelView::statusMessageRequested,
|
||||
this, &MainWindow::setStatusMessage);
|
||||
connect(spatial_panel_view_, &panels::spatial_hierarchy::SpatialHierarchyPanelView::statusMessageRequested,
|
||||
connect(spatial_view_, &panels::spatial_hierarchy::SpatialHierarchyPanelView::statusMessageRequested,
|
||||
this, &MainWindow::setStatusMessage);
|
||||
|
||||
models_dock_ = components::panel::makeDock(
|
||||
"Models", components::panel::wrapPanel(models_panel), this, true);
|
||||
spatial_dock_ = components::panel::makeDock(
|
||||
"Spatial Hierarchy", components::panel::wrapPanel(spatial_panel), this);
|
||||
properties_dock_ = components::panel::makeDock(
|
||||
"Properties", components::panel::wrapPanel(properties_panel), this);
|
||||
layers_dock_ = components::panel::makeDock(
|
||||
"Layers", components::panel::wrapPanel(makeComingSoonPanel("Layers")), this);
|
||||
stored_views_dock_ = components::panel::makeDock(
|
||||
"Stored Views", components::panel::wrapPanel(makeComingSoonPanel("Stored Views")), this);
|
||||
search_dock_ = components::panel::makeDock(
|
||||
"Search and Query", components::panel::wrapPanel(makeComingSoonPanel("Search and Query")), this);
|
||||
spreadsheet_dock_ = components::panel::makeDock(
|
||||
"Spreadsheet", components::panel::wrapPanel(makeComingSoonPanel("Spreadsheet")), this);
|
||||
clash_dock_ = components::panel::makeDock(
|
||||
"Clash", components::panel::wrapPanel(makeComingSoonPanel("Clash")), this);
|
||||
issues_dock_ = components::panel::makeDock(
|
||||
"Issues", components::panel::wrapPanel(makeComingSoonPanel("Issues")), this);
|
||||
models_panel_ = new components::Panel("Models", models_widget, this, true);
|
||||
spatial_panel_ = new components::Panel("Spatial Hierarchy", spatial_widget, this);
|
||||
properties_panel_ = new components::Panel("Properties", properties_widget, this);
|
||||
layers_panel_ = new components::Panel("Layers", new panels::todo::TodoPanelWidget("Layers", this), this);
|
||||
stored_views_panel_ = new components::Panel(
|
||||
"Stored Views", new panels::todo::TodoPanelWidget("Stored Views", this), this);
|
||||
search_panel_ = new components::Panel(
|
||||
"Search and Query", new panels::todo::TodoPanelWidget("Search and Query", this), this);
|
||||
spreadsheet_panel_ = new components::Panel(
|
||||
"Spreadsheet", new panels::todo::TodoPanelWidget("Spreadsheet", this), this);
|
||||
audit_panel_ = new components::Panel("Audit", new panels::todo::TodoPanelWidget("Audit", this), this);
|
||||
clash_panel_ = new components::Panel("Clash", new panels::todo::TodoPanelWidget("Clash", this), this);
|
||||
issues_panel_ = new components::Panel("Issues", new panels::todo::TodoPanelWidget("Issues", this), this);
|
||||
|
||||
addDockWidget(Qt::LeftDockWidgetArea, models_dock_);
|
||||
addDockWidget(Qt::LeftDockWidgetArea, spatial_dock_);
|
||||
splitDockWidget(models_dock_, spatial_dock_, Qt::Vertical);
|
||||
addDockWidget(Qt::LeftDockWidgetArea, models_panel_);
|
||||
addDockWidget(Qt::LeftDockWidgetArea, spatial_panel_);
|
||||
splitDockWidget(models_panel_, spatial_panel_, Qt::Vertical);
|
||||
|
||||
addDockWidget(Qt::RightDockWidgetArea, properties_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, layers_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, stored_views_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, search_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, spreadsheet_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, clash_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, issues_dock_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, properties_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, layers_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, stored_views_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, search_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, spreadsheet_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, audit_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, clash_panel_);
|
||||
addDockWidget(Qt::RightDockWidgetArea, issues_panel_);
|
||||
|
||||
tabifyDockWidget(properties_dock_, layers_dock_);
|
||||
tabifyDockWidget(layers_dock_, stored_views_dock_);
|
||||
tabifyDockWidget(stored_views_dock_, search_dock_);
|
||||
tabifyDockWidget(search_dock_, spreadsheet_dock_);
|
||||
tabifyDockWidget(spreadsheet_dock_, clash_dock_);
|
||||
tabifyDockWidget(clash_dock_, issues_dock_);
|
||||
properties_dock_->raise();
|
||||
tabifyDockWidget(properties_panel_, layers_panel_);
|
||||
tabifyDockWidget(layers_panel_, stored_views_panel_);
|
||||
tabifyDockWidget(stored_views_panel_, search_panel_);
|
||||
tabifyDockWidget(search_panel_, spreadsheet_panel_);
|
||||
tabifyDockWidget(spreadsheet_panel_, audit_panel_);
|
||||
tabifyDockWidget(audit_panel_, clash_panel_);
|
||||
tabifyDockWidget(clash_panel_, issues_panel_);
|
||||
properties_panel_->raise();
|
||||
|
||||
layers_dock_->hide();
|
||||
stored_views_dock_->hide();
|
||||
search_dock_->hide();
|
||||
spreadsheet_dock_->hide();
|
||||
clash_dock_->hide();
|
||||
issues_dock_->hide();
|
||||
layers_panel_->hide();
|
||||
stored_views_panel_->hide();
|
||||
search_panel_->hide();
|
||||
spreadsheet_panel_->hide();
|
||||
audit_panel_->hide();
|
||||
clash_panel_->hide();
|
||||
issues_panel_->hide();
|
||||
|
||||
resizeDocks({models_dock_, properties_dock_}, {290, 330}, Qt::Horizontal);
|
||||
resizeDocks({models_dock_, spatial_dock_}, {280, 240}, Qt::Vertical);
|
||||
resizeDocks({models_panel_, properties_panel_}, {290, 330}, Qt::Horizontal);
|
||||
resizeDocks({models_panel_, spatial_panel_}, {280, 240}, Qt::Vertical);
|
||||
}
|
||||
|
||||
void MainWindow::setupStatus() {
|
||||
@@ -728,6 +454,7 @@ void MainWindow::setupStatus() {
|
||||
void MainWindow::setupLoader() {
|
||||
AppSettings::instance().setLoadDataSource(false);
|
||||
loader_ = new SceneLoader(viewport_, this);
|
||||
element_registry_->bindLoader(loader_);
|
||||
connect(loader_, &SceneLoader::loadStarted, this, &MainWindow::onLoadStarted);
|
||||
connect(loader_, &SceneLoader::loadedFromSidecar, this, &MainWindow::onLoadedFromSidecar);
|
||||
connect(loader_, &SceneLoader::loadedFromStream, this, &MainWindow::onLoadedFromStream);
|
||||
|
||||
+16
-14
@@ -31,6 +31,7 @@ class QTabBar;
|
||||
class QToolButton;
|
||||
class ViewportWindow;
|
||||
class SceneLoader;
|
||||
namespace ifcinterface { class ElementRegistry; }
|
||||
namespace ifcinterface::panels::models { class ModelsPanelView; }
|
||||
namespace ifcinterface::panels::spatial_hierarchy { class SpatialHierarchyPanelView; }
|
||||
namespace ifcinterface::panels::properties { class PropertiesPanelView; }
|
||||
@@ -46,7 +47,7 @@ private:
|
||||
void setupChrome();
|
||||
void setupRibbon();
|
||||
void setupViewport();
|
||||
void setupDocks();
|
||||
void setupPanels();
|
||||
void setupStatus();
|
||||
void setupLoader();
|
||||
QWidget* buildHomeRibbonPage();
|
||||
@@ -55,7 +56,6 @@ private:
|
||||
QWidget* buildPanelsRibbonPage();
|
||||
QToolButton* makeRibbonAction(const QString& text, const QString& icon_path);
|
||||
QWidget* makeRibbonGroup(const QString& title, const QList<QToolButton*>& buttons);
|
||||
QWidget* makeComingSoonPanel(const QString& title);
|
||||
QToolButton* makePanelToggle(const QString& text, QDockWidget* dock);
|
||||
void setStatusMessage(const QString& mode, const QString& detail);
|
||||
void addFiles(const QStringList& paths);
|
||||
@@ -78,19 +78,21 @@ private:
|
||||
QStackedWidget* ribbon_pages_ = nullptr;
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
SceneLoader* loader_ = nullptr;
|
||||
ifcinterface::ElementRegistry* element_registry_ = nullptr;
|
||||
QWidget* viewport_container_ = nullptr;
|
||||
QDockWidget* models_dock_ = nullptr;
|
||||
QDockWidget* spatial_dock_ = nullptr;
|
||||
QDockWidget* layers_dock_ = nullptr;
|
||||
QDockWidget* properties_dock_ = nullptr;
|
||||
QDockWidget* stored_views_dock_ = nullptr;
|
||||
QDockWidget* search_dock_ = nullptr;
|
||||
QDockWidget* spreadsheet_dock_ = nullptr;
|
||||
QDockWidget* clash_dock_ = nullptr;
|
||||
QDockWidget* issues_dock_ = nullptr;
|
||||
ifcinterface::panels::models::ModelsPanelView* models_panel_view_ = nullptr;
|
||||
ifcinterface::panels::spatial_hierarchy::SpatialHierarchyPanelView* spatial_panel_view_ = nullptr;
|
||||
ifcinterface::panels::properties::PropertiesPanelView* properties_panel_view_ = nullptr;
|
||||
QDockWidget* models_panel_ = nullptr;
|
||||
QDockWidget* spatial_panel_ = nullptr;
|
||||
QDockWidget* layers_panel_ = nullptr;
|
||||
QDockWidget* properties_panel_ = nullptr;
|
||||
QDockWidget* stored_views_panel_ = nullptr;
|
||||
QDockWidget* search_panel_ = nullptr;
|
||||
QDockWidget* spreadsheet_panel_ = nullptr;
|
||||
QDockWidget* audit_panel_ = nullptr;
|
||||
QDockWidget* clash_panel_ = nullptr;
|
||||
QDockWidget* issues_panel_ = nullptr;
|
||||
ifcinterface::panels::models::ModelsPanelView* models_view_ = nullptr;
|
||||
ifcinterface::panels::spatial_hierarchy::SpatialHierarchyPanelView* spatial_view_ = nullptr;
|
||||
ifcinterface::panels::properties::PropertiesPanelView* properties_view_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::shell
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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 "KeyValueTable.h"
|
||||
|
||||
#include "SvgIcon.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace ifcinterface::components {
|
||||
|
||||
KeyValueTable::KeyValueTable(const QList<KeyValueTableRow>& rows, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setObjectName("attributeList");
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(6);
|
||||
|
||||
for (const auto& row_data : rows) {
|
||||
auto* row = new QWidget(this);
|
||||
if (!row_data.trailing_icon_path.isEmpty()) {
|
||||
row->setObjectName("relationshipRow");
|
||||
} else {
|
||||
row->setObjectName("keyValueRow");
|
||||
}
|
||||
|
||||
auto* row_layout = new QHBoxLayout(row);
|
||||
row_layout->setContentsMargins(0, 0, 0, 0);
|
||||
row_layout->setSpacing(12);
|
||||
|
||||
auto* key = new QLabel(row_data.key, row);
|
||||
key->setObjectName("propertyKeyLabel");
|
||||
if (row_data.key_minimum_width > 0) {
|
||||
key->setMinimumWidth(row_data.key_minimum_width);
|
||||
}
|
||||
|
||||
auto* value = new QLabel(row_data.value, row);
|
||||
value->setObjectName(row_data.value_object_name.isEmpty()
|
||||
? "propertyValueLabel"
|
||||
: row_data.value_object_name);
|
||||
value->setWordWrap(true);
|
||||
value->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
|
||||
row_layout->addWidget(key);
|
||||
row_layout->addWidget(value, 1);
|
||||
|
||||
if (!row_data.trailing_icon_path.isEmpty()) {
|
||||
auto* icon = new QLabel(row);
|
||||
icon->setObjectName(row_data.trailing_icon_object_name.isEmpty()
|
||||
? "relationshipIconLabel"
|
||||
: row_data.trailing_icon_object_name);
|
||||
icon->setPixmap(icons::makePanelSvgPixmap(row_data.trailing_icon_path, QSize(14, 14)));
|
||||
icon->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
row_layout->addWidget(icon, 0, Qt::AlignRight | Qt::AlignVCenter);
|
||||
}
|
||||
|
||||
layout->addWidget(row);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::components
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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_COMPONENTS_KEYVALUETABLE_H
|
||||
#define IFCINTERFACE_COMPONENTS_KEYVALUETABLE_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
namespace ifcinterface::components {
|
||||
|
||||
struct KeyValueTableRow {
|
||||
QString key;
|
||||
QString value;
|
||||
QString value_object_name = "propertyValueLabel";
|
||||
QString trailing_icon_path;
|
||||
QString trailing_icon_object_name;
|
||||
int key_minimum_width = 0;
|
||||
};
|
||||
|
||||
class KeyValueTable : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit KeyValueTable(const QList<KeyValueTableRow>& rows, QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::components
|
||||
|
||||
#endif
|
||||
@@ -18,8 +18,9 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "PanelChrome.h"
|
||||
#include "Panel.h"
|
||||
|
||||
#include "Style.h"
|
||||
#include "SvgIcon.h"
|
||||
|
||||
#include <QDockWidget>
|
||||
@@ -30,7 +31,7 @@
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace ifcinterface::components::panel {
|
||||
namespace ifcinterface::components {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -69,32 +70,31 @@ public:
|
||||
|
||||
} // namespace
|
||||
|
||||
QDockWidget* makeDock(const QString& title, QWidget* content, QWidget* parent, bool has_settings) {
|
||||
auto* dock = new QDockWidget(title, parent);
|
||||
dock->setObjectName(title);
|
||||
dock->setFeatures(QDockWidget::DockWidgetMovable |
|
||||
QDockWidget::DockWidgetFloatable |
|
||||
QDockWidget::DockWidgetClosable);
|
||||
dock->setTitleBarWidget(new DockTitleBar(title, has_settings, dock));
|
||||
dock->setWidget(content);
|
||||
return dock;
|
||||
}
|
||||
|
||||
QFrame* wrapPanel(QWidget* inner) {
|
||||
Panel::Panel(const QString& title, QWidget* content, QWidget* parent, bool has_settings)
|
||||
: QDockWidget(title, parent)
|
||||
{
|
||||
auto* outer = new QFrame();
|
||||
auto* outer_layout = new QVBoxLayout(outer);
|
||||
outer_layout->setContentsMargins(6, 6, 6, 6);
|
||||
outer_layout->setContentsMargins(style::metrics::padding,
|
||||
style::metrics::padding,
|
||||
style::metrics::padding,
|
||||
style::metrics::padding);
|
||||
outer_layout->setSpacing(0);
|
||||
|
||||
auto* frame = new QFrame(outer);
|
||||
frame->setObjectName("panelFrame");
|
||||
auto* layout = new QVBoxLayout(frame);
|
||||
layout->setContentsMargins(0, 8, 0, 8);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(inner);
|
||||
|
||||
frame->setObjectName("panel");
|
||||
auto* frame_layout = new QVBoxLayout(frame);
|
||||
frame_layout->setContentsMargins(0, style::metrics::padding, 0, style::metrics::padding);
|
||||
frame_layout->setSpacing(0);
|
||||
frame_layout->addWidget(content);
|
||||
outer_layout->addWidget(frame);
|
||||
return outer;
|
||||
|
||||
setObjectName(title);
|
||||
setFeatures(QDockWidget::DockWidgetMovable |
|
||||
QDockWidget::DockWidgetFloatable |
|
||||
QDockWidget::DockWidgetClosable);
|
||||
setTitleBarWidget(new DockTitleBar(title, has_settings, this));
|
||||
setWidget(outer);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::components::panel
|
||||
} // namespace ifcinterface::components
|
||||
@@ -21,17 +21,19 @@
|
||||
#ifndef IFCINTERFACE_COMPONENTS_PANEL_PANELCHROME_H
|
||||
#define IFCINTERFACE_COMPONENTS_PANEL_PANELCHROME_H
|
||||
|
||||
#include <QString>
|
||||
#include <QDockWidget>
|
||||
|
||||
class QDockWidget;
|
||||
class QFrame;
|
||||
class QWidget;
|
||||
|
||||
namespace ifcinterface::components::panel {
|
||||
namespace ifcinterface::components {
|
||||
|
||||
QDockWidget* makeDock(const QString& title, QWidget* content, QWidget* parent, bool has_settings = false);
|
||||
QFrame* wrapPanel(QWidget* inner);
|
||||
class Panel : public QDockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
} // namespace ifcinterface::components::panel
|
||||
public:
|
||||
explicit Panel(const QString& title, QWidget* content, QWidget* parent = nullptr, bool has_settings = false);
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::components
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Section.h"
|
||||
|
||||
#include "Style.h"
|
||||
#include "SvgIcon.h"
|
||||
|
||||
#include <QFrame>
|
||||
@@ -49,14 +50,14 @@ Section::Section(const QString& title, SectionHeaderMode header_mode,
|
||||
setObjectName("panelSection");
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(6);
|
||||
layout->setSpacing(style::metrics::section_spacing);
|
||||
|
||||
if (header_mode == SectionHeaderMode::Visible) {
|
||||
auto* header = new QFrame(this);
|
||||
header->setObjectName("panelSectionHeader");
|
||||
auto* header_layout = new QHBoxLayout(header);
|
||||
header_layout->setContentsMargins(0, 0, 0, 0);
|
||||
header_layout->setSpacing(6);
|
||||
header_layout->setSpacing(style::metrics::section_spacing);
|
||||
|
||||
auto* toggle = new QToolButton(header);
|
||||
toggle->setObjectName("panelSectionHeaderButton");
|
||||
@@ -89,7 +90,8 @@ Section::Section(const QString& title, SectionHeaderMode header_mode,
|
||||
auto* filter_wrapper = new QWidget(this);
|
||||
filter_wrapper->setObjectName("panelSectionFilterWrapper");
|
||||
auto* filter_wrapper_layout = new QVBoxLayout(filter_wrapper);
|
||||
filter_wrapper_layout->setContentsMargins(10, 0, 10, 0);
|
||||
filter_wrapper_layout->setContentsMargins(style::metrics::filter_body_padding_x, 0,
|
||||
style::metrics::filter_body_padding_x, 0);
|
||||
filter_wrapper_layout->setSpacing(0);
|
||||
filter_wrapper_layout->addWidget(filter_field_);
|
||||
layout->addWidget(filter_wrapper);
|
||||
@@ -108,7 +110,8 @@ Section::Section(const QString& title, SectionHeaderMode header_mode,
|
||||
auto* filter_wrapper = new QWidget(this);
|
||||
filter_wrapper->setObjectName("panelSectionFilterWrapper");
|
||||
auto* filter_wrapper_layout = new QVBoxLayout(filter_wrapper);
|
||||
filter_wrapper_layout->setContentsMargins(8, 0, 8, 0);
|
||||
filter_wrapper_layout->setContentsMargins(style::metrics::hidden_filter_body_padding_x, 0,
|
||||
style::metrics::hidden_filter_body_padding_x, 0);
|
||||
filter_wrapper_layout->setSpacing(0);
|
||||
filter_wrapper_layout->addWidget(filter_field_);
|
||||
layout->addWidget(filter_wrapper);
|
||||
@@ -118,11 +121,14 @@ Section::Section(const QString& title, SectionHeaderMode header_mode,
|
||||
body_->setObjectName("panelSectionBody");
|
||||
body_layout_ = new QVBoxLayout(body_);
|
||||
if (header_mode == SectionHeaderMode::Visible) {
|
||||
body_layout_->setContentsMargins(10, 6, 10, 0);
|
||||
body_layout_->setContentsMargins(style::metrics::section_body_padding_x,
|
||||
style::metrics::section_body_padding_top,
|
||||
style::metrics::section_body_padding_x, 0);
|
||||
} else {
|
||||
body_layout_->setContentsMargins(8, 0, 8, 0);
|
||||
body_layout_->setContentsMargins(style::metrics::hidden_section_body_padding_x, 0,
|
||||
style::metrics::hidden_section_body_padding_x, 0);
|
||||
}
|
||||
body_layout_->setSpacing(6);
|
||||
body_layout_->setSpacing(style::metrics::section_spacing);
|
||||
layout->addWidget(body_);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
// 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 "Style.h"
|
||||
|
||||
namespace ifcinterface::components::style {
|
||||
|
||||
QString buildAppStyleSheet() {
|
||||
return QString(R"(
|
||||
QMainWindow {
|
||||
background: #26292f;
|
||||
}
|
||||
QWidget {
|
||||
color: #d0d5dd;
|
||||
background: #26292f;
|
||||
selection-background-color: #39b54a;
|
||||
selection-color: #14161a;
|
||||
}
|
||||
QFrame#ribbonShell {
|
||||
background: #2d3138;
|
||||
border-bottom: 1px solid #1b1d22;
|
||||
}
|
||||
QTabBar::tab {
|
||||
background: transparent;
|
||||
color: #8d97a7;
|
||||
padding: 8px 14px;
|
||||
margin-right: 2px;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
QTabBar::tab:selected {
|
||||
color: #f2f5fa;
|
||||
border-bottom: 2px solid #39b54a;
|
||||
}
|
||||
QTabBar::tab:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
QFrame#ribbonBand {
|
||||
background: #31353d;
|
||||
border-top: 1px solid #3b4048;
|
||||
}
|
||||
QFrame#ribbonPage {
|
||||
background: transparent;
|
||||
}
|
||||
QFrame#ribbonGroup {
|
||||
background: transparent;
|
||||
border-right: 1px solid #434852;
|
||||
}
|
||||
QLabel#ribbonGroupLabel {
|
||||
color: #7f8796;
|
||||
font-size: 9px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
QToolButton#ribbonButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 6px 4px 4px 4px;
|
||||
font-size: 11px;
|
||||
color: #d6dce6;
|
||||
}
|
||||
QToolButton#ribbonButton:hover {
|
||||
background: #3a3f48;
|
||||
}
|
||||
QToolButton#ribbonButton:pressed {
|
||||
background: #24282f;
|
||||
}
|
||||
QFrame#viewportShell {
|
||||
background: #202329;
|
||||
border-top: 1px solid #1d2025;
|
||||
}
|
||||
QFrame#viewportFrame {
|
||||
background: #1a1d22;
|
||||
border: 1px solid #333942;
|
||||
}
|
||||
QDockWidget {
|
||||
color: #d0d5dd;
|
||||
}
|
||||
QLabel#dockTitleText {
|
||||
color: #dfe4ec;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
QToolButton#dockTitleButton {
|
||||
color: #8e97a5;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
QToolButton#dockTitleButton:hover {
|
||||
color: #ffffff;
|
||||
background: #353a42;
|
||||
}
|
||||
QFrame#panel {
|
||||
background: #2b2f36;
|
||||
border: 1px solid #3e444e;
|
||||
border-radius: %1px;
|
||||
}
|
||||
QTreeWidget, QListWidget, QTableWidget, QAbstractScrollArea {
|
||||
background: #2b2f36;
|
||||
border: none;
|
||||
outline: none;
|
||||
gridline-color: #333842;
|
||||
}
|
||||
QTreeWidget::viewport, QListWidget::viewport, QTableWidget::viewport {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QHeaderView::section {
|
||||
background: #31353d;
|
||||
color: #b5becc;
|
||||
border: none;
|
||||
border-bottom: 1px solid #434a55;
|
||||
padding: 7px 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
QTableCornerButton::section {
|
||||
background: #31353d;
|
||||
border: none;
|
||||
}
|
||||
QScrollArea {
|
||||
background: #2b2f36;
|
||||
border: none;
|
||||
}
|
||||
QScrollArea > QWidget > QWidget {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QLineEdit {
|
||||
background: #31353d;
|
||||
border: 1px solid #434a55;
|
||||
border-radius: %1px;
|
||||
padding: %2px %3px;
|
||||
color: #d9dfeb;
|
||||
}
|
||||
QLineEdit:focus {
|
||||
border: 1px solid #5b6472;
|
||||
}
|
||||
QFrame#entityClassCard {
|
||||
background: #26292f;
|
||||
border: 1px solid #404650;
|
||||
border-radius: %1px;
|
||||
}
|
||||
QLabel#entityClassLabel {
|
||||
color: #eef2f8;
|
||||
font-weight: 700;
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#entityTypeLabel {
|
||||
color: #9aa4b3;
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#attributeList {
|
||||
background: transparent;
|
||||
}
|
||||
QTreeView::item, QListView::item, QTableView::item {
|
||||
padding: 4px;
|
||||
}
|
||||
QScrollBar:vertical {
|
||||
background: transparent;
|
||||
width: 10px;
|
||||
margin: 2px 2px 2px 0;
|
||||
}
|
||||
QScrollBar:horizontal {
|
||||
background: transparent;
|
||||
height: 10px;
|
||||
margin: 0 2px 2px 2px;
|
||||
}
|
||||
QScrollBar::handle:vertical, QScrollBar::handle:horizontal {
|
||||
background: #525a67;
|
||||
border-radius: %1px;
|
||||
min-height: 24px;
|
||||
min-width: 24px;
|
||||
}
|
||||
QScrollBar::handle:vertical:hover, QScrollBar::handle:horizontal:hover {
|
||||
background: #697385;
|
||||
}
|
||||
QScrollBar::add-line, QScrollBar::sub-line,
|
||||
QScrollBar::add-page, QScrollBar::sub-page {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
QStatusBar {
|
||||
background: #24272c;
|
||||
border-top: 1px solid #1a1c20;
|
||||
}
|
||||
QStatusBar QLabel {
|
||||
color: #97a1af;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
QGroupBox {
|
||||
background: transparent;
|
||||
border: 1px solid #404650;
|
||||
border-radius: %1px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox#propertySetCard {
|
||||
background: #26292f;
|
||||
border: 1px solid #404650;
|
||||
border-radius: %1px;
|
||||
}
|
||||
QGroupBox#propertySetCard::title {
|
||||
subcontrol-origin: margin;
|
||||
left: %4px;
|
||||
padding: 0 4px;
|
||||
color: #d5dbe5;
|
||||
}
|
||||
QGroupBox#propertySetCard > QWidget {
|
||||
background: #26292f;
|
||||
}
|
||||
QWidget#panelSection {
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#panelSectionFilterWrapper {
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#relationshipRow {
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#relationshipIconLabel {
|
||||
background: transparent;
|
||||
}
|
||||
QWidget#inspectorPanel {
|
||||
background: #2b2f36;
|
||||
}
|
||||
QFrame#panelSectionHeader {
|
||||
background: #26292f;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #e1e7f0;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
padding: %5px;
|
||||
margin: 0;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
QToolButton#panelSectionHeaderButton::menu-indicator {
|
||||
image: none;
|
||||
width: 0;
|
||||
}
|
||||
QToolButton#panelSectionFilterToggle {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: %5px;
|
||||
}
|
||||
QToolButton#panelSectionFilterToggle:hover {
|
||||
background: #353a42;
|
||||
}
|
||||
QWidget#panelSectionBody {
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#propertyKeyLabel {
|
||||
color: #9aa4b3;
|
||||
background: transparent;
|
||||
}
|
||||
QLabel#propertyValueLabel {
|
||||
color: #dce2eb;
|
||||
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::control_padding_y)
|
||||
.arg(metrics::control_padding_x)
|
||||
.arg(metrics::card_padding)
|
||||
.arg(metrics::section_header_padding);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::components::style
|
||||
@@ -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_COMPONENTS_STYLE_H
|
||||
#define IFCINTERFACE_COMPONENTS_STYLE_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace ifcinterface::components::style::metrics {
|
||||
|
||||
inline constexpr int padding = 6;
|
||||
inline constexpr int section_spacing = 6;
|
||||
inline constexpr int section_body_padding_x = 10;
|
||||
inline constexpr int section_body_padding_top = 6;
|
||||
inline constexpr int hidden_section_body_padding_x = 8;
|
||||
inline constexpr int section_header_padding = 2;
|
||||
inline constexpr int filter_body_padding_x = 10;
|
||||
inline constexpr int hidden_filter_body_padding_x = 8;
|
||||
inline constexpr int card_padding = 10;
|
||||
inline constexpr int control_padding_y = 6;
|
||||
inline constexpr int control_padding_x = 8;
|
||||
inline constexpr int panel_radius = 3;
|
||||
|
||||
} // namespace ifcinterface::components::style::metrics
|
||||
|
||||
namespace ifcinterface::components::style {
|
||||
|
||||
QString buildAppStyleSheet();
|
||||
|
||||
} // namespace ifcinterface::components::style
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="24" stroke-width="1.5" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 21L5 21C3.89543 21 3 20.1046 3 19L3 5C3 3.89543 3.89543 3 5 3L19 3C20.1046 3 21 3.89543 21 5L21 19C21 20.1046 20.1046 21 19 21Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.5 21V3" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.5 10L7.25 12L5.5 14" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 533 B |
@@ -4,21 +4,6 @@
|
||||
<file alias="DMSans-VariableFont_opsz,wght.ttf">../ifctester/webapp/public/fonts/dmsans/DMSans-VariableFont_opsz,wght.ttf</file>
|
||||
</qresource>
|
||||
<qresource prefix="/icons">
|
||||
<file alias="IFC.png">../bonsai/bonsai/bim/data/icons/IFC.png</file>
|
||||
<file alias="dm_add.png">../bonsai/bonsai/bim/data/icons/dm_add.png</file>
|
||||
<file alias="dm_add_type.png">../bonsai/bonsai/bim/data/icons/dm_add_type.png</file>
|
||||
<file alias="dm_assign.png">../bonsai/bonsai/bim/data/icons/dm_assign.png</file>
|
||||
<file alias="dm_centerline.png">../bonsai/bonsai/bim/data/icons/dm_centerline.png</file>
|
||||
<file alias="dm_connect_mep_elements.png">../bonsai/bonsai/bim/data/icons/dm_connect_mep_elements.png</file>
|
||||
<file alias="dm_decomposition.png">../bonsai/bonsai/bim/data/icons/dm_decomposition.png</file>
|
||||
<file alias="dm_edit_profile.png">../bonsai/bonsai/bim/data/icons/dm_edit_profile.png</file>
|
||||
<file alias="dm_ifc.png">../bonsai/bonsai/bim/data/icons/dm_ifc.png</file>
|
||||
<file alias="dm_perform_quantity_take-off.png">../bonsai/bonsai/bim/data/icons/dm_perform_quantity_take-off.png</file>
|
||||
<file alias="dm_rectangle.png">../bonsai/bonsai/bim/data/icons/dm_rectangle.png</file>
|
||||
<file alias="dm_refresh.png">../bonsai/bonsai/bim/data/icons/dm_refresh.png</file>
|
||||
<file alias="dm_rotate_90.png">../bonsai/bonsai/bim/data/icons/dm_rotate_90.png</file>
|
||||
<file alias="dm_split.png">../bonsai/bonsai/bim/data/icons/dm_split.png</file>
|
||||
<file alias="dm_toggle_openings.png">../bonsai/bonsai/bim/data/icons/dm_toggle_openings.png</file>
|
||||
<file alias="plus-square.svg">icons/plus-square.svg</file>
|
||||
<file alias="download-square.svg">icons/download-square.svg</file>
|
||||
<file alias="cloud-square.svg">icons/cloud-square.svg</file>
|
||||
@@ -55,5 +40,6 @@
|
||||
<file alias="filter.svg">icons/filter.svg</file>
|
||||
<file alias="cube-dots.svg">icons/cube-dots.svg</file>
|
||||
<file alias="cursor-pointer.svg">icons/cursor-pointer.svg</file>
|
||||
<file alias="sidebar-expand.svg">icons/sidebar-expand.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -22,22 +22,36 @@
|
||||
|
||||
#include "PropertiesPanelWidget.h"
|
||||
|
||||
#include "../../ElementRegistry.h"
|
||||
#include "../../../ifcviewer/ViewportWindow.h"
|
||||
|
||||
namespace ifcinterface::panels::properties {
|
||||
|
||||
PropertiesPanelView::PropertiesPanelView(PropertiesPanelWidget* widget, QObject* parent)
|
||||
: QObject(parent), widget_(widget)
|
||||
PropertiesPanelView::PropertiesPanelView(PropertiesPanelWidget* widget,
|
||||
ViewportWindow* viewport,
|
||||
ifcinterface::ElementRegistry* registry,
|
||||
QObject* parent)
|
||||
: QObject(parent), widget_(widget), registry_(registry)
|
||||
{
|
||||
state_.entity = {"IfcWall", "SOLIDWALL"};
|
||||
state_.attributes = {
|
||||
connect(viewport, &ViewportWindow::objectPicked, this, [this](uint32_t object_id) {
|
||||
refresh(object_id);
|
||||
});
|
||||
refresh(0);
|
||||
}
|
||||
|
||||
void PropertiesPanelView::refresh(uint32_t object_id) {
|
||||
PropertiesPanelState state;
|
||||
state.entity = {"IfcWall", "SOLIDWALL"};
|
||||
state.attributes = {
|
||||
{"GlobalId", "2Q$n5SLPP9Q8B7wQKjKfUQ"},
|
||||
{"Name", "Core-EXT-204"},
|
||||
{"Description", "External load-bearing wall"},
|
||||
};
|
||||
state_.relationships = {
|
||||
state.relationships = {
|
||||
{"Type", "Basic Wall: Exterior - 200mm"},
|
||||
{"Container", "Level 02"},
|
||||
};
|
||||
state_.property_sets = {
|
||||
state.property_sets = {
|
||||
{"Pset_WallCommon",
|
||||
{{"Reference", "Core-EXT-204"},
|
||||
{"Status", "Reviewed"},
|
||||
@@ -53,7 +67,7 @@ PropertiesPanelView::PropertiesPanelView(PropertiesPanelWidget* widget, QObject*
|
||||
{"Last Review", "2026-04-30"},
|
||||
{"Assigned To", "Design Coordination"}}},
|
||||
};
|
||||
state_.quantity_sets = {
|
||||
state.quantity_sets = {
|
||||
{"BaseQuantities",
|
||||
{{"Length", "6.20 m"},
|
||||
{"Height", "3.45 m"},
|
||||
@@ -65,7 +79,25 @@ PropertiesPanelView::PropertiesPanelView(PropertiesPanelWidget* widget, QObject*
|
||||
{"Paint Coverage", "42.78 m2"}}},
|
||||
};
|
||||
|
||||
widget_->setState(state_);
|
||||
if (registry_) {
|
||||
auto info = registry_->find(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);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::panels::properties
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace ifcinterface { class ElementRegistry; }
|
||||
class ViewportWindow;
|
||||
namespace ifcinterface::panels::properties {
|
||||
|
||||
class PropertiesPanelWidget;
|
||||
@@ -32,11 +34,16 @@ class PropertiesPanelWidget;
|
||||
class PropertiesPanelView : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PropertiesPanelView(PropertiesPanelWidget* widget, QObject* parent = nullptr);
|
||||
explicit PropertiesPanelView(PropertiesPanelWidget* widget,
|
||||
ViewportWindow* viewport,
|
||||
ifcinterface::ElementRegistry* registry,
|
||||
QObject* parent = nullptr);
|
||||
|
||||
private:
|
||||
void refresh(uint32_t object_id);
|
||||
|
||||
PropertiesPanelWidget* widget_ = nullptr;
|
||||
PropertiesPanelState state_;
|
||||
ifcinterface::ElementRegistry* registry_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::panels::properties
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
|
||||
#include "PropertiesPanelWidget.h"
|
||||
|
||||
#include "../../components/KeyValueTable.h"
|
||||
#include "../../components/Section.h"
|
||||
#include "../../components/SvgIcon.h"
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QFrame>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
@@ -36,79 +36,37 @@ namespace {
|
||||
QWidget* makePropertySetPanel(const ifcinterface::panels::properties::PropertySet& property_set, QWidget* parent = nullptr) {
|
||||
auto* group = new QGroupBox(property_set.title, parent);
|
||||
group->setObjectName("propertySetCard");
|
||||
auto* form = new QFormLayout(group);
|
||||
form->setContentsMargins(10, 10, 10, 10);
|
||||
form->setHorizontalSpacing(16);
|
||||
form->setVerticalSpacing(6);
|
||||
form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
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) {
|
||||
auto* key = new QLabel(row.key, group);
|
||||
key->setObjectName("propertyKeyLabel");
|
||||
auto* value = new QLabel(row.value, group);
|
||||
value->setObjectName("propertyValueLabel");
|
||||
value->setWordWrap(true);
|
||||
form->addRow(key, value);
|
||||
rows.append({row.key, row.value, "propertyValueLabel", "", "", 0});
|
||||
}
|
||||
|
||||
layout->addWidget(new ifcinterface::components::KeyValueTable(rows, group));
|
||||
return group;
|
||||
}
|
||||
|
||||
QWidget* makeAttributeList(const QList<ifcinterface::panels::properties::KeyValueRow>& rows, QWidget* parent = nullptr) {
|
||||
auto* panel = new QWidget(parent);
|
||||
panel->setObjectName("attributeList");
|
||||
auto* form = new QFormLayout(panel);
|
||||
form->setContentsMargins(0, 0, 0, 0);
|
||||
form->setHorizontalSpacing(16);
|
||||
form->setVerticalSpacing(6);
|
||||
form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
|
||||
QList<ifcinterface::components::KeyValueTableRow> table_rows;
|
||||
for (const auto& row : rows) {
|
||||
auto* key = new QLabel(row.key, panel);
|
||||
key->setObjectName("propertyKeyLabel");
|
||||
auto* value = new QLabel(row.value, panel);
|
||||
value->setObjectName("propertyValueLabel");
|
||||
value->setWordWrap(true);
|
||||
form->addRow(key, value);
|
||||
table_rows.append({row.key, row.value, "propertyValueLabel", "", "", 0});
|
||||
}
|
||||
|
||||
return panel;
|
||||
return new ifcinterface::components::KeyValueTable(table_rows, parent);
|
||||
}
|
||||
|
||||
QWidget* makeRelationshipList(const QList<ifcinterface::panels::properties::RelationshipRow>& rows, QWidget* parent = nullptr) {
|
||||
auto* panel = new QWidget(parent);
|
||||
panel->setObjectName("attributeList");
|
||||
auto* layout = new QVBoxLayout(panel);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(6);
|
||||
|
||||
QList<ifcinterface::components::KeyValueTableRow> table_rows;
|
||||
for (const auto& row_data : rows) {
|
||||
auto* row = new QWidget(panel);
|
||||
row->setObjectName("relationshipRow");
|
||||
auto* row_layout = new QHBoxLayout(row);
|
||||
row_layout->setContentsMargins(0, 0, 0, 0);
|
||||
row_layout->setSpacing(12);
|
||||
|
||||
auto* key = new QLabel(row_data.key, row);
|
||||
key->setObjectName("propertyKeyLabel");
|
||||
key->setMinimumWidth(72);
|
||||
|
||||
auto* target = new QLabel(row_data.value, row);
|
||||
target->setObjectName("relationshipValueLabel");
|
||||
target->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
|
||||
auto* icon = new QLabel(row);
|
||||
icon->setObjectName("relationshipIconLabel");
|
||||
icon->setPixmap(ifcinterface::components::icons::makePanelSvgPixmap(":/icons/cursor-pointer.svg", QSize(14, 14)));
|
||||
icon->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
row_layout->addWidget(key);
|
||||
row_layout->addWidget(target, 1);
|
||||
row_layout->addWidget(icon, 0, Qt::AlignRight | Qt::AlignVCenter);
|
||||
layout->addWidget(row);
|
||||
table_rows.append({row_data.key,
|
||||
row_data.value,
|
||||
"relationshipValueLabel",
|
||||
":/icons/cursor-pointer.svg",
|
||||
"relationshipIconLabel",
|
||||
72});
|
||||
}
|
||||
|
||||
return panel;
|
||||
return new ifcinterface::components::KeyValueTable(table_rows, parent);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -121,22 +79,28 @@ PropertiesPanelWidget::PropertiesPanelWidget(QWidget* parent)
|
||||
auto* root = 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_->setSpacing(12);
|
||||
|
||||
scroll_->setWidget(content_);
|
||||
root->addWidget(scroll_);
|
||||
}
|
||||
|
||||
void PropertiesPanelWidget::setState(const PropertiesPanelState& state) {
|
||||
auto* root = qobject_cast<QVBoxLayout*>(layout());
|
||||
while (auto* item = root->takeAt(0)) {
|
||||
void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
|
||||
while (auto* item = content_layout_->takeAt(0)) {
|
||||
if (auto* widget = item->widget()) widget->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
|
||||
auto* content = new QWidget(this);
|
||||
content->setObjectName("inspectorPanel");
|
||||
auto* content_layout = new QVBoxLayout(content);
|
||||
content_layout->setContentsMargins(0, 0, 0, 0);
|
||||
content_layout->setSpacing(12);
|
||||
|
||||
auto* entity_card = new QFrame(content);
|
||||
auto* entity_card = new QFrame(content_);
|
||||
entity_card->setObjectName("entityClassCard");
|
||||
auto* entity_layout = new QHBoxLayout(entity_card);
|
||||
entity_layout->setContentsMargins(10, 8, 10, 8);
|
||||
@@ -159,37 +123,31 @@ void PropertiesPanelWidget::setState(const PropertiesPanelState& state) {
|
||||
|
||||
QList<QWidget*> property_set_widgets;
|
||||
for (const auto& property_set : state.property_sets) {
|
||||
property_set_widgets.append(makePropertySetPanel(property_set, content));
|
||||
property_set_widgets.append(makePropertySetPanel(property_set, content_));
|
||||
}
|
||||
|
||||
QList<QWidget*> quantity_set_widgets;
|
||||
for (const auto& property_set : state.quantity_sets) {
|
||||
quantity_set_widgets.append(makePropertySetPanel(property_set, content));
|
||||
quantity_set_widgets.append(makePropertySetPanel(property_set, content_));
|
||||
}
|
||||
|
||||
auto* entity_section = new components::Section("", components::SectionHeaderMode::Hidden, "", content);
|
||||
auto* entity_section = new components::Section("", components::SectionHeaderMode::Hidden, "", content_);
|
||||
entity_section->addBodyWidget(entity_card);
|
||||
auto* attributes_section = new components::Section("Attributes", components::SectionHeaderMode::Visible, "", content);
|
||||
attributes_section->addBodyWidget(makeAttributeList(state.attributes, content));
|
||||
auto* relationships_section = new components::Section("Relationships", components::SectionHeaderMode::Visible, "", content);
|
||||
relationships_section->addBodyWidget(makeRelationshipList(state.relationships, content));
|
||||
auto* properties_section = new components::Section("Properties", components::SectionHeaderMode::Visible, "Filter properties or sets", content);
|
||||
auto* attributes_section = new components::Section("Attributes", components::SectionHeaderMode::Visible, "", content_);
|
||||
attributes_section->addBodyWidget(makeAttributeList(state.attributes, content_));
|
||||
auto* relationships_section = new components::Section("Relationships", components::SectionHeaderMode::Visible, "", content_);
|
||||
relationships_section->addBodyWidget(makeRelationshipList(state.relationships, content_));
|
||||
auto* properties_section = new components::Section("Properties", components::SectionHeaderMode::Visible, "Filter properties or sets", content_);
|
||||
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", content_);
|
||||
for (auto* widget : quantity_set_widgets) quantities_section->addBodyWidget(widget);
|
||||
|
||||
content_layout->addWidget(entity_section);
|
||||
content_layout->addWidget(attributes_section);
|
||||
content_layout->addWidget(relationships_section);
|
||||
content_layout->addWidget(properties_section);
|
||||
content_layout->addWidget(quantities_section);
|
||||
content_layout->addStretch(1);
|
||||
|
||||
auto* scroll = new QScrollArea(this);
|
||||
scroll->setWidgetResizable(true);
|
||||
scroll->setFrameShape(QFrame::NoFrame);
|
||||
scroll->setWidget(content);
|
||||
root->addWidget(scroll);
|
||||
content_layout_->addWidget(entity_section);
|
||||
content_layout_->addWidget(attributes_section);
|
||||
content_layout_->addWidget(relationships_section);
|
||||
content_layout_->addWidget(properties_section);
|
||||
content_layout_->addWidget(quantities_section);
|
||||
content_layout_->addStretch(1);
|
||||
}
|
||||
|
||||
} // namespace ifcinterface::panels::properties
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QScrollArea;
|
||||
class QVBoxLayout;
|
||||
|
||||
namespace ifcinterface::panels::properties {
|
||||
|
||||
class PropertiesPanelWidget : public QWidget {
|
||||
@@ -32,7 +35,12 @@ class PropertiesPanelWidget : public QWidget {
|
||||
public:
|
||||
explicit PropertiesPanelWidget(QWidget* parent = nullptr);
|
||||
|
||||
void setState(const PropertiesPanelState& state);
|
||||
void render(const PropertiesPanelState& state);
|
||||
|
||||
private:
|
||||
QScrollArea* scroll_ = nullptr;
|
||||
QWidget* content_ = nullptr;
|
||||
QVBoxLayout* content_layout_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace ifcinterface::panels::properties
|
||||
|
||||
Reference in New Issue
Block a user