mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-28 03:05:33 +00:00
Interface mockup 9
This commit is contained in:
@@ -39,6 +39,10 @@ void ElementRegistry::bindLoader(SceneLoader* loader) {
|
|||||||
this, &ElementRegistry::onStreamedElementsReady);
|
this, &ElementRegistry::onStreamedElementsReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ElementRegistry::clear() {
|
||||||
|
elements_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<BasicElementInfo> ElementRegistry::findBasicElementInfo(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;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public:
|
|||||||
explicit ElementRegistry(QObject* parent = nullptr);
|
explicit ElementRegistry(QObject* parent = nullptr);
|
||||||
|
|
||||||
void bindLoader(SceneLoader* loader);
|
void bindLoader(SceneLoader* loader);
|
||||||
|
void clear();
|
||||||
std::optional<BasicElementInfo> findBasicElementInfo(uint32_t object_id) const;
|
std::optional<BasicElementInfo> findBasicElementInfo(uint32_t object_id) const;
|
||||||
std::optional<express::Base> findEntity(uint32_t object_id) const;
|
std::optional<express::Base> findEntity(uint32_t object_id) const;
|
||||||
|
|
||||||
|
|||||||
+247
-54
@@ -21,12 +21,15 @@
|
|||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#include "../ifcviewer/AppSettings.h"
|
#include "../ifcviewer/AppSettings.h"
|
||||||
|
#include "../ifcviewer/Federation.h"
|
||||||
#include "../ifcviewer/SceneLoader.h"
|
#include "../ifcviewer/SceneLoader.h"
|
||||||
#include "../ifcviewer/ViewportWindow.h"
|
#include "../ifcviewer/ViewportWindow.h"
|
||||||
#include "ElementRegistry.h"
|
#include "ElementRegistry.h"
|
||||||
|
#include "components/Buttons.h"
|
||||||
#include "components/Panel.h"
|
#include "components/Panel.h"
|
||||||
#include "components/Style.h"
|
#include "components/Style.h"
|
||||||
#include "components/SvgIcon.h"
|
#include "components/Tabs.h"
|
||||||
|
#include "panels/add_model/Dialog.h"
|
||||||
#include "panels/todo/Widget.h"
|
#include "panels/todo/Widget.h"
|
||||||
#include "panels/models/View.h"
|
#include "panels/models/View.h"
|
||||||
#include "panels/models/Widget.h"
|
#include "panels/models/Widget.h"
|
||||||
@@ -38,15 +41,17 @@
|
|||||||
|
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QListView>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
#include <QTabBar>
|
#include <QTreeView>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
@@ -55,7 +60,12 @@ namespace ifcinterface::shell {
|
|||||||
MainWindow::MainWindow(QWidget* parent)
|
MainWindow::MainWindow(QWidget* parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
{
|
{
|
||||||
|
federation_ = new Federation(this);
|
||||||
element_registry_ = new ifcinterface::ElementRegistry(this);
|
element_registry_ = new ifcinterface::ElementRegistry(this);
|
||||||
|
connect(federation_, &Federation::dirtyChanged, this, [this](bool dirty) {
|
||||||
|
setWindowModified(dirty);
|
||||||
|
updateWindowTitle();
|
||||||
|
});
|
||||||
setupChrome();
|
setupChrome();
|
||||||
setupViewport();
|
setupViewport();
|
||||||
setupPanels();
|
setupPanels();
|
||||||
@@ -67,46 +77,18 @@ MainWindow::MainWindow(QWidget* parent)
|
|||||||
|
|
||||||
void MainWindow::setupChrome() {
|
void MainWindow::setupChrome() {
|
||||||
setObjectName("appWindow");
|
setObjectName("appWindow");
|
||||||
setWindowTitle("IfcOpenShell Interface");
|
|
||||||
setDockOptions(QMainWindow::AllowNestedDocks |
|
setDockOptions(QMainWindow::AllowNestedDocks |
|
||||||
QMainWindow::AllowTabbedDocks |
|
QMainWindow::AllowTabbedDocks |
|
||||||
QMainWindow::GroupedDragging);
|
QMainWindow::GroupedDragging);
|
||||||
setStyleSheet(components::style::buildAppStyleSheet());
|
updateWindowTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton* MainWindow::makeRibbonAction(const QString& text, const QString& icon_path) {
|
QToolButton* MainWindow::makeRibbonAction(const QString& text, const QString& icon_path) {
|
||||||
auto* button = new QToolButton(this);
|
return components::buttons::makeButton(text, icon_path, this, QSize(90, 54));
|
||||||
button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
|
||||||
button->setIcon(icon_path.endsWith(".svg")
|
|
||||||
? components::icons::makeTintedSvgIcon(icon_path)
|
|
||||||
: QIcon(icon_path));
|
|
||||||
button->setIconSize(QSize(20, 20));
|
|
||||||
button->setText(text);
|
|
||||||
button->setMinimumSize(QSize(68, 54));
|
|
||||||
button->setObjectName("ribbonButton");
|
|
||||||
button->setAutoRaise(false);
|
|
||||||
return button;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* MainWindow::makeRibbonGroup(const QString& title, const QList<QToolButton*>& buttons) {
|
QWidget* MainWindow::makeRibbonGroup(const QString& title, const QList<QToolButton*>& buttons) {
|
||||||
auto* group = new QFrame(this);
|
return components::buttons::makeButtonGroup(title, buttons, this);
|
||||||
group->setObjectName("ribbonGroup");
|
|
||||||
auto* group_layout = new QVBoxLayout(group);
|
|
||||||
group_layout->setContentsMargins(8, 6, 8, 4);
|
|
||||||
group_layout->setSpacing(4);
|
|
||||||
auto* button_row = new QHBoxLayout();
|
|
||||||
button_row->setContentsMargins(0, 0, 0, 0);
|
|
||||||
button_row->setSpacing(4);
|
|
||||||
for (auto* button : buttons) {
|
|
||||||
button_row->addWidget(button);
|
|
||||||
}
|
|
||||||
auto* label = new QLabel(title, group);
|
|
||||||
label->setObjectName("ribbonGroupLabel");
|
|
||||||
label->setProperty("textRole", "secondary");
|
|
||||||
label->setAlignment(Qt::AlignCenter);
|
|
||||||
group_layout->addLayout(button_row);
|
|
||||||
group_layout->addWidget(label);
|
|
||||||
return group;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setStatusMessage(const QString& mode, const QString& detail) {
|
void MainWindow::setStatusMessage(const QString& mode, const QString& detail) {
|
||||||
@@ -137,13 +119,9 @@ QWidget* MainWindow::buildHomeRibbonPage() {
|
|||||||
row->setSpacing(0);
|
row->setSpacing(0);
|
||||||
|
|
||||||
auto* new_project = makeRibbonAction("New Project", ":/icons/plus-square.svg");
|
auto* new_project = makeRibbonAction("New Project", ":/icons/plus-square.svg");
|
||||||
connect(new_project, &QToolButton::clicked, this, [this]() {
|
connect(new_project, &QToolButton::clicked, this, &MainWindow::onNewProject);
|
||||||
setStatusMessage("Project", "New Project coming soon");
|
|
||||||
});
|
|
||||||
auto* open_project = makeRibbonAction("Open Project", ":/icons/download-square.svg");
|
auto* open_project = makeRibbonAction("Open Project", ":/icons/download-square.svg");
|
||||||
connect(open_project, &QToolButton::clicked, this, [this]() {
|
connect(open_project, &QToolButton::clicked, this, &MainWindow::onOpenProject);
|
||||||
setStatusMessage("Project", "Open Project coming soon");
|
|
||||||
});
|
|
||||||
auto* open_cloud = makeRibbonAction("Open Cloud", ":/icons/cloud-square.svg");
|
auto* open_cloud = makeRibbonAction("Open Cloud", ":/icons/cloud-square.svg");
|
||||||
connect(open_cloud, &QToolButton::clicked, this, [this]() {
|
connect(open_cloud, &QToolButton::clicked, this, [this]() {
|
||||||
setStatusMessage("Project", "Open Cloud Project coming soon");
|
setStatusMessage("Project", "Open Cloud Project coming soon");
|
||||||
@@ -153,13 +131,9 @@ QWidget* MainWindow::buildHomeRibbonPage() {
|
|||||||
setStatusMessage("Project", "Open Recent coming soon");
|
setStatusMessage("Project", "Open Recent coming soon");
|
||||||
});
|
});
|
||||||
auto* save_project = makeRibbonAction("Save Project", ":/icons/floppy-disk.svg");
|
auto* save_project = makeRibbonAction("Save Project", ":/icons/floppy-disk.svg");
|
||||||
connect(save_project, &QToolButton::clicked, this, [this]() {
|
connect(save_project, &QToolButton::clicked, this, &MainWindow::onSaveProject);
|
||||||
setStatusMessage("Project", "Save Project coming soon");
|
|
||||||
});
|
|
||||||
auto* save_project_as = makeRibbonAction("Save As", ":/icons/floppy-disk-arrow-in.svg");
|
auto* save_project_as = makeRibbonAction("Save As", ":/icons/floppy-disk-arrow-in.svg");
|
||||||
connect(save_project_as, &QToolButton::clicked, this, [this]() {
|
connect(save_project_as, &QToolButton::clicked, this, &MainWindow::onSaveProjectAs);
|
||||||
setStatusMessage("Project", "Save Project As coming soon");
|
|
||||||
});
|
|
||||||
|
|
||||||
auto* add_model = makeRibbonAction("Add Model", ":/icons/cube.svg");
|
auto* add_model = makeRibbonAction("Add Model", ":/icons/cube.svg");
|
||||||
connect(add_model, &QToolButton::clicked, this, &MainWindow::onAddFiles);
|
connect(add_model, &QToolButton::clicked, this, &MainWindow::onAddFiles);
|
||||||
@@ -322,14 +296,12 @@ void MainWindow::setupRibbon() {
|
|||||||
shell_layout->setContentsMargins(0, 0, 0, 0);
|
shell_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
shell_layout->setSpacing(0);
|
shell_layout->setSpacing(0);
|
||||||
|
|
||||||
ribbon_tabs_ = new QTabBar(shell);
|
ribbon_tabs_ = new components::TabBar(shell);
|
||||||
ribbon_tabs_->addTab("Home");
|
ribbon_tabs_->addTab("Home");
|
||||||
ribbon_tabs_->addTab("Navigate");
|
ribbon_tabs_->addTab("Navigate");
|
||||||
ribbon_tabs_->addTab("Inspect");
|
ribbon_tabs_->addTab("Inspect");
|
||||||
ribbon_tabs_->addTab("Panels");
|
ribbon_tabs_->addTab("Panels");
|
||||||
ribbon_tabs_->setCurrentIndex(0);
|
ribbon_tabs_->setCurrentIndex(0);
|
||||||
ribbon_tabs_->setExpanding(false);
|
|
||||||
ribbon_tabs_->setDrawBase(false);
|
|
||||||
|
|
||||||
auto* ribbon_band = new QFrame(shell);
|
auto* ribbon_band = new QFrame(shell);
|
||||||
ribbon_band->setObjectName("ribbonBand");
|
ribbon_band->setObjectName("ribbonBand");
|
||||||
@@ -347,7 +319,7 @@ void MainWindow::setupRibbon() {
|
|||||||
shell_layout->addWidget(ribbon_tabs_);
|
shell_layout->addWidget(ribbon_tabs_);
|
||||||
shell_layout->addWidget(ribbon_band);
|
shell_layout->addWidget(ribbon_band);
|
||||||
|
|
||||||
connect(ribbon_tabs_, &QTabBar::currentChanged,
|
connect(ribbon_tabs_, &components::TabBar::currentChanged,
|
||||||
ribbon_pages_, &QStackedWidget::setCurrentIndex);
|
ribbon_pages_, &QStackedWidget::setCurrentIndex);
|
||||||
|
|
||||||
setMenuWidget(shell);
|
setMenuWidget(shell);
|
||||||
@@ -481,8 +453,16 @@ void MainWindow::setupLoader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::addFiles(const QStringList& paths) {
|
void MainWindow::addFiles(const QStringList& paths) {
|
||||||
if (paths.isEmpty()) return;
|
QStringList accepted_paths;
|
||||||
loader_->addFiles(paths);
|
QStringList accepted_fed_ids;
|
||||||
|
for (const auto& path : paths) {
|
||||||
|
const QString fed_id = federation_->addModel(path);
|
||||||
|
if (fed_id.isEmpty()) continue;
|
||||||
|
accepted_paths << path;
|
||||||
|
accepted_fed_ids << fed_id;
|
||||||
|
}
|
||||||
|
loadModelsFromPaths(accepted_paths, accepted_fed_ids);
|
||||||
|
updateWindowTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MainWindow::formatElapsed(qint64 ms) const {
|
QString MainWindow::formatElapsed(qint64 ms) const {
|
||||||
@@ -492,12 +472,225 @@ QString MainWindow::formatElapsed(qint64 ms) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onAddFiles() {
|
void MainWindow::onAddFiles() {
|
||||||
const QStringList paths = QFileDialog::getOpenFileNames(
|
panels::add_model::AddModelDialog dialog(this);
|
||||||
this, "Add IFC Files", QString(),
|
if (dialog.exec() != QDialog::Accepted) return;
|
||||||
"IFC Viewer Cache (*.ifcview)");
|
|
||||||
|
QStringList paths;
|
||||||
|
switch (dialog.selectedMode()) {
|
||||||
|
case panels::add_model::SourceMode::IfcFile: {
|
||||||
|
QFileDialog file_dialog(this, "Add IFC Files");
|
||||||
|
file_dialog.setFileMode(QFileDialog::ExistingFiles);
|
||||||
|
file_dialog.setNameFilter("IFC Files (*.ifc);;All Files (*)");
|
||||||
|
file_dialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||||
|
if (file_dialog.exec() == QDialog::Accepted) {
|
||||||
|
paths = file_dialog.selectedFiles();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case panels::add_model::SourceMode::IfcDatabase: {
|
||||||
|
QFileDialog database_dialog(this, "Add IFC Databases");
|
||||||
|
database_dialog.setFileMode(QFileDialog::Directory);
|
||||||
|
database_dialog.setOption(QFileDialog::ShowDirsOnly, true);
|
||||||
|
database_dialog.setOption(QFileDialog::DontResolveSymlinks, true);
|
||||||
|
database_dialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||||
|
if (auto* list = database_dialog.findChild<QListView*>("listView")) {
|
||||||
|
list->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
}
|
||||||
|
if (auto* tree = database_dialog.findChild<QTreeView*>()) {
|
||||||
|
tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
}
|
||||||
|
if (database_dialog.exec() == QDialog::Accepted) {
|
||||||
|
paths = database_dialog.selectedFiles();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case panels::add_model::SourceMode::GeometryOnly: {
|
||||||
|
QFileDialog file_dialog(this, "Add Geometry Only");
|
||||||
|
file_dialog.setFileMode(QFileDialog::ExistingFiles);
|
||||||
|
file_dialog.setNameFilter("IFC Viewer Cache (*.ifcview);;All Files (*)");
|
||||||
|
file_dialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||||
|
if (file_dialog.exec() == QDialog::Accepted) {
|
||||||
|
paths = file_dialog.selectedFiles();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case panels::add_model::SourceMode::None:
|
||||||
|
return;
|
||||||
|
}
|
||||||
addFiles(paths);
|
addFiles(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::clearScene() {
|
||||||
|
if (viewport_) viewport_->setSelectedObjectId(0);
|
||||||
|
if (properties_view_) properties_view_->clearSelection();
|
||||||
|
|
||||||
|
const auto model_ids = model_id_to_fed_id_.keys();
|
||||||
|
for (uint32_t mid : model_ids) {
|
||||||
|
viewport_->removeModel(mid);
|
||||||
|
loader_->removeModel(mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
fed_id_to_model_id_.clear();
|
||||||
|
model_id_to_fed_id_.clear();
|
||||||
|
element_registry_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::confirmDiscardIfDirty() {
|
||||||
|
if (!federation_->isDirty()) return true;
|
||||||
|
const auto result = QMessageBox::question(
|
||||||
|
this, "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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::loadModelsFromPaths(const QStringList& paths, const QStringList& fed_ids) {
|
||||||
|
if (paths.isEmpty()) return;
|
||||||
|
const auto ids = loader_->addFiles(paths);
|
||||||
|
for (int i = 0; i < paths.size() && i < static_cast<int>(ids.size()) && i < fed_ids.size(); ++i) {
|
||||||
|
fed_id_to_model_id_[fed_ids[i]] = ids[i];
|
||||||
|
model_id_to_fed_id_[ids[i]] = fed_ids[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::openProject(const QString& path) {
|
||||||
|
if (loader_ && loader_->isLoading()) {
|
||||||
|
QMessageBox::information(
|
||||||
|
this, "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(this, "Open Project",
|
||||||
|
QString("Could not open project:\n%1").arg(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearScene();
|
||||||
|
|
||||||
|
QStringList paths;
|
||||||
|
QStringList fed_ids;
|
||||||
|
QStringList missing;
|
||||||
|
for (const auto& model : federation_->models()) {
|
||||||
|
if (model.source_kind != "local") continue;
|
||||||
|
if (!QFileInfo::exists(model.source_path)) {
|
||||||
|
missing << model.source_path;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
paths << model.source_path;
|
||||||
|
fed_ids << model.id;
|
||||||
|
}
|
||||||
|
loadModelsFromPaths(paths, fed_ids);
|
||||||
|
|
||||||
|
for (const auto& msg : missing) {
|
||||||
|
warnings << QString("Source not found, kept in project: %1").arg(msg);
|
||||||
|
}
|
||||||
|
if (!warnings.isEmpty()) {
|
||||||
|
QMessageBox::warning(this, "Open Project",
|
||||||
|
"Project opened with warnings:\n\n" + warnings.join("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
federation_->markClean();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
updateWindowTitle();
|
||||||
|
setStatusMessage("Project", QFileInfo(path).fileName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::saveProject() {
|
||||||
|
if (federation_->filePath().isEmpty()) return saveProjectAs();
|
||||||
|
|
||||||
|
QString err;
|
||||||
|
if (!federation_->save(federation_->filePath(), &err)) {
|
||||||
|
QMessageBox::warning(this, "Save Project",
|
||||||
|
QString("Could not save project:\n%1").arg(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
updateWindowTitle();
|
||||||
|
setStatusMessage("Project", QFileInfo(federation_->filePath()).fileName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::saveProjectAs() {
|
||||||
|
QString suggested = federation_->filePath();
|
||||||
|
if (suggested.isEmpty()) suggested = "project.ifcfed";
|
||||||
|
|
||||||
|
QFileDialog file_dialog(this, "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";
|
||||||
|
|
||||||
|
QString err;
|
||||||
|
if (!federation_->save(path, &err)) {
|
||||||
|
QMessageBox::warning(this, "Save Project",
|
||||||
|
QString("Could not save project:\n%1").arg(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
updateWindowTitle();
|
||||||
|
setStatusMessage("Project", QFileInfo(path).fileName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateWindowTitle() {
|
||||||
|
const QString project_path = federation_ ? federation_->filePath() : QString();
|
||||||
|
if (project_path.isEmpty() && (!federation_ || federation_->models().empty())) {
|
||||||
|
setWindowTitle("IfcOpenShell Interface");
|
||||||
|
} else if (project_path.isEmpty()) {
|
||||||
|
setWindowTitle("untitled[*] - IfcOpenShell Interface");
|
||||||
|
} else {
|
||||||
|
setWindowTitle(QFileInfo(project_path).fileName() + "[*] - IfcOpenShell Interface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onNewProject() {
|
||||||
|
if (loader_ && loader_->isLoading()) {
|
||||||
|
QMessageBox::information(
|
||||||
|
this, "New Project",
|
||||||
|
"Wait until the current model load finishes before creating a new project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!confirmDiscardIfDirty()) return;
|
||||||
|
clearScene();
|
||||||
|
federation_->clear();
|
||||||
|
updateWindowTitle();
|
||||||
|
setStatusMessage("Project", "Untitled");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onOpenProject() {
|
||||||
|
QFileDialog file_dialog(this, "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;
|
||||||
|
const QString path = file_dialog.selectedFiles().value(0);
|
||||||
|
if (path.isEmpty()) return;
|
||||||
|
openProject(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onSaveProject() {
|
||||||
|
saveProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onSaveProjectAs() {
|
||||||
|
saveProjectAs();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onLoadStarted(uint32_t /*mid*/, QString display_name) {
|
void MainWindow::onLoadStarted(uint32_t /*mid*/, QString display_name) {
|
||||||
status_mode_label_->setText("Loading");
|
status_mode_label_->setText("Loading");
|
||||||
status_selection_label_->setText(display_name);
|
status_selection_label_->setText(display_name);
|
||||||
|
|||||||
@@ -21,17 +21,19 @@
|
|||||||
#ifndef IFCINTERFACE_SHELL_MAINWINDOW_H
|
#ifndef IFCINTERFACE_SHELL_MAINWINDOW_H
|
||||||
#define IFCINTERFACE_SHELL_MAINWINDOW_H
|
#define IFCINTERFACE_SHELL_MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QDockWidget;
|
class QDockWidget;
|
||||||
class QStackedWidget;
|
class QStackedWidget;
|
||||||
class QTabBar;
|
|
||||||
class QToolButton;
|
class QToolButton;
|
||||||
|
class Federation;
|
||||||
class ViewportWindow;
|
class ViewportWindow;
|
||||||
class SceneLoader;
|
class SceneLoader;
|
||||||
namespace ifcinterface { class ElementRegistry; }
|
namespace ifcinterface { class ElementRegistry; }
|
||||||
|
namespace ifcinterface::components { class TabBar; }
|
||||||
namespace ifcinterface::panels::models { class ModelsPanelView; }
|
namespace ifcinterface::panels::models { class ModelsPanelView; }
|
||||||
namespace ifcinterface::panels::spatial_hierarchy { class SpatialHierarchyPanelView; }
|
namespace ifcinterface::panels::spatial_hierarchy { class SpatialHierarchyPanelView; }
|
||||||
namespace ifcinterface::panels::properties { class PropertiesPanelView; }
|
namespace ifcinterface::panels::properties { class PropertiesPanelView; }
|
||||||
@@ -54,6 +56,13 @@ private:
|
|||||||
QWidget* buildNavigateRibbonPage();
|
QWidget* buildNavigateRibbonPage();
|
||||||
QWidget* buildInspectRibbonPage();
|
QWidget* buildInspectRibbonPage();
|
||||||
QWidget* buildPanelsRibbonPage();
|
QWidget* buildPanelsRibbonPage();
|
||||||
|
void clearScene();
|
||||||
|
bool confirmDiscardIfDirty();
|
||||||
|
void loadModelsFromPaths(const QStringList& paths, const QStringList& fed_ids);
|
||||||
|
bool openProject(const QString& path);
|
||||||
|
bool saveProject();
|
||||||
|
bool saveProjectAs();
|
||||||
|
void updateWindowTitle();
|
||||||
QToolButton* makeRibbonAction(const QString& text, const QString& icon_path);
|
QToolButton* makeRibbonAction(const QString& text, const QString& icon_path);
|
||||||
QWidget* makeRibbonGroup(const QString& title, const QList<QToolButton*>& buttons);
|
QWidget* makeRibbonGroup(const QString& title, const QList<QToolButton*>& buttons);
|
||||||
QToolButton* makePanelToggle(const QString& text, QDockWidget* dock);
|
QToolButton* makePanelToggle(const QString& text, QDockWidget* dock);
|
||||||
@@ -69,12 +78,17 @@ private slots:
|
|||||||
void onLoadCancelled(uint32_t mid);
|
void onLoadCancelled(uint32_t mid);
|
||||||
void onLoadError(uint32_t mid, QString message);
|
void onLoadError(uint32_t mid, QString message);
|
||||||
void onAllLoadsFinished();
|
void onAllLoadsFinished();
|
||||||
|
void onNewProject();
|
||||||
|
void onOpenProject();
|
||||||
|
void onSaveProject();
|
||||||
|
void onSaveProjectAs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Federation* federation_ = nullptr;
|
||||||
QLabel* status_mode_label_ = nullptr;
|
QLabel* status_mode_label_ = nullptr;
|
||||||
QLabel* status_selection_label_ = nullptr;
|
QLabel* status_selection_label_ = nullptr;
|
||||||
QLabel* status_perf_label_ = nullptr;
|
QLabel* status_perf_label_ = nullptr;
|
||||||
QTabBar* ribbon_tabs_ = nullptr;
|
ifcinterface::components::TabBar* ribbon_tabs_ = nullptr;
|
||||||
QStackedWidget* ribbon_pages_ = nullptr;
|
QStackedWidget* ribbon_pages_ = nullptr;
|
||||||
ViewportWindow* viewport_ = nullptr;
|
ViewportWindow* viewport_ = nullptr;
|
||||||
SceneLoader* loader_ = nullptr;
|
SceneLoader* loader_ = nullptr;
|
||||||
@@ -93,6 +107,8 @@ private:
|
|||||||
ifcinterface::panels::models::ModelsPanelView* models_view_ = nullptr;
|
ifcinterface::panels::models::ModelsPanelView* models_view_ = nullptr;
|
||||||
ifcinterface::panels::spatial_hierarchy::SpatialHierarchyPanelView* spatial_view_ = nullptr;
|
ifcinterface::panels::spatial_hierarchy::SpatialHierarchyPanelView* spatial_view_ = nullptr;
|
||||||
ifcinterface::panels::properties::PropertiesPanelView* properties_view_ = nullptr;
|
ifcinterface::panels::properties::PropertiesPanelView* properties_view_ = nullptr;
|
||||||
|
QHash<QString, uint32_t> fed_id_to_model_id_;
|
||||||
|
QHash<uint32_t, QString> model_id_to_fed_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ifcinterface::shell
|
} // namespace ifcinterface::shell
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
// 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 "Buttons.h"
|
||||||
|
|
||||||
|
#include "SvgIcon.h"
|
||||||
|
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace ifcinterface::components::buttons {
|
||||||
|
|
||||||
|
QToolButton* makeButton(const QString& text,
|
||||||
|
const QString& icon_path,
|
||||||
|
QWidget* parent,
|
||||||
|
const QSize& minimum_size) {
|
||||||
|
auto* button = new QToolButton(parent);
|
||||||
|
button->setObjectName("ribbonButton");
|
||||||
|
button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
||||||
|
button->setIcon(components::icons::makeTintedSvgIcon(icon_path));
|
||||||
|
button->setIconSize(QSize(20, 20));
|
||||||
|
button->setText(text);
|
||||||
|
button->setMinimumSize(minimum_size);
|
||||||
|
button->setAutoRaise(false);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* makeButtonGroup(const QString& title,
|
||||||
|
const QList<QToolButton*>& buttons,
|
||||||
|
QWidget* parent,
|
||||||
|
bool trailing_separator,
|
||||||
|
int vertical_spacing) {
|
||||||
|
auto* group = new QFrame(parent);
|
||||||
|
group->setObjectName("ribbonGroup");
|
||||||
|
group->setProperty("separator", trailing_separator);
|
||||||
|
|
||||||
|
auto* group_layout = new QVBoxLayout(group);
|
||||||
|
group_layout->setContentsMargins(8, 6, 8, 4);
|
||||||
|
group_layout->setSpacing(vertical_spacing);
|
||||||
|
|
||||||
|
auto* button_row = new QHBoxLayout();
|
||||||
|
button_row->setContentsMargins(0, 0, 0, 0);
|
||||||
|
button_row->setSpacing(4);
|
||||||
|
for (auto* button : buttons) {
|
||||||
|
button_row->addWidget(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* label = new QLabel(title, group);
|
||||||
|
label->setObjectName("ribbonGroupLabel");
|
||||||
|
label->setProperty("textRole", "secondary");
|
||||||
|
label->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
group_layout->addLayout(button_row);
|
||||||
|
group_layout->addWidget(label);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ifcinterface::components::buttons
|
||||||
@@ -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_COMPONENTS_BUTTONS_H
|
||||||
|
#define IFCINTERFACE_COMPONENTS_BUTTONS_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
class QToolButton;
|
||||||
|
class QWidget;
|
||||||
|
|
||||||
|
namespace ifcinterface::components::buttons {
|
||||||
|
|
||||||
|
QToolButton* makeButton(const QString& text,
|
||||||
|
const QString& icon_path,
|
||||||
|
QWidget* parent,
|
||||||
|
const QSize& minimum_size = QSize(90, 54));
|
||||||
|
|
||||||
|
QWidget* makeButtonGroup(const QString& title,
|
||||||
|
const QList<QToolButton*>& buttons,
|
||||||
|
QWidget* parent,
|
||||||
|
bool trailing_separator = true,
|
||||||
|
int vertical_spacing = 4);
|
||||||
|
|
||||||
|
} // namespace ifcinterface::components::buttons
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// 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 "Style.h"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace ifcinterface::components {
|
||||||
|
|
||||||
|
Dialog::Dialog(QWidget* parent, bool scrollable)
|
||||||
|
: QDialog(parent)
|
||||||
|
{
|
||||||
|
auto* outer_layout = new QVBoxLayout(this);
|
||||||
|
outer_layout->setContentsMargins(style::metrics::padding,
|
||||||
|
style::metrics::padding,
|
||||||
|
style::metrics::padding,
|
||||||
|
style::metrics::padding);
|
||||||
|
outer_layout->setSpacing(0);
|
||||||
|
|
||||||
|
auto* frame = new QFrame(this);
|
||||||
|
frame->setObjectName("panel");
|
||||||
|
auto* frame_layout = new QVBoxLayout(frame);
|
||||||
|
frame_layout->setContentsMargins(0,
|
||||||
|
style::metrics::section_body_padding,
|
||||||
|
0,
|
||||||
|
style::metrics::section_body_padding);
|
||||||
|
frame_layout->setSpacing(0);
|
||||||
|
|
||||||
|
if (scrollable) {
|
||||||
|
auto* scroll = new QScrollArea(frame);
|
||||||
|
scroll->setWidgetResizable(true);
|
||||||
|
scroll->setFrameShape(QFrame::NoFrame);
|
||||||
|
|
||||||
|
auto* scroll_body = new QWidget(scroll);
|
||||||
|
scroll_body->setObjectName("panelScrollBody");
|
||||||
|
body_layout_ = new QVBoxLayout(scroll_body);
|
||||||
|
body_layout_->setContentsMargins(0, 0, 0, 0);
|
||||||
|
body_layout_->setSpacing(0);
|
||||||
|
|
||||||
|
scroll->setWidget(scroll_body);
|
||||||
|
frame_layout->addWidget(scroll);
|
||||||
|
} else {
|
||||||
|
auto* body = new QWidget(frame);
|
||||||
|
body_layout_ = new QVBoxLayout(body);
|
||||||
|
body_layout_->setContentsMargins(0, 0, 0, 0);
|
||||||
|
body_layout_->setSpacing(0);
|
||||||
|
frame_layout->addWidget(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
outer_layout->addWidget(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dialog::addBodyWidget(QWidget* widget) {
|
||||||
|
body_layout_->addWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ifcinterface::components
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// 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_DIALOG_H
|
||||||
|
#define IFCINTERFACE_COMPONENTS_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QVBoxLayout;
|
||||||
|
class QWidget;
|
||||||
|
|
||||||
|
namespace ifcinterface::components {
|
||||||
|
|
||||||
|
class Dialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Dialog(QWidget* parent = nullptr,
|
||||||
|
bool scrollable = false);
|
||||||
|
|
||||||
|
void addBodyWidget(QWidget* widget);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVBoxLayout* body_layout_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ifcinterface::components
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -95,15 +95,22 @@ Panel::Panel(const QString& title, QWidget* content, QWidget* parent, bool has_s
|
|||||||
|
|
||||||
auto* scroll_body = new QWidget(scroll);
|
auto* scroll_body = new QWidget(scroll);
|
||||||
scroll_body->setObjectName("panelScrollBody");
|
scroll_body->setObjectName("panelScrollBody");
|
||||||
auto* scroll_body_layout = new QVBoxLayout(scroll_body);
|
body_layout_ = new QVBoxLayout(scroll_body);
|
||||||
scroll_body_layout->setContentsMargins(0, 0, 0, 0);
|
body_layout_->setContentsMargins(0, 0, 0, 0);
|
||||||
scroll_body_layout->setSpacing(0);
|
body_layout_->setSpacing(0);
|
||||||
scroll_body_layout->addWidget(content);
|
|
||||||
|
|
||||||
scroll->setWidget(scroll_body);
|
scroll->setWidget(scroll_body);
|
||||||
frame_layout->addWidget(scroll);
|
frame_layout->addWidget(scroll);
|
||||||
} else {
|
} else {
|
||||||
frame_layout->addWidget(content);
|
auto* body = new QWidget(frame);
|
||||||
|
body_layout_ = new QVBoxLayout(body);
|
||||||
|
body_layout_->setContentsMargins(0, 0, 0, 0);
|
||||||
|
body_layout_->setSpacing(0);
|
||||||
|
frame_layout->addWidget(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
body_layout_->addWidget(content);
|
||||||
}
|
}
|
||||||
outer_layout->addWidget(frame);
|
outer_layout->addWidget(frame);
|
||||||
|
|
||||||
@@ -115,4 +122,8 @@ Panel::Panel(const QString& title, QWidget* content, QWidget* parent, bool has_s
|
|||||||
setWidget(outer);
|
setWidget(outer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Panel::addBodyWidget(QWidget* widget) {
|
||||||
|
body_layout_->addWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ifcinterface::components
|
} // namespace ifcinterface::components
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
|
|
||||||
class QWidget;
|
class QWidget;
|
||||||
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace ifcinterface::components {
|
namespace ifcinterface::components {
|
||||||
|
|
||||||
@@ -32,10 +33,15 @@ class Panel : public QDockWidget {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Panel(const QString& title,
|
explicit Panel(const QString& title,
|
||||||
QWidget* content,
|
QWidget* content = nullptr,
|
||||||
QWidget* parent = nullptr,
|
QWidget* parent = nullptr,
|
||||||
bool has_settings = false,
|
bool has_settings = false,
|
||||||
bool scrollable = false);
|
bool scrollable = false);
|
||||||
|
|
||||||
|
void addBodyWidget(QWidget* widget);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVBoxLayout* body_layout_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ifcinterface::components
|
} // namespace ifcinterface::components
|
||||||
|
|||||||
@@ -34,29 +34,39 @@ QString buildAppStyleSheet() {
|
|||||||
background: ${app_background};
|
background: ${app_background};
|
||||||
color: ${primary_text};
|
color: ${primary_text};
|
||||||
}
|
}
|
||||||
|
QFileDialog,
|
||||||
|
QFileDialog QWidget,
|
||||||
|
QFileDialog QStackedWidget,
|
||||||
|
QFileDialog QSplitter {
|
||||||
|
background: ${app_background};
|
||||||
|
color: ${primary_text};
|
||||||
|
}
|
||||||
QFrame#ribbonShell {
|
QFrame#ribbonShell {
|
||||||
background: ${ribbon_shell_background};
|
background: ${ribbon_shell_background};
|
||||||
border-bottom: 1px solid ${border};
|
border-bottom: 1px solid ${border};
|
||||||
}
|
}
|
||||||
QTabBar::tab {
|
QTabBar#appTabBar {
|
||||||
|
background: ${ribbon_shell_background};
|
||||||
|
}
|
||||||
|
QTabBar#appTabBar::tab {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${secondary_text};
|
color: ${secondary_text};
|
||||||
padding: 8px 14px;
|
padding: 8px 14px;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
}
|
}
|
||||||
QTabBar::tab:selected {
|
QTabBar#appTabBar::tab:selected {
|
||||||
color: ${primary_text};
|
color: ${primary_text};
|
||||||
border-bottom: 2px solid ${selection_background};
|
border-bottom: 2px solid ${selection_background};
|
||||||
}
|
}
|
||||||
QTabBar::tab:hover {
|
QTabBar#appTabBar::tab:hover {
|
||||||
color: ${ribbon_tab_hover_text};
|
color: ${ribbon_tab_hover_text};
|
||||||
}
|
}
|
||||||
QFrame#ribbonBand {
|
QFrame#ribbonBand {
|
||||||
background: ${ribbon_band_background};
|
background: ${ribbon_band_background};
|
||||||
border-top: 1px solid ${border};
|
border-top: 1px solid ${border};
|
||||||
}
|
}
|
||||||
QTabWidget::pane {
|
QTabWidget#appTabWidget::pane {
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@@ -67,6 +77,9 @@ QString buildAppStyleSheet() {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
border-right: 1px solid ${border};
|
border-right: 1px solid ${border};
|
||||||
}
|
}
|
||||||
|
QFrame#ribbonGroup[separator="false"] {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
QLabel#ribbonGroupLabel {
|
QLabel#ribbonGroupLabel {
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -105,6 +118,7 @@ QString buildAppStyleSheet() {
|
|||||||
QListWidget,
|
QListWidget,
|
||||||
QTableWidget,
|
QTableWidget,
|
||||||
QLineEdit,
|
QLineEdit,
|
||||||
|
QComboBox,
|
||||||
QSpinBox,
|
QSpinBox,
|
||||||
QDoubleSpinBox,
|
QDoubleSpinBox,
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
@@ -179,6 +193,21 @@ QString buildAppStyleSheet() {
|
|||||||
QLineEdit:focus {
|
QLineEdit:focus {
|
||||||
border: 1px solid ${control_border_focus};
|
border: 1px solid ${control_border_focus};
|
||||||
}
|
}
|
||||||
|
QComboBox {
|
||||||
|
background: ${control_background};
|
||||||
|
border: 1px solid ${border};
|
||||||
|
border-radius: ${panel_radius}px;
|
||||||
|
padding: ${padding}px ${padding}px;
|
||||||
|
}
|
||||||
|
QComboBox:focus {
|
||||||
|
border: 1px solid ${control_border_focus};
|
||||||
|
}
|
||||||
|
QComboBox QAbstractItemView {
|
||||||
|
background: ${panel_background};
|
||||||
|
border: 1px solid ${border};
|
||||||
|
selection-background-color: ${selection_background};
|
||||||
|
selection-color: ${selection_text};
|
||||||
|
}
|
||||||
QSpinBox, QDoubleSpinBox {
|
QSpinBox, QDoubleSpinBox {
|
||||||
background: ${control_background};
|
background: ${control_background};
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// 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 "Tabs.h"
|
||||||
|
|
||||||
|
namespace ifcinterface::components {
|
||||||
|
|
||||||
|
TabBar::TabBar(QWidget* parent)
|
||||||
|
: QTabBar(parent)
|
||||||
|
{
|
||||||
|
setObjectName("appTabBar");
|
||||||
|
setExpanding(false);
|
||||||
|
setDrawBase(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabWidget::TabWidget(QWidget* parent)
|
||||||
|
: QTabWidget(parent)
|
||||||
|
{
|
||||||
|
setObjectName("appTabWidget");
|
||||||
|
setTabBar(new TabBar(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ifcinterface::components
|
||||||
@@ -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_COMPONENTS_TABS_H
|
||||||
|
#define IFCINTERFACE_COMPONENTS_TABS_H
|
||||||
|
|
||||||
|
#include <QTabBar>
|
||||||
|
#include <QTabWidget>
|
||||||
|
|
||||||
|
namespace ifcinterface::components {
|
||||||
|
|
||||||
|
class TabBar : public QTabBar {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabBar(QWidget* parent = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TabWidget : public QTabWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TabWidget(QWidget* parent = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ifcinterface::components
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<!-- This file was generated with the assistance of an AI coding tool. -->
|
||||||
|
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 7.35304V16.647C21 16.8649 20.8819 17.0656 20.6914 17.1715L12.2914 21.8381C12.1102 21.9388 11.8898 21.9388 11.7086 21.8381L3.30861 17.1715C3.11814 17.0656 3 16.8649 3 16.647V7.35304C3 7.13514 3.11814 6.93437 3.30861 6.82855L11.7086 2.16188C11.8898 2.06121 12.1102 2.06121 12.2914 2.16188L20.6914 6.82855C20.8819 6.93437 21 7.13514 21 7.35304Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M3.52844 7.29357L11.7086 11.8381C11.8898 11.9388 12.1102 11.9388 12.2914 11.8381L20.5 7.27777" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M12 21V12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8.5 8.5L15.5 15.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8.5 15.5L15.5 8.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M10.5 8.5L8.5 10.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15.5 13.5L13.5 15.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M4 6V12C4 12 4 15 11 15C18 15 18 12 18 12V6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M11 3C18 3 18 6 18 6C18 6 18 9 11 9C4 9 4 6 4 6C4 6 4 3 11 3Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M11 21C4 21 4 18 4 18V12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M19 22V16M19 16L22 19M19 16L16 19" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 611 B |
@@ -0,0 +1,6 @@
|
|||||||
|
<!-- This file was generated with the assistance of an AI coding tool. -->
|
||||||
|
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M5 6.5C5 4.567 8.13401 3 12 3C15.866 3 19 4.567 19 6.5C19 8.433 15.866 10 12 10C8.13401 10 5 8.433 5 6.5Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M19 6.5V12.5C19 14.433 15.866 16 12 16C8.13401 16 5 14.433 5 12.5V6.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M19 12.5V17.5C19 19.433 15.866 21 12 21C8.13401 21 5 19.433 5 17.5V12.5" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 688 B |
@@ -43,5 +43,8 @@
|
|||||||
<file alias="sidebar-expand.svg">icons/sidebar-expand.svg</file>
|
<file alias="sidebar-expand.svg">icons/sidebar-expand.svg</file>
|
||||||
<file alias="check.svg">icons/check.svg</file>
|
<file alias="check.svg">icons/check.svg</file>
|
||||||
<file alias="xmark-circle.svg">icons/xmark-circle.svg</file>
|
<file alias="xmark-circle.svg">icons/xmark-circle.svg</file>
|
||||||
|
<file alias="database.svg">icons/database.svg</file>
|
||||||
|
<file alias="database-restore.svg">icons/database-restore.svg</file>
|
||||||
|
<file alias="cube-bandage.svg">icons/cube-bandage.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
#include "components/Style.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
@@ -70,6 +71,7 @@ int main(int argc, char* argv[]) {
|
|||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
installUiFont();
|
installUiFont();
|
||||||
|
app.setStyleSheet(ifcinterface::components::style::buildAppStyleSheet());
|
||||||
|
|
||||||
ifcinterface::shell::MainWindow window;
|
ifcinterface::shell::MainWindow window;
|
||||||
window.show();
|
window.show();
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
// 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 "../../components/Dialog.h"
|
||||||
|
#include "../../components/Buttons.h"
|
||||||
|
#include "../../components/Section.h"
|
||||||
|
#include "../../components/Style.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
namespace ifcinterface::panels::add_model {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class HoverDescriptionFilter : public QObject {
|
||||||
|
public:
|
||||||
|
HoverDescriptionFilter(QLabel* label, QString hover_text, QString default_text)
|
||||||
|
: label_(label), hover_text_(std::move(hover_text)), default_text_(std::move(default_text)) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject* watched, QEvent* event) override {
|
||||||
|
Q_UNUSED(watched);
|
||||||
|
if (event->type() == QEvent::Enter) {
|
||||||
|
label_->setText(hover_text_);
|
||||||
|
} else if (event->type() == QEvent::Leave) {
|
||||||
|
label_->setText(default_text_);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel* label_ = nullptr;
|
||||||
|
QString hover_text_;
|
||||||
|
QString default_text_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
AddModelDialog::AddModelDialog(QWidget* parent)
|
||||||
|
: components::Dialog(parent)
|
||||||
|
{
|
||||||
|
setObjectName("appDialog");
|
||||||
|
setWindowTitle("Add Model");
|
||||||
|
setModal(true);
|
||||||
|
setStyleSheet(components::style::buildAppStyleSheet());
|
||||||
|
setupUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddModelDialog::setupUi() {
|
||||||
|
if (auto* root = qobject_cast<QVBoxLayout*>(layout())) {
|
||||||
|
root->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString default_description = "Choose what to add to the project";
|
||||||
|
auto* description_section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||||
|
auto* description = new QLabel(default_description, description_section);
|
||||||
|
description->setProperty("textRole", "secondary");
|
||||||
|
description->setWordWrap(true);
|
||||||
|
description->setAlignment(Qt::AlignCenter);
|
||||||
|
description->setMinimumWidth((90 * 4) + (components::style::metrics::padding * 3));
|
||||||
|
description->setMinimumHeight(description->fontMetrics().lineSpacing() * 2 + 4);
|
||||||
|
description_section->addBodyWidget(description);
|
||||||
|
|
||||||
|
auto* choices_section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||||
|
auto* choices = new QWidget(choices_section);
|
||||||
|
auto* row = new QHBoxLayout(choices);
|
||||||
|
row->setContentsMargins(0, 0, 0, 0);
|
||||||
|
row->setSpacing(components::style::metrics::padding);
|
||||||
|
|
||||||
|
auto* add_ifc = components::buttons::makeButton("Add IFC File", ":/icons/cube.svg", choices, QSize(90, 68));
|
||||||
|
connect(add_ifc, &QToolButton::clicked, this, [this]() {
|
||||||
|
selected_mode_ = SourceMode::IfcFile;
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
add_ifc->installEventFilter(new HoverDescriptionFilter(
|
||||||
|
description,
|
||||||
|
"Add IFC files and load both geometry and data.",
|
||||||
|
default_description));
|
||||||
|
|
||||||
|
auto* add_database = components::buttons::makeButton("Add IFC\nDatabase", ":/icons/database.svg", choices, QSize(90, 68));
|
||||||
|
connect(add_database, &QToolButton::clicked, this, [this]() {
|
||||||
|
selected_mode_ = SourceMode::IfcDatabase;
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
add_database->installEventFilter(new HoverDescriptionFilter(
|
||||||
|
description,
|
||||||
|
"Add IFC RDB databases for optimised performance",
|
||||||
|
default_description));
|
||||||
|
|
||||||
|
auto* add_geometry = components::buttons::makeButton("Add Geometry", ":/icons/cube-bandage.svg", choices, QSize(90, 68));
|
||||||
|
connect(add_geometry, &QToolButton::clicked, this, [this]() {
|
||||||
|
selected_mode_ = SourceMode::GeometryOnly;
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
add_geometry->installEventFilter(new HoverDescriptionFilter(
|
||||||
|
description,
|
||||||
|
"Add pure geometry for fast visualisation",
|
||||||
|
default_description));
|
||||||
|
|
||||||
|
auto* convert_database = components::buttons::makeButton("Convert IFC File\nto Database", ":/icons/database-restore.svg", choices, QSize(90, 68));
|
||||||
|
connect(convert_database, &QToolButton::clicked, this, [description]() {
|
||||||
|
description->setText("IFC-to-database conversion is coming soon.");
|
||||||
|
});
|
||||||
|
convert_database->installEventFilter(new HoverDescriptionFilter(
|
||||||
|
description,
|
||||||
|
"Convert IFC files to databases for smaller filesizes, reduced memory, and faster access. No data is lost.",
|
||||||
|
default_description));
|
||||||
|
|
||||||
|
row->addWidget(components::buttons::makeButtonGroup("ADD", {add_ifc, add_database, add_geometry}, choices, true, 8));
|
||||||
|
row->addWidget(components::buttons::makeButtonGroup("TOOLS", {convert_database}, choices, false, 8));
|
||||||
|
choices_section->addBodyWidget(choices);
|
||||||
|
|
||||||
|
addBodyWidget(description_section);
|
||||||
|
addBodyWidget(choices_section);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ifcinterface::panels::add_model
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// 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_ADDMODELDIALOG_H
|
||||||
|
#define IFCINTERFACE_PANELS_ADDMODELDIALOG_H
|
||||||
|
|
||||||
|
#include "../../components/Dialog.h"
|
||||||
|
|
||||||
|
namespace ifcinterface::panels::add_model {
|
||||||
|
|
||||||
|
enum class SourceMode {
|
||||||
|
None,
|
||||||
|
IfcFile,
|
||||||
|
IfcDatabase,
|
||||||
|
GeometryOnly,
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddModelDialog : public components::Dialog {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AddModelDialog(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
SourceMode selectedMode() const { return selected_mode_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUi();
|
||||||
|
|
||||||
|
SourceMode selected_mode_ = SourceMode::None;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ifcinterface::panels::add_model
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -40,6 +40,10 @@ PropertiesPanelView::PropertiesPanelView(PropertiesPanelWidget* widget,
|
|||||||
refresh(0);
|
refresh(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropertiesPanelView::clearSelection() {
|
||||||
|
refresh(0);
|
||||||
|
}
|
||||||
|
|
||||||
void PropertiesPanelView::refresh(uint32_t object_id) {
|
void PropertiesPanelView::refresh(uint32_t object_id) {
|
||||||
PropertiesPanelState state;
|
PropertiesPanelState state;
|
||||||
state.entity = {"IfcWall", "SOLIDWALL"};
|
state.entity = {"IfcWall", "SOLIDWALL"};
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public:
|
|||||||
ViewportWindow* viewport,
|
ViewportWindow* viewport,
|
||||||
ifcinterface::ElementRegistry* registry,
|
ifcinterface::ElementRegistry* registry,
|
||||||
QObject* parent = nullptr);
|
QObject* parent = nullptr);
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refresh(uint32_t object_id);
|
void refresh(uint32_t object_id);
|
||||||
|
|||||||
@@ -35,6 +35,13 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
void clearLayout(QVBoxLayout* layout) {
|
||||||
|
while (auto* item = layout->takeAt(0)) {
|
||||||
|
if (auto* widget = item->widget()) widget->deleteLater();
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QWidget* makePropertySetPanel(const ifcinterface::panels::properties::PropertySet& property_set, QWidget* parent = nullptr) {
|
QWidget* makePropertySetPanel(const ifcinterface::panels::properties::PropertySet& property_set, QWidget* parent = nullptr) {
|
||||||
auto* group = new QGroupBox(property_set.title, parent);
|
auto* group = new QGroupBox(property_set.title, parent);
|
||||||
group->setObjectName("propertySetBox");
|
group->setObjectName("propertySetBox");
|
||||||
@@ -91,6 +98,34 @@ QWidget* makeFilterWrapper(QLineEdit** field_out, QWidget* parent = nullptr) {
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFrame* makeEntityBox(const ifcinterface::panels::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
|
||||||
|
|
||||||
namespace ifcinterface::panels::properties {
|
namespace ifcinterface::panels::properties {
|
||||||
@@ -101,93 +136,10 @@ PropertiesPanelWidget::PropertiesPanelWidget(QWidget* parent)
|
|||||||
content_layout_ = new QVBoxLayout(this);
|
content_layout_ = new QVBoxLayout(this);
|
||||||
content_layout_->setContentsMargins(0, 0, 0, 0);
|
content_layout_->setContentsMargins(0, 0, 0, 0);
|
||||||
content_layout_->setSpacing(12);
|
content_layout_->setSpacing(12);
|
||||||
|
|
||||||
auto* entity_box = new QFrame(this);
|
|
||||||
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(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);
|
|
||||||
entity_class_label_ = new QLabel(entity_text);
|
|
||||||
entity_class_label_->setObjectName("entityClassLabel");
|
|
||||||
entity_type_label_ = new QLabel(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);
|
|
||||||
|
|
||||||
entity_section_ = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
|
||||||
entity_section_->addBodyWidget(entity_box);
|
|
||||||
attributes_section_ = new components::Section("Attributes", components::SectionHeaderMode::Visible, this);
|
|
||||||
relationships_section_ = new components::Section("Relationships", components::SectionHeaderMode::Visible, this);
|
|
||||||
properties_section_ = new components::Section("Properties", components::SectionHeaderMode::Visible, this);
|
|
||||||
quantities_section_ = new components::Section("Quantities", components::SectionHeaderMode::Visible, this);
|
|
||||||
|
|
||||||
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_);
|
|
||||||
|
|
||||||
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_);
|
|
||||||
|
|
||||||
properties_filter_wrapper_ = makeFilterWrapper(&properties_filter_field_, properties_section_);
|
|
||||||
properties_filter_field_->setPlaceholderText("Filter properties or sets");
|
|
||||||
quantities_filter_wrapper_ = makeFilterWrapper(&quantities_filter_field_, quantities_section_);
|
|
||||||
quantities_filter_field_->setPlaceholderText("Filter quantities or sets");
|
|
||||||
|
|
||||||
connect(properties_filter_toggle_, &QToolButton::toggled, properties_filter_field_, [this](bool visible) {
|
|
||||||
properties_filter_field_->setVisible(visible);
|
|
||||||
properties_filter_wrapper_->setVisible(visible);
|
|
||||||
if (visible) properties_filter_field_->setFocus();
|
|
||||||
});
|
|
||||||
connect(quantities_filter_toggle_, &QToolButton::toggled, quantities_filter_field_, [this](bool visible) {
|
|
||||||
quantities_filter_field_->setVisible(visible);
|
|
||||||
quantities_filter_wrapper_->setVisible(visible);
|
|
||||||
if (visible) quantities_filter_field_->setFocus();
|
|
||||||
});
|
|
||||||
|
|
||||||
properties_filter_wrapper_->setVisible(false);
|
|
||||||
quantities_filter_wrapper_->setVisible(false);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
|
void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
|
||||||
const bool attributes_expanded = attributes_section_->isExpanded();
|
clearLayout(content_layout_);
|
||||||
const bool relationships_expanded = relationships_section_->isExpanded();
|
|
||||||
const bool properties_expanded = properties_section_->isExpanded();
|
|
||||||
const bool quantities_expanded = quantities_section_->isExpanded();
|
|
||||||
const bool properties_filter_visible = properties_filter_toggle_->isChecked();
|
|
||||||
const bool quantities_filter_visible = quantities_filter_toggle_->isChecked();
|
|
||||||
const QString properties_filter_text = properties_filter_field_->text();
|
|
||||||
const QString quantities_filter_text = quantities_filter_field_->text();
|
|
||||||
|
|
||||||
entity_class_label_->setText(state.entity.entity_class);
|
|
||||||
entity_type_label_->setText(state.entity.predefined_type);
|
|
||||||
|
|
||||||
attributes_section_->clearBody();
|
|
||||||
relationships_section_->clearBody();
|
|
||||||
properties_section_->clearBody();
|
|
||||||
quantities_section_->clearBody();
|
|
||||||
|
|
||||||
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) {
|
||||||
@@ -199,21 +151,98 @@ void PropertiesPanelWidget::render(const PropertiesPanelState& state) {
|
|||||||
quantity_set_widgets.append(makePropertySetPanel(property_set, this));
|
quantity_set_widgets.append(makePropertySetPanel(property_set, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes_section_->addBodyWidget(makeAttributeList(state.attributes, this));
|
auto* entity_section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||||
relationships_section_->addBodyWidget(makeRelationshipList(state.relationships, this));
|
entity_section->addBodyWidget(makeEntityBox(state.entity, this));
|
||||||
properties_section_->addBodyWidget(properties_filter_wrapper_);
|
|
||||||
for (auto* widget : property_set_widgets) properties_section_->addBodyWidget(widget);
|
|
||||||
quantities_section_->addBodyWidget(quantities_filter_wrapper_);
|
|
||||||
for (auto* widget : quantity_set_widgets) quantities_section_->addBodyWidget(widget);
|
|
||||||
|
|
||||||
attributes_section_->setExpanded(attributes_expanded);
|
auto* attributes_section = new components::Section("Attributes", components::SectionHeaderMode::Visible, this);
|
||||||
relationships_section_->setExpanded(relationships_expanded);
|
attributes_section->addBodyWidget(makeAttributeList(state.attributes, this));
|
||||||
properties_section_->setExpanded(properties_expanded);
|
attributes_section->setExpanded(attributes_expanded_);
|
||||||
quantities_section_->setExpanded(quantities_expanded);
|
|
||||||
properties_filter_field_->setText(properties_filter_text);
|
auto* relationships_section = new components::Section("Relationships", components::SectionHeaderMode::Visible, this);
|
||||||
quantities_filter_field_->setText(quantities_filter_text);
|
relationships_section->addBodyWidget(makeRelationshipList(state.relationships, this));
|
||||||
properties_filter_toggle_->setChecked(properties_filter_visible);
|
relationships_section->setExpanded(relationships_expanded_);
|
||||||
quantities_filter_toggle_->setChecked(quantities_filter_visible);
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
} // namespace ifcinterface::panels::properties
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
@@ -42,19 +43,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QVBoxLayout* content_layout_ = nullptr;
|
QVBoxLayout* content_layout_ = nullptr;
|
||||||
QLabel* entity_class_label_ = nullptr;
|
bool attributes_expanded_ = true;
|
||||||
QLabel* entity_type_label_ = nullptr;
|
bool relationships_expanded_ = true;
|
||||||
components::Section* entity_section_ = nullptr;
|
bool properties_expanded_ = true;
|
||||||
components::Section* attributes_section_ = nullptr;
|
bool quantities_expanded_ = true;
|
||||||
components::Section* relationships_section_ = nullptr;
|
bool properties_filter_visible_ = false;
|
||||||
components::Section* properties_section_ = nullptr;
|
bool quantities_filter_visible_ = false;
|
||||||
components::Section* quantities_section_ = nullptr;
|
QString properties_filter_text_;
|
||||||
QWidget* properties_filter_wrapper_ = nullptr;
|
QString quantities_filter_text_;
|
||||||
QWidget* quantities_filter_wrapper_ = nullptr;
|
|
||||||
QLineEdit* properties_filter_field_ = nullptr;
|
|
||||||
QLineEdit* quantities_filter_field_ = nullptr;
|
|
||||||
QToolButton* properties_filter_toggle_ = nullptr;
|
|
||||||
QToolButton* quantities_filter_toggle_ = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ifcinterface::panels::properties
|
} // namespace ifcinterface::panels::properties
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
#include "Dialog.h"
|
#include "Dialog.h"
|
||||||
|
|
||||||
#include "../../../ifcviewer/AppSettings.h"
|
#include "../../../ifcviewer/AppSettings.h"
|
||||||
|
#include "../../components/Dialog.h"
|
||||||
#include "../../components/Section.h"
|
#include "../../components/Section.h"
|
||||||
#include "../../components/Style.h"
|
#include "../../components/Style.h"
|
||||||
#include "../../components/SvgIcon.h"
|
#include "../../components/SvgIcon.h"
|
||||||
|
#include "../../components/Tabs.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
@@ -35,13 +37,12 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QTabWidget>
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
namespace ifcinterface::panels::settings {
|
namespace ifcinterface::panels::settings {
|
||||||
|
|
||||||
SettingsDialog::SettingsDialog(QWidget* parent)
|
SettingsDialog::SettingsDialog(QWidget* parent)
|
||||||
: QDialog(parent)
|
: components::Dialog(parent)
|
||||||
{
|
{
|
||||||
setObjectName("appDialog");
|
setObjectName("appDialog");
|
||||||
setWindowTitle("Settings");
|
setWindowTitle("Settings");
|
||||||
@@ -57,23 +58,12 @@ void SettingsDialog::showEvent(QShowEvent* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::setupUi() {
|
void SettingsDialog::setupUi() {
|
||||||
auto* root = new QVBoxLayout(this);
|
auto* tabs = new components::TabWidget(this);
|
||||||
root->setContentsMargins(12, 12, 12, 12);
|
|
||||||
root->setSpacing(0);
|
|
||||||
|
|
||||||
auto* panel = new QFrame(this);
|
|
||||||
panel->setObjectName("panel");
|
|
||||||
auto* panel_layout = new QVBoxLayout(panel);
|
|
||||||
panel_layout->setContentsMargins(0, components::style::metrics::section_body_padding, 0,
|
|
||||||
components::style::metrics::section_body_padding);
|
|
||||||
panel_layout->setSpacing(12);
|
|
||||||
|
|
||||||
auto* tabs = new QTabWidget(panel);
|
|
||||||
|
|
||||||
auto* graphics_tab = new QWidget(tabs);
|
auto* graphics_tab = new QWidget(tabs);
|
||||||
auto* graphics_layout = new QVBoxLayout(graphics_tab);
|
auto* graphics_layout = new QVBoxLayout(graphics_tab);
|
||||||
graphics_layout->setContentsMargins(0, 0, 0, 0);
|
graphics_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
graphics_layout->setSpacing(12);
|
graphics_layout->setSpacing(components::style::metrics::padding);
|
||||||
|
|
||||||
auto* general_section = new components::Section("General", components::SectionHeaderMode::Visible, graphics_tab);
|
auto* general_section = new components::Section("General", components::SectionHeaderMode::Visible, graphics_tab);
|
||||||
auto* general_body = new QWidget(general_section);
|
auto* general_body = new QWidget(general_section);
|
||||||
@@ -148,7 +138,7 @@ void SettingsDialog::setupUi() {
|
|||||||
auto* tab = new QWidget(tabs);
|
auto* tab = new QWidget(tabs);
|
||||||
auto* layout = new QVBoxLayout(tab);
|
auto* layout = new QVBoxLayout(tab);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->setSpacing(12);
|
layout->setSpacing(components::style::metrics::padding);
|
||||||
|
|
||||||
auto* section = new components::Section(title, components::SectionHeaderMode::Visible, tab);
|
auto* section = new components::Section(title, components::SectionHeaderMode::Visible, tab);
|
||||||
auto* body = new QWidget(section);
|
auto* body = new QWidget(section);
|
||||||
@@ -179,7 +169,7 @@ void SettingsDialog::setupUi() {
|
|||||||
tabs->addTab(make_placeholder_tab("About", "Version, credits, and environment information will live here."),
|
tabs->addTab(make_placeholder_tab("About", "Version, credits, and environment information will live here."),
|
||||||
"About");
|
"About");
|
||||||
|
|
||||||
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, panel);
|
auto* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
if (auto* ok = buttons->button(QDialogButtonBox::Ok)) {
|
if (auto* ok = buttons->button(QDialogButtonBox::Ok)) {
|
||||||
ok->setText("OK");
|
ok->setText("OK");
|
||||||
ok->setIcon(components::icons::makeSvgIcon(":/icons/check.svg"));
|
ok->setIcon(components::icons::makeSvgIcon(":/icons/check.svg"));
|
||||||
@@ -191,9 +181,11 @@ void SettingsDialog::setupUi() {
|
|||||||
connect(buttons, &QDialogButtonBox::accepted, this, &SettingsDialog::onAccepted);
|
connect(buttons, &QDialogButtonBox::accepted, this, &SettingsDialog::onAccepted);
|
||||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
panel_layout->addWidget(tabs);
|
auto* actions_section = new components::Section("", components::SectionHeaderMode::Hidden, this);
|
||||||
panel_layout->addWidget(buttons);
|
actions_section->addBodyWidget(buttons);
|
||||||
root->addWidget(panel);
|
|
||||||
|
addBodyWidget(tabs);
|
||||||
|
addBodyWidget(actions_section);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::syncFromSettings() {
|
void SettingsDialog::syncFromSettings() {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#ifndef IFCINTERFACE_PANELS_SETTINGSDIALOG_H
|
#ifndef IFCINTERFACE_PANELS_SETTINGSDIALOG_H
|
||||||
#define IFCINTERFACE_PANELS_SETTINGSDIALOG_H
|
#define IFCINTERFACE_PANELS_SETTINGSDIALOG_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include "../../components/Dialog.h"
|
||||||
|
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class QDoubleSpinBox;
|
class QDoubleSpinBox;
|
||||||
@@ -31,7 +31,7 @@ class QSpinBox;
|
|||||||
|
|
||||||
namespace ifcinterface::panels::settings {
|
namespace ifcinterface::panels::settings {
|
||||||
|
|
||||||
class SettingsDialog : public QDialog {
|
class SettingsDialog : public components::Dialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SettingsDialog(QWidget* parent = nullptr);
|
explicit SettingsDialog(QWidget* parent = nullptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user