3D Widgets: Difference between revisions
No edit summary |
No edit summary |
||
Line 144: | Line 144: | ||
Here, ValueInfo is responsible of getting Value from the (client-side) representation. Value and ValueInfo are linked (by the proxy at creation) so this change will be automatically reflected to the Value property. All the GUI has to do is to listen to the PropertyModifiedEvent and grab changes from the Value property. The GUI can also set the Value directly (make sure to call render afterwards otherwise the widget won't change). Any property pair defined liked this is automatically linked by the proxy at creation. All properties are updated when a EndInteractionEvent is invoked by the widget. | Here, ValueInfo is responsible of getting Value from the (client-side) representation. Value and ValueInfo are linked (by the proxy at creation) so this change will be automatically reflected to the Value property. All the GUI has to do is to listen to the PropertyModifiedEvent and grab changes from the Value property. The GUI can also set the Value directly (make sure to call render afterwards otherwise the widget won't change). Any property pair defined liked this is automatically linked by the proxy at creation. All properties are updated when a EndInteractionEvent is invoked by the widget. | ||
Here is how this all comes together in the example widget I added to paraview (GUI/Widget/vtkPVNew3DWidget.cxx). First, create the proxy and add observer: | |||
<pre> | |||
this->WidgetProxy = vtkSMNew3DWidgetProxy::SafeDownCast( | |||
vtkSMObject::GetProxyManager()->NewProxy( | |||
"displays", "SliderRepresentation")); | |||
// Force object creation | |||
this->WidgetProxy->UpdateVTKObjects(); | |||
this->WidgetProxy->AddObserver(vtkCommand::PropertyModifiedEvent, | |||
this->Observer); | |||
// Add to the render module. | |||
vtkSMRenderModuleProxy* rm = pvApp->GetRenderModuleProxy(); | |||
vtkSMProxyProperty* pp = vtkSMProxyProperty::SafeDownCast( | |||
rm->GetProperty("Displays")); | |||
pp->AddProxy(this->WidgetProxy); | |||
rm->UpdateVTKObjects(); | |||
</pre> | |||
Initialize the GUI and the widget from the property that is controlled (Resolution of the cone): | |||
<pre> | |||
void vtkPVNew3DWidget::Initialize() | |||
{ | |||
vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast( | |||
this->GetSMProperty()); | |||
this->EntryWidget->SetValueAsInt(ivp->GetElement(0)); | |||
vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Value")); | |||
dvp->SetElements1(ivp->GetElement(0)); | |||
this->WidgetProxy->UpdateVTKObjects(); | |||
this->GetPVApplication()->GetRenderModuleProxy()->StillRender(); | |||
} | |||
</pre> | |||
Switch the widget on/off when the cone source proxy is selected/deselected: | |||
<pre> | |||
//---------------------------------------------------------------------------- | |||
void vtkPVNew3DWidget::Select() | |||
{ | |||
if(this->WidgetProxy) | |||
{ | |||
vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Visibility")); | |||
ivp->SetElements1(1); | |||
vtkSMIntVectorProperty* enabled = vtkSMIntVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Enabled")); | |||
enabled->SetElements1(1); | |||
this->WidgetProxy->UpdateVTKObjects(); | |||
} | |||
} | |||
//---------------------------------------------------------------------------- | |||
void vtkPVNew3DWidget::Deselect() | |||
{ | |||
if(this->WidgetProxy) | |||
{ | |||
vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Visibility")); | |||
ivp->SetElements1(0); | |||
vtkSMIntVectorProperty* enabled = vtkSMIntVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Enabled")); | |||
enabled->SetElements1(0); | |||
this->WidgetProxy->UpdateVTKObjects(); | |||
} | |||
} | |||
</pre> | |||
If the 3D widget is modified, update the corresponding entry widget: | |||
<pre> | |||
void vtkPVNew3DWidget::WidgetModified() | |||
{ | |||
vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Value")); | |||
if (!dvp) | |||
{ | |||
return; | |||
} | |||
double val = dvp->GetElement(0); | |||
if (val != this->EntryWidget->GetValueAsDouble()) | |||
{ | |||
this->EntryWidget->SetValueAsDouble(val); | |||
this->ModifiedCallback(); | |||
} | |||
} | |||
</pre> | |||
If the entry widget is modified, update the 3D widget: | |||
<pre> | |||
void vtkPVNew3DWidget::EntryModifiedCallback(const char* key) | |||
{ | |||
vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast( | |||
this->WidgetProxy->GetProperty("Value")); | |||
if (!dvp) | |||
{ | |||
return; | |||
} | |||
if ((key && (!strcmp(key, "Tab") || | |||
!strcmp(key, "ISO_Left_Tab") || | |||
!strcmp(key, "Return") || | |||
!strcmp(key, ""))) || !key) | |||
{ | |||
double val = dvp->GetElement(0); | |||
double eVal = this->EntryWidget->GetValueAsDouble(); | |||
if (val != eVal) | |||
{ | |||
dvp->SetElements1(eVal); | |||
this->WidgetProxy->UpdateVTKObjects(); | |||
this->GetPVApplication()->GetRenderModuleProxy()->StillRender(); | |||
this->ModifiedCallback(); | |||
} | |||
} | |||
} | |||
</pre> |
Revision as of 12:51, 21 April 2006
Adding a (new style) 3D widget to SM requires writing 3 XML proxy definitions. Here is an example:
- Widget: The widget takes care of event handling and passing the right events to the representation. This is only instantiated on the client:
<Proxy name="SliderWidget" class="vtkSliderWidget"> <ProxyProperty name="Representation" command="SetRepresentation"> <ProxyGroupDomain name="groups"> <Group name="props" /> </ProxyGroupDomain> </ProxyProperty> <IntVectorProperty name="Enabled" command="SetEnabled" number_of_elements="1" default_values="0"> <BooleanDomain/> </IntVectorProperty> </Proxy>
Here, the Enabled property is required.
- Representation: Representation contains the actual geometry that is rendered and that is used for picking
<Proxy name="SliderRepresentation3D" class="vtkSliderRepresentation3D"> <IntVectorProperty name="Visibility" command="SetVisibility" number_of_elements="1" default_values="1" animateable="1"> <BooleanDomain name="bool" /> </IntVectorProperty> <DoubleVectorProperty name="Value" command="SetValue" number_of_elements="1" information_property="ValueInfo" default_values="0"> <DoubleRangeDomain name="range"/> </DoubleVectorProperty> <DoubleVectorProperty name="ValueInfo" command="GetValue" information_only="1"> <SimpleDoubleInformationHelper/> </DoubleVectorProperty> <DoubleVectorProperty name="Point1" command="SetPoint1InWorldCoordinates" number_of_elements="3" default_values="-1.0 0.0 0.0"> <DoubleRangeDomain name="range"/> </DoubleVectorProperty> <DoubleVectorProperty name="Point2" command="SetPoint2InWorldCoordinates" number_of_elements="3" default_values="1.0 0.0 0.0"> <DoubleRangeDomain name="range"/> </DoubleVectorProperty> <DoubleVectorProperty name="MinimumValue" command="SetMinimumValue" number_of_elements="1" default_values="0"> <DoubleRangeDomain name="range"/> </DoubleVectorProperty> <DoubleVectorProperty name="MaximumValue" command="SetMaximumValue" number_of_elements="1" default_values="1"> <DoubleRangeDomain name="range"/> </DoubleVectorProperty> </Proxy>
The Visibility property is required.
- Finally:
<New3DWidgetProxy name="SliderRepresentation"> <SubProxy> <Proxy name="Prop" proxygroup="props" proxyname="SliderRepresentation3D"> </Proxy> <ExposedProperties> <Property name="Visibility" /> <Property name="ValueInfo" /> <Property name="Value" /> <Property name="Point1" /> <Property name="Point2" /> <Property name="MinimumValue" /> <Property name="MaximumValue" /> </ExposedProperties> </SubProxy> <SubProxy> <Proxy name="Widget" proxygroup="3d_widgets" proxyname="SliderWidget"> </Proxy> <ExposedProperties> <Property name="Enabled" /> </ExposedProperties> </SubProxy> </New3DWidgetProxy> <!-- End of displays group --> </ProxyGroup>
The vtkSMNew3DWidgetProxy class takes care of managing the 3d widgets. It has to have 2 sub-proxies: Prop and Widget. These two must correspond to a vtkWidgetRepresentation and vtkAbstractWidget (like the two examples above). The Visibility and Enabled properties must be enabled. Once added to the render module, a vtkSMNew3DWidgetProxy object manages the widget and the representation. If a user interaction causes a change to the representation it manages, it updates the corresponding property. For this, one or more pairs of properties have to exist in the representation. For example:
<Proxy name="SliderRepresentation3D" class="vtkSliderRepresentation3D"> ... <DoubleVectorProperty name="Value" command="SetValue" number_of_elements="1" information_property="ValueInfo" default_values="0"> <DoubleRangeDomain name="range"/> </DoubleVectorProperty> <DoubleVectorProperty name="ValueInfo" command="GetValue" information_only="1"> <SimpleDoubleInformationHelper/> </DoubleVectorProperty> ... </Proxy>
Here, ValueInfo is responsible of getting Value from the (client-side) representation. Value and ValueInfo are linked (by the proxy at creation) so this change will be automatically reflected to the Value property. All the GUI has to do is to listen to the PropertyModifiedEvent and grab changes from the Value property. The GUI can also set the Value directly (make sure to call render afterwards otherwise the widget won't change). Any property pair defined liked this is automatically linked by the proxy at creation. All properties are updated when a EndInteractionEvent is invoked by the widget.
Here is how this all comes together in the example widget I added to paraview (GUI/Widget/vtkPVNew3DWidget.cxx). First, create the proxy and add observer:
this->WidgetProxy = vtkSMNew3DWidgetProxy::SafeDownCast( vtkSMObject::GetProxyManager()->NewProxy( "displays", "SliderRepresentation")); // Force object creation this->WidgetProxy->UpdateVTKObjects(); this->WidgetProxy->AddObserver(vtkCommand::PropertyModifiedEvent, this->Observer); // Add to the render module. vtkSMRenderModuleProxy* rm = pvApp->GetRenderModuleProxy(); vtkSMProxyProperty* pp = vtkSMProxyProperty::SafeDownCast( rm->GetProperty("Displays")); pp->AddProxy(this->WidgetProxy); rm->UpdateVTKObjects();
Initialize the GUI and the widget from the property that is controlled (Resolution of the cone):
void vtkPVNew3DWidget::Initialize() { vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast( this->GetSMProperty()); this->EntryWidget->SetValueAsInt(ivp->GetElement(0)); vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Value")); dvp->SetElements1(ivp->GetElement(0)); this->WidgetProxy->UpdateVTKObjects(); this->GetPVApplication()->GetRenderModuleProxy()->StillRender(); }
Switch the widget on/off when the cone source proxy is selected/deselected:
//---------------------------------------------------------------------------- void vtkPVNew3DWidget::Select() { if(this->WidgetProxy) { vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Visibility")); ivp->SetElements1(1); vtkSMIntVectorProperty* enabled = vtkSMIntVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Enabled")); enabled->SetElements1(1); this->WidgetProxy->UpdateVTKObjects(); } } //---------------------------------------------------------------------------- void vtkPVNew3DWidget::Deselect() { if(this->WidgetProxy) { vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Visibility")); ivp->SetElements1(0); vtkSMIntVectorProperty* enabled = vtkSMIntVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Enabled")); enabled->SetElements1(0); this->WidgetProxy->UpdateVTKObjects(); } }
If the 3D widget is modified, update the corresponding entry widget:
void vtkPVNew3DWidget::WidgetModified() { vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Value")); if (!dvp) { return; } double val = dvp->GetElement(0); if (val != this->EntryWidget->GetValueAsDouble()) { this->EntryWidget->SetValueAsDouble(val); this->ModifiedCallback(); } }
If the entry widget is modified, update the 3D widget:
void vtkPVNew3DWidget::EntryModifiedCallback(const char* key) { vtkSMDoubleVectorProperty* dvp = vtkSMDoubleVectorProperty::SafeDownCast( this->WidgetProxy->GetProperty("Value")); if (!dvp) { return; } if ((key && (!strcmp(key, "Tab") || !strcmp(key, "ISO_Left_Tab") || !strcmp(key, "Return") || !strcmp(key, ""))) || !key) { double val = dvp->GetElement(0); double eVal = this->EntryWidget->GetValueAsDouble(); if (val != eVal) { dvp->SetElements1(eVal); this->WidgetProxy->UpdateVTKObjects(); this->GetPVApplication()->GetRenderModuleProxy()->StillRender(); this->ModifiedCallback(); } } }