From c8cdf68c15cf5a9d34c6680290fbbdd32d95ca56 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Sun, 27 Aug 2023 23:01:42 -0400 Subject: [PATCH] ENH: Add support for connect/disconnect --- .../Logic/vtkSlicerMixedRealityLogic.cxx | 2 +- .../MRML/vtkMRMLMixedRealityViewNode.cxx | 30 +++++++ .../MRML/vtkMRMLMixedRealityViewNode.h | 14 ++++ .../UI/qSlicerMixedRealityModuleWidget.ui | 82 ++++++++++++++++++- .../Widgets/qMRMLMixedRealityView.cxx | 54 ++++++------ MixedReality/Widgets/qMRMLMixedRealityView.h | 2 +- .../qSlicerMixedRealityModuleWidget.cxx | 46 +++++++++-- .../qSlicerMixedRealityModuleWidget.h | 3 +- 8 files changed, 191 insertions(+), 42 deletions(-) diff --git a/MixedReality/Logic/vtkSlicerMixedRealityLogic.cxx b/MixedReality/Logic/vtkSlicerMixedRealityLogic.cxx index 6330a90..0caf06f 100644 --- a/MixedReality/Logic/vtkSlicerMixedRealityLogic.cxx +++ b/MixedReality/Logic/vtkSlicerMixedRealityLogic.cxx @@ -305,7 +305,7 @@ void vtkSlicerMixedRealityLogic::SetMixedRealityActive(bool activate) { if (this->GetMixedRealityConnected() && this->GetMixedRealityViewNode() - /* && this->GetMixedRealityViewNode()->HasError() */) + && this->GetMixedRealityViewNode()->HasError()) { // If it is connected already but there is an error then disconnect first then reconnect // as the error may be resolved by reconnecting. diff --git a/MixedReality/MRML/vtkMRMLMixedRealityViewNode.cxx b/MixedReality/MRML/vtkMRMLMixedRealityViewNode.cxx index 5340aa5..a56abdb 100644 --- a/MixedReality/MRML/vtkMRMLMixedRealityViewNode.cxx +++ b/MixedReality/MRML/vtkMRMLMixedRealityViewNode.cxx @@ -137,3 +137,33 @@ bool vtkMRMLMixedRealityViewNode::SetAndObserveReferenceViewNode(vtkMRMLViewNode this->SetAndObserveReferenceViewNodeID(node->GetID()); return true; } + +//---------------------------------------------------------------------------- +bool vtkMRMLMixedRealityViewNode::HasError() +{ + return !this->LastErrorMessage.empty(); +} + +//---------------------------------------------------------------------------- +void vtkMRMLMixedRealityViewNode::ClearError() +{ + this->SetError(""); +} + +//---------------------------------------------------------------------------- +void vtkMRMLMixedRealityViewNode::SetError(const std::string& errorText) +{ + if (this->LastErrorMessage == errorText) + { + // no change + return; + } + this->LastErrorMessage = errorText; + this->Modified(); +} + +//---------------------------------------------------------------------------- +std::string vtkMRMLMixedRealityViewNode::GetError() const +{ + return this->LastErrorMessage; +} diff --git a/MixedReality/MRML/vtkMRMLMixedRealityViewNode.h b/MixedReality/MRML/vtkMRMLMixedRealityViewNode.h index 8715448..113ccdc 100644 --- a/MixedReality/MRML/vtkMRMLMixedRealityViewNode.h +++ b/MixedReality/MRML/vtkMRMLMixedRealityViewNode.h @@ -75,6 +75,18 @@ class VTK_SLICER_MIXEDREALITY_MODULE_MRML_EXPORT vtkMRMLMixedRealityViewNode vtkSetMacro(PlayerIPAddress, const std::string); vtkGetMacro(PlayerIPAddress, std::string); + /// Return true if an error has occurred. + bool HasError(); + + /// Clear error state. + void ClearError(); + + /// Set error message. Non-empty string means that an error has occurred. + void SetError(const std::string& errorText); + + /// Get error message. Non-empty string means that an error has occurred. + std::string GetError() const; + protected: vtkMRMLMixedRealityViewNode(); ~vtkMRMLMixedRealityViewNode() override; @@ -83,6 +95,8 @@ class VTK_SLICER_MIXEDREALITY_MODULE_MRML_EXPORT vtkMRMLMixedRealityViewNode std::string PlayerIPAddress; + std::string LastErrorMessage; + static const char* ReferenceViewNodeReferenceRole; }; diff --git a/MixedReality/Resources/UI/qSlicerMixedRealityModuleWidget.ui b/MixedReality/Resources/UI/qSlicerMixedRealityModuleWidget.ui index b26e6e3..e1fc679 100644 --- a/MixedReality/Resources/UI/qSlicerMixedRealityModuleWidget.ui +++ b/MixedReality/Resources/UI/qSlicerMixedRealityModuleWidget.ui @@ -21,14 +21,85 @@ - + - PlayerIPAddress + Connect to hardware: - + + + + + + + + 999.999.999.999 + + + + + + + + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 190 + 190 + 190 + + + + + + + + + + + + + + + + + Enable rendering: + + + + + @@ -55,6 +126,11 @@
qSlicerWidget.h
1 + + ctkCheckBox + QCheckBox +
ctkCheckBox.h
+
ctkCollapsibleButton QWidget diff --git a/MixedReality/Widgets/qMRMLMixedRealityView.cxx b/MixedReality/Widgets/qMRMLMixedRealityView.cxx index 4a67119..9d4d5c2 100644 --- a/MixedReality/Widgets/qMRMLMixedRealityView.cxx +++ b/MixedReality/Widgets/qMRMLMixedRealityView.cxx @@ -284,10 +284,10 @@ void qMRMLMixedRealityViewPrivate::updateWidgetFromMRML() { this->destroyRenderWindow(); } -// if (this->MRMLMixedRealityViewNode) -// { -// this->MRMLMixedRealityViewNode->ClearError(); -// } + if (this->MRMLMixedRealityViewNode) + { + this->MRMLMixedRealityViewNode->ClearError(); + } return; } @@ -296,12 +296,12 @@ void qMRMLMixedRealityViewPrivate::updateWidgetFromMRML() QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); this->createRenderWindow(); QApplication::restoreOverrideCursor(); -// if (!q->isHardwareConnected()) -// { -// this->MRMLMixedRealityViewNode->SetError("Connection failed"); -// return; -// } -// this->MRMLMixedRealityViewNode->ClearError(); + if (!q->isHardwareConnected()) + { + this->MRMLMixedRealityViewNode->SetError("Connection failed"); + return; + } + this->MRMLMixedRealityViewNode->ClearError(); } if (this->DisplayableManagerGroup->GetMRMLDisplayableNode() != this->MRMLMixedRealityViewNode.GetPointer()) @@ -380,14 +380,14 @@ void qMRMLMixedRealityViewPrivate::updateWidgetFromMRML() // } // } -// if (this->MRMLMixedRealityViewNode->GetActive()) -// { + if (this->MRMLMixedRealityViewNode->GetActive()) + { this->MixedRealityLoopTimer.start(0); -// } -// else -// { -// this->MixedRealityLoopTimer.stop(); -// } + } + else + { + this->MixedRealityLoopTimer.stop(); + } } //--------------------------------------------------------------------------- @@ -731,20 +731,20 @@ void qMRMLMixedRealityView::getDisplayableManagers(vtkCollection* displayableMan } //------------------------------------------------------------------------------ -//bool qMRMLMixedRealityView::isHardwareConnected()const -//{ -// vtkOpenVRRenderWindow* renWin = this->renderWindow(); -// if (!renWin) -// { -// return false; -// } +bool qMRMLMixedRealityView::isHardwareConnected()const +{ + vtkOpenXRRenderWindow* renWin = this->renderWindow(); + if (!renWin) + { + return false; + } // if (!renWin->GetHMD()) // { // return false; // } -// // connected successfully -// return true; -//} + // connected successfully + return true; +} //------------------------------------------------------------------------------ //void qMRMLMixedRealityView::setGrabObjectsEnabled(bool enable) diff --git a/MixedReality/Widgets/qMRMLMixedRealityView.h b/MixedReality/Widgets/qMRMLMixedRealityView.h index cd21ac4..3e5bbcf 100644 --- a/MixedReality/Widgets/qMRMLMixedRealityView.h +++ b/MixedReality/Widgets/qMRMLMixedRealityView.h @@ -96,7 +96,7 @@ class Q_SLICER_MODULE_MIXEDREALITY_WIDGETS_EXPORT qMRMLMixedRealityView : public // Q_INVOKABLE void updateViewFromReferenceViewCamera(); /// Get underlying RenderWindow -// Q_INVOKABLE bool isHardwareConnected()const; + Q_INVOKABLE bool isHardwareConnected()const; /// Enable/disable grabbing and moving objects in the scene // Q_INVOKABLE void setGrabObjectsEnabled(bool enable); diff --git a/MixedReality/qSlicerMixedRealityModuleWidget.cxx b/MixedReality/qSlicerMixedRealityModuleWidget.cxx index 610d758..9c10e99 100644 --- a/MixedReality/qSlicerMixedRealityModuleWidget.cxx +++ b/MixedReality/qSlicerMixedRealityModuleWidget.cxx @@ -65,7 +65,13 @@ void qSlicerMixedRealityModuleWidget::setup() d->setupUi(this); this->Superclass::setup(); - connect(d->PlayerIPAddressLineEdit, SIGNAL(textChanged(QString)), this, SLOT(setPlayerIPAddress(QString))); + connect(d->ConnectCheckBox, SIGNAL(toggled(bool)), this, SLOT(setMixedRealityConnected(bool))); + connect(d->RenderingEnabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(setMixedRealityActive(bool))); + + this->updateWidgetFromMRML(); + + // If virtual reality logic is modified it indicates that the view node may changed + qvtkConnect(logic(), vtkCommand::ModifiedEvent, this, SLOT(updateWidgetFromMRML())); } //-------------------------------------------------------------------------- @@ -76,18 +82,40 @@ void qSlicerMixedRealityModuleWidget::updateWidgetFromMRML() vtkSlicerMixedRealityLogic* xrLogic = vtkSlicerMixedRealityLogic::SafeDownCast(this->logic()); vtkMRMLMixedRealityViewNode* xrViewNode = xrLogic->GetMixedRealityViewNode(); - bool wasBlocked = d->PlayerIPAddressLineEdit->blockSignals(true); - d->PlayerIPAddressLineEdit->setText(QString::fromStdString(xrViewNode->GetPlayerIPAddress())); + bool wasBlocked = d->ConnectCheckBox->blockSignals(true); + d->ConnectCheckBox->setChecked(xrViewNode != nullptr && xrViewNode->GetVisibility()); + d->ConnectCheckBox->blockSignals(wasBlocked); + + wasBlocked = d->PlayerIPAddressLineEdit->blockSignals(true); + if (xrViewNode != nullptr) + { + d->PlayerIPAddressLineEdit->setText(QString::fromStdString(xrViewNode->GetPlayerIPAddress())); + } d->PlayerIPAddressLineEdit->blockSignals(wasBlocked); + + QString errorText; + if (xrViewNode && xrViewNode->HasError()) + { + errorText = xrViewNode->GetError().c_str(); + } + d->ConnectionStatusLabel->setText(errorText); + + wasBlocked = d->RenderingEnabledCheckBox->blockSignals(true); + d->RenderingEnabledCheckBox->setChecked(xrViewNode != nullptr && xrViewNode->GetActive()); + d->RenderingEnabledCheckBox->blockSignals(wasBlocked); } //----------------------------------------------------------------------------- -void qSlicerMixedRealityModuleWidget::setPlayerIPAddress(const QString& value) +void qSlicerMixedRealityModuleWidget::setMixedRealityConnected(bool connect) { + Q_D(qSlicerMixedRealityModuleWidget); vtkSlicerMixedRealityLogic* xrLogic = vtkSlicerMixedRealityLogic::SafeDownCast(this->logic()); - vtkMRMLMixedRealityViewNode* xrViewNode = xrLogic->GetMixedRealityViewNode(); - if (xrViewNode) - { - xrViewNode->SetPlayerIPAddress(value.toStdString()); - } + xrLogic->SetMixedRealityConnected(connect, d->PlayerIPAddressLineEdit->text().toStdString()); +} + +//----------------------------------------------------------------------------- +void qSlicerMixedRealityModuleWidget::setMixedRealityActive(bool activate) +{ + vtkSlicerMixedRealityLogic* xrLogic = vtkSlicerMixedRealityLogic::SafeDownCast(this->logic()); + xrLogic->SetMixedRealityActive(activate); } diff --git a/MixedReality/qSlicerMixedRealityModuleWidget.h b/MixedReality/qSlicerMixedRealityModuleWidget.h index a6ba076..9a6e819 100644 --- a/MixedReality/qSlicerMixedRealityModuleWidget.h +++ b/MixedReality/qSlicerMixedRealityModuleWidget.h @@ -40,7 +40,8 @@ class Q_SLICER_QTMODULES_MIXEDREALITY_EXPORT qSlicerMixedRealityModuleWidget : virtual ~qSlicerMixedRealityModuleWidget(); public slots: - void setPlayerIPAddress(const QString& value); + void setMixedRealityConnected(bool connect); + void setMixedRealityActive(bool activate); protected slots: void updateWidgetFromMRML();