186 lines
5.3 KiB
C++
186 lines
5.3 KiB
C++
#include "vtkQViewport.h"
|
||
|
||
#include <QVBoxLayout>
|
||
#include <QResizeEvent>
|
||
|
||
#include <vtkAxesActor.h>
|
||
#include <vtkCamera.h>
|
||
#include <vtkCameraOrientationWidget.h>
|
||
#include <vtkInteractorStyleTrackballCamera.h>
|
||
#include <vtkObjectFactory.h>
|
||
#include <vtkRenderWindowInteractor.h>
|
||
#include <vtkTextProperty.h>
|
||
|
||
namespace uLib {
|
||
namespace Vtk {
|
||
|
||
QViewport::QViewport(QWidget* parent)
|
||
: QWidget(parent)
|
||
, Viewport()
|
||
, m_VtkWidget(nullptr)
|
||
, m_GridButton(nullptr)
|
||
, m_ProjButton(nullptr)
|
||
, m_renderTimer(nullptr)
|
||
, m_renderPending(false)
|
||
{
|
||
// Build the layout – zero margins so VTK fills the entire widget
|
||
auto* layout = new QVBoxLayout(this);
|
||
layout->setContentsMargins(0, 0, 0, 0);
|
||
layout->setSpacing(0);
|
||
|
||
m_VtkWidget = new QVTKOpenGLNativeWidget(this);
|
||
layout->addWidget(m_VtkWidget);
|
||
|
||
// Initialize render timer
|
||
m_renderTimer = new QTimer(this);
|
||
m_renderTimer->setSingleShot(true);
|
||
connect(m_renderTimer, &QTimer::timeout, this, &QViewport::doRender);
|
||
|
||
// Grid Toggle Button
|
||
m_GridButton = new QPushButton(m_VtkWidget);
|
||
|
||
m_GridButton->setText("#");
|
||
m_GridButton->setFixedSize(40, 40);
|
||
m_GridButton->setToolTip("Toggle Grid");
|
||
m_GridButton->setStyleSheet(
|
||
"QPushButton {"
|
||
" border-radius: 20px;" // Perfectly circular
|
||
" background-color: rgba(40, 40, 40, 180);"
|
||
" color: white;"
|
||
" font-size: 22px;"
|
||
" border: 1.5px solid rgba(255, 255, 255, 60);"
|
||
"}"
|
||
"QPushButton:hover {"
|
||
" background-color: rgba(70, 70, 70, 200);"
|
||
" border: 1.5px solid rgba(255, 255, 255, 100);"
|
||
"}"
|
||
"QPushButton:checked {"
|
||
" background-color: rgba(0, 120, 215, 200);" // Nice "active" blue
|
||
" color: white;"
|
||
" border: 1.5px solid rgba(255, 255, 255, 120);"
|
||
"}"
|
||
"QPushButton:pressed {"
|
||
" background-color: rgba(0, 90, 160, 220);"
|
||
"}"
|
||
);
|
||
m_GridButton->setCheckable(true);
|
||
m_GridButton->setChecked(true); // Grid is on by default
|
||
connect(m_GridButton, &QPushButton::clicked, this, &QViewport::onGridButtonClicked);
|
||
|
||
// Projection Toggle Button (below grid button)
|
||
m_ProjButton = new QPushButton(m_VtkWidget);
|
||
m_ProjButton->setText("P");
|
||
m_ProjButton->setFixedSize(40, 40);
|
||
m_ProjButton->setToolTip("Toggle Perspective / Orthographic");
|
||
m_ProjButton->setStyleSheet(
|
||
"QPushButton {"
|
||
" border-radius: 20px;"
|
||
" background-color: rgba(40, 40, 40, 180);"
|
||
" color: white;"
|
||
" font-size: 22px;"
|
||
" border: 1.5px solid rgba(255, 255, 255, 60);"
|
||
"}"
|
||
"QPushButton:hover {"
|
||
" background-color: rgba(70, 70, 70, 200);"
|
||
" border: 1.5px solid rgba(255, 255, 255, 100);"
|
||
"}"
|
||
"QPushButton:checked {"
|
||
" background-color: rgba(0, 120, 215, 200);"
|
||
" color: white;"
|
||
" border: 1.5px solid rgba(255, 255, 255, 120);"
|
||
"}"
|
||
"QPushButton:pressed {"
|
||
" background-color: rgba(0, 90, 160, 220);"
|
||
"}"
|
||
);
|
||
m_ProjButton->setCheckable(true);
|
||
m_ProjButton->setChecked(false); // Perspective by default
|
||
connect(m_ProjButton, &QPushButton::clicked, this, &QViewport::onProjButtonClicked);
|
||
|
||
// After the Qt widget exists but before the first paint,
|
||
// attach the renderer and configure the pipeline.
|
||
SetupPipeline();
|
||
}
|
||
|
||
QViewport::~QViewport()
|
||
{
|
||
if (m_VtkWidget && m_VtkWidget->renderWindow()) {
|
||
m_VtkWidget->renderWindow()->RemoveRenderer(this->GetRenderer());
|
||
}
|
||
}
|
||
|
||
void QViewport::SetupPipeline()
|
||
{
|
||
// Add our renderer to the QVTKOpenGLNativeWidget's render window
|
||
::vtkRenderWindow* rw = m_VtkWidget->renderWindow();
|
||
rw->AddRenderer(this->GetRenderer());
|
||
|
||
// Common setup
|
||
Viewport::SetupPipeline(rw->GetInteractor());
|
||
}
|
||
|
||
// ── Public API ────────────────────────────────────────────────────────────────
|
||
|
||
void QViewport::Render()
|
||
{
|
||
if (!m_throttledRendering) {
|
||
doRender();
|
||
return;
|
||
}
|
||
if (m_renderPending) return;
|
||
m_renderPending = true;
|
||
m_renderTimer->start(16);
|
||
}
|
||
|
||
void QViewport::doRender()
|
||
{
|
||
m_renderPending = false;
|
||
if (m_VtkWidget && m_VtkWidget->renderWindow())
|
||
m_VtkWidget->renderWindow()->Render();
|
||
}
|
||
|
||
vtkRenderWindow* QViewport::GetRenderWindow()
|
||
{
|
||
return m_VtkWidget->renderWindow();
|
||
}
|
||
|
||
vtkRenderWindowInteractor* QViewport::GetInteractor()
|
||
{
|
||
return m_VtkWidget->renderWindow()->GetInteractor();
|
||
}
|
||
|
||
void QViewport::onGridButtonClicked()
|
||
{
|
||
SetGridVisible(m_GridButton->isChecked());
|
||
}
|
||
|
||
void QViewport::onProjButtonClicked()
|
||
{
|
||
SetParallelProjection(m_ProjButton->isChecked());
|
||
}
|
||
|
||
void QViewport::OnSelectionChanged(Prop3D* p)
|
||
{
|
||
emit prop3dSelected(p);
|
||
}
|
||
|
||
void QViewport::resizeEvent(QResizeEvent* event)
|
||
{
|
||
QWidget::resizeEvent(event);
|
||
if (m_GridButton) {
|
||
// Position under the gizmo (top-right corner).
|
||
// Standard CameraOrientationWidget is usually 150-180px.
|
||
int x = width() - m_GridButton->width() - 10;
|
||
int y = 160;
|
||
m_GridButton->move(x, y);
|
||
}
|
||
if (m_ProjButton) {
|
||
int x = width() - m_ProjButton->width() - 10;
|
||
int y = 210;
|
||
m_ProjButton->move(x, y);
|
||
}
|
||
}
|
||
|
||
} // namespace Vtk
|
||
} // namespace uLib
|