attach vtk context to gcompose
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user