attach vtk context to gcompose

This commit is contained in:
AndreaRigoni
2026-03-22 12:18:33 +00:00
parent a8f786d8d1
commit 324aaa91b7
36 changed files with 674 additions and 19 deletions

View File

@@ -3,6 +3,7 @@
#include <typeinfo>
#include <cxxabi.h>
#include <functional>
#include "Core/Object.h"
ContextModel::ContextModel(QObject* parent)
: QAbstractItemModel(parent), m_rootContext(nullptr) {}
@@ -12,6 +13,12 @@ ContextModel::~ContextModel() {}
void ContextModel::setContext(uLib::ObjectsContext* context) {
beginResetModel();
m_rootContext = context;
if (m_rootContext) {
uLib::Object::connect(m_rootContext, &uLib::Object::Updated, [this]() {
this->beginResetModel();
this->endResetModel();
});
}
endResetModel();
}
@@ -118,7 +125,14 @@ QVariant ContextModel::data(const QModelIndex& index, int role) const {
uLib::Object* obj = static_cast<uLib::Object*>(index.internalPointer());
if (role == Qt::DisplayRole) {
return getDemangledName(typeid(*obj));
QString typeName = getDemangledName(typeid(*obj));
std::string instName = obj->GetInstanceName();
if (instName.empty()) return typeName;
return QString("%1 (%2)").arg(QString::fromStdString(instName)).arg(typeName);
}
if (role == Qt::EditRole) {
return QString::fromStdString(obj->GetInstanceName());
}
return QVariant();
@@ -130,3 +144,18 @@ QVariant ContextModel::headerData(int section, Qt::Orientation orientation, int
}
return QVariant();
}
Qt::ItemFlags ContextModel::flags(const QModelIndex& index) const {
if (!index.isValid()) return Qt::NoItemFlags;
return Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
bool ContextModel::setData(const QModelIndex& index, const QVariant& value, int role) {
if (index.isValid() && role == Qt::EditRole) {
uLib::Object* obj = static_cast<uLib::Object*>(index.internalPointer());
obj->SetInstanceName(value.toString().toStdString());
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
return true;
}
return false;
}

View File

@@ -18,6 +18,8 @@ public:
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
private:
uLib::ObjectsContext* m_rootContext;

View File

@@ -4,8 +4,16 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QTreeView>
#include <QSplitter>
#include <QList>
#include <QShortcut>
#include <QItemSelectionModel>
#include <Vtk/vtkQViewport.h>
#include <Vtk/vtkObjectsContext.h>
ContextPanel::ContextPanel(QWidget* parent) : QWidget(parent) {
ContextPanel::ContextPanel(QWidget* parent)
: QWidget(parent)
, m_vtkContext(nullptr) {
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->setSpacing(0);
@@ -32,12 +40,92 @@ ContextPanel::ContextPanel(QWidget* parent) : QWidget(parent) {
m_model = new ContextModel(this);
m_treeView->setModel(m_model);
m_layout->addWidget(m_treeView);
m_splitter = new QSplitter(Qt::Vertical, this);
m_splitter->addWidget(m_treeView);
m_vtkView = new uLib::Vtk::QViewport(m_splitter);
m_splitter->addWidget(m_vtkView);
QList<int> sizes;
sizes << 400 << 200;
m_splitter->setSizes(sizes);
m_layout->addWidget(m_splitter);
connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &ContextPanel::onSelectionChanged);
auto* deleteShortcut = new QShortcut(QKeySequence::Delete, this);
connect(deleteShortcut, &QShortcut::activated, [this]() {
auto selectedIndexes = m_treeView->selectionModel()->selectedIndexes();
if (selectedIndexes.isEmpty() || !m_context) return;
// Collect objects to remove to avoid iterator invalidation issues if context signal emits during removal
std::vector<uLib::Object*> toRemove;
for (const auto& idx : selectedIndexes) {
if (idx.column() == 0) {
toRemove.push_back(static_cast<uLib::Object*>(idx.internalPointer()));
}
}
for (auto* obj : toRemove) {
m_context->RemoveObject(obj);
}
});
}
ContextPanel::~ContextPanel() {}
void ContextPanel::setContext(uLib::ObjectsContext* context) {
m_context = context;
m_model->setContext(context);
m_treeView->expandAll();
if (m_vtkContext) {
m_vtkView->RemovePuppet(*m_vtkContext);
delete m_vtkContext;
}
m_vtkContext = new uLib::Vtk::vtkObjectsContext(context);
m_vtkView->AddPuppet(*m_vtkContext);
// Render viewport and add child puppets when context is updated
if (context) {
uLib::Object::connect(m_vtkContext, &uLib::Vtk::vtkObjectsContext::PuppetAdded, [this](uLib::Vtk::Puppet* p) {
if (this->m_vtkView && p) {
this->m_vtkView->AddPuppet(*p);
this->m_vtkView->ZoomAuto();
this->m_vtkView->Render();
}
});
// Add any puppets that were created during m_vtkContext's construction
for (auto* obj : context->GetObjects()) {
if (auto* p = m_vtkContext->GetPuppet(obj)) {
this->m_vtkView->AddPuppet(*p);
}
}
uLib::Object::connect(context, &uLib::Object::Updated, [this]() {
if (this->m_vtkView) {
this->m_vtkView->ZoomAuto();
this->m_vtkView->Render();
}
});
}
m_vtkView->Render();
}
void ContextPanel::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
uLib::Object* target = nullptr;
if (!selected.indexes().isEmpty()) {
target = static_cast<uLib::Object*>(selected.indexes().first().internalPointer());
}
emit objectSelected(target);
if (m_vtkContext) {
auto* puppet = m_vtkContext->GetPuppet(target);
m_vtkView->SelectPuppet(puppet);
}
}

View File

@@ -2,6 +2,7 @@
#define CONTEXT_PANEL_H
#include <QWidget>
#include <QItemSelection>
class QTreeView;
class QVBoxLayout;
@@ -9,9 +10,16 @@ class QLabel;
class ContextModel;
namespace uLib {
class Object;
class ObjectsContext;
namespace Vtk {
class QViewport;
class vtkObjectsContext;
}
}
class QSplitter;
class ContextPanel : public QWidget {
Q_OBJECT
public:
@@ -20,12 +28,22 @@ public:
void setContext(uLib::ObjectsContext* context);
Q_SIGNALS:
void objectSelected(uLib::Object* obj);
private Q_SLOTS:
void onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
private:
QVBoxLayout* m_layout;
QWidget* m_titleBar;
QLabel* m_titleLabel;
QTreeView* m_treeView;
ContextModel* m_model;
QSplitter* m_splitter;
uLib::Vtk::QViewport* m_vtkView;
uLib::Vtk::vtkObjectsContext* m_vtkContext;
uLib::ObjectsContext* m_context;
};
#endif // CONTEXT_PANEL_H

View File

@@ -1,6 +1,10 @@
#include "MainPanel.h"
#include "ViewportPane.h"
#include "ContextPanel.h"
#include "Core/ObjectFactory.h"
#include "Core/ObjectsContext.h"
#include "Vtk/vtkObjectsContext.h"
#include "Vtk/vtkQViewport.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSplitter>
@@ -11,7 +15,7 @@
#include <QApplication>
#include "StyleManager.h"
MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
MainPanel::MainPanel(QWidget* parent) : QWidget(parent), m_context(nullptr), m_mainVtkContext(nullptr) {
auto* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
@@ -44,8 +48,23 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
themeMenu->addAction("Bright", this, &MainPanel::onBrightTheme);
btnTheme->setMenu(themeMenu);
// New Menu Button
auto* btnNew = new QPushButton("New", menuPanel);
btnNew->setObjectName("MenuButton");
auto* newMenu = new QMenu(btnNew);
auto classes = uLib::ObjectFactory::Instance().GetRegisteredClasses();
for (const auto& className : classes) {
auto* action = newMenu->addAction(QString::fromStdString(className));
connect(action, &QAction::triggered, [this, className]() {
this->onCreateObject(className);
});
}
btnNew->setMenu(newMenu);
menuLayout->addWidget(logo);
menuLayout->addWidget(btnFile);
menuLayout->addWidget(btnNew);
menuLayout->addWidget(btnTheme);
menuLayout->addStretch();
@@ -58,6 +77,16 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
m_firstPane = new ViewportPane(m_rootSplitter);
m_rootSplitter->addWidget(m_firstPane);
connect(m_contextPanel, &ContextPanel::objectSelected, [this](uLib::Object* obj) {
if (auto* viewport = qobject_cast<uLib::Vtk::QViewport*>(m_firstPane->currentViewport())) {
uLib::Vtk::Puppet* puppet = nullptr;
if (m_mainVtkContext) {
puppet = m_mainVtkContext->GetPuppet(obj);
}
viewport->SelectPuppet(puppet);
}
});
// Set initial sizes
QList<int> sizes;
sizes << 200 << 1000;
@@ -67,7 +96,52 @@ MainPanel::MainPanel(QWidget* parent) : QWidget(parent) {
}
void MainPanel::setContext(uLib::ObjectsContext* context) {
m_context = context;
m_contextPanel->setContext(context);
if (m_mainVtkContext) {
if (auto* viewport = qobject_cast<uLib::Vtk::QViewport*>(m_firstPane->currentViewport())) {
viewport->RemovePuppet(*m_mainVtkContext);
}
delete m_mainVtkContext;
m_mainVtkContext = nullptr;
}
if (context) {
if (auto* viewport = qobject_cast<uLib::Vtk::QViewport*>(m_firstPane->currentViewport())) {
m_mainVtkContext = new uLib::Vtk::vtkObjectsContext(context);
viewport->AddPuppet(*m_mainVtkContext);
uLib::Object::connect(m_mainVtkContext, &uLib::Vtk::vtkObjectsContext::PuppetAdded, [viewport](uLib::Vtk::Puppet* p) {
if (viewport && p) {
viewport->AddPuppet(*p);
viewport->ZoomAuto();
viewport->Render();
}
});
// Add any puppets that were created during m_mainVtkContext's construction
for (auto* obj : context->GetObjects()) {
if (auto* p = m_mainVtkContext->GetPuppet(obj)) {
viewport->AddPuppet(*p);
}
}
uLib::Object::connect(context, &uLib::Object::Updated, [viewport]() {
viewport->ZoomAuto();
viewport->Render();
});
viewport->ZoomAuto();
viewport->Render();
}
}
}
void MainPanel::onCreateObject(const std::string& className) {
if (!m_context) return;
auto* obj = uLib::ObjectFactory::Instance().Create(className);
if (obj) {
m_context->AddObject(obj);
}
}
void MainPanel::onOpen() {

View File

@@ -9,6 +9,9 @@ class ContextPanel;
namespace uLib {
class ObjectsContext;
namespace Vtk {
class vtkObjectsContext;
}
}
class MainPanel : public QWidget {
@@ -25,11 +28,15 @@ private slots:
void onSave();
void onDarkTheme();
void onBrightTheme();
void onCreateObject(const std::string& className);
private:
QSplitter* m_rootSplitter;
ViewportPane* m_firstPane;
ContextPanel* m_contextPanel;
uLib::ObjectsContext* m_context;
uLib::Vtk::vtkObjectsContext* m_mainVtkContext;
};
#endif // MAINPANEL_H

View File

@@ -33,7 +33,8 @@ int main(int argc, char** argv) {
std::cout << "Starting gcompose Qt application..." << std::endl;
ContainerBox world_box(Vector3f(1, 1, 1));
world_box.Scale(Vector3f(20_mm, 20_mm, 20_mm));
world_box.Scale(Vector3f(2_mm, 2_mm, 2_mm));
world_box.SetPosition(Vector3f(-1_mm, -1_mm, -1_mm));
Geant::Scene scene;
scene.ConstructWorldBox(world_box.GetSize(), "G4_AIR");
@@ -46,14 +47,7 @@ int main(int argc, char** argv) {
// 2. Initialize MainWindow (contains embedded VTK QViewport)
MainWindow window;
window.setContext(&globalContext);
MainPanel* panel = window.getPanel();
ViewportPane* pane = panel->getFirstPane();
Vtk::QViewport* viewport = qobject_cast<Vtk::QViewport*>(pane->currentViewport());
Vtk::vtkContainerBox vtk_box(&world_box);
viewport->AddPuppet(vtk_box);
viewport->ZoomAuto();
std::cout << "Geant4 and VTK scenes are ready." << std::endl;
window.show();