You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
6.4 KiB
C
204 lines
6.4 KiB
C
3 weeks ago
|
/*=========================================================================
|
||
|
|
||
|
Program: Visualization Toolkit
|
||
|
Module: vtkWidgetSet.h
|
||
|
|
||
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||
|
All rights reserved.
|
||
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||
|
|
||
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||
|
PURPOSE. See the above copyright notice for more information.
|
||
|
|
||
|
=========================================================================*/
|
||
|
/**
|
||
|
* @class vtkWidgetSet
|
||
|
* @brief Synchronize a collection on vtkWidgets drawn on different renderwindows using the
|
||
|
* Callback - Dispatch Action mechanism.
|
||
|
*
|
||
|
*
|
||
|
* The class synchronizes a set of vtkAbstractWidget(s). Widgets typically
|
||
|
* invoke "Actions" that drive the geometry/behaviour of their representations
|
||
|
* in response to interactor events. Interactor interactions on a render window
|
||
|
* are mapped into "Callbacks" by the widget, from which "Actions" are
|
||
|
* dispatched to the entire set. This architecture allows us to tie widgets
|
||
|
* existing in different render windows together. For instance a HandleWidget
|
||
|
* might exist on the sagittal view. Moving it around should update the
|
||
|
* representations of the corresponding handle widget that lies on the axial
|
||
|
* and coronal and volume views as well.
|
||
|
*
|
||
|
* @par User API:
|
||
|
* A user would use this class as follows.
|
||
|
* \code
|
||
|
* vtkWidgetSet *set = vtkWidgetSet::New();
|
||
|
* vtkParallelopipedWidget *w1 = vtkParallelopipedWidget::New();
|
||
|
* set->AddWidget(w1);
|
||
|
* w1->SetInteractor(axialRenderWindow->GetInteractor());
|
||
|
* vtkParallelopipedWidget *w2 = vtkParallelopipedWidget::New();
|
||
|
* set->AddWidget(w2);
|
||
|
* w2->SetInteractor(coronalRenderWindow->GetInteractor());
|
||
|
* vtkParallelopipedWidget *w3 = vtkParallelopipedWidget::New();
|
||
|
* set->AddWidget(w3);
|
||
|
* w3->SetInteractor(sagittalRenderWindow->GetInteractor());
|
||
|
* set->SetEnabled(1);
|
||
|
* \endcode
|
||
|
*
|
||
|
* @par Motivation:
|
||
|
* The motivation for this class is really to provide a usable API to tie
|
||
|
* together multiple widgets of the same kind. To enable this, subclasses
|
||
|
* of vtkAbstractWidget, must be written as follows:
|
||
|
* They will generally have callback methods mapped to some user
|
||
|
* interaction such as:
|
||
|
* \code
|
||
|
* this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent,
|
||
|
* vtkEvent::NoModifier, 0, 0, nullptr,
|
||
|
* vtkPaintbrushWidget::BeginDrawStrokeEvent,
|
||
|
* this, vtkPaintbrushWidget::BeginDrawCallback);
|
||
|
* \endcode
|
||
|
* The callback invoked when the left button is pressed looks like:
|
||
|
* \code
|
||
|
* void vtkPaintbrushWidget::BeginDrawCallback(vtkAbstractWidget *w)
|
||
|
* {
|
||
|
* vtkPaintbrushWidget *self = vtkPaintbrushWidget::SafeDownCast(w);
|
||
|
* self->WidgetSet->DispatchAction(self, &vtkPaintbrushWidget::BeginDrawAction);
|
||
|
* }
|
||
|
* \endcode
|
||
|
* The actual code for handling the drawing is written in the BeginDrawAction
|
||
|
* method.
|
||
|
* \code
|
||
|
* void vtkPaintbrushWidget::BeginDrawAction( vtkPaintbrushWidget *dispatcher)
|
||
|
* {
|
||
|
* // Do stuff to draw...
|
||
|
* // Here dispatcher is the widget that was interacted with, the one that
|
||
|
* // dispatched an action to all the other widgets in its group. You may, if
|
||
|
* // necessary find it helpful to get parameters from it.
|
||
|
* // For instance for a ResizeAction:
|
||
|
* // if (this != dispatcher)
|
||
|
* // {
|
||
|
* // double *newsize = dispatcher->GetRepresentation()->GetSize();
|
||
|
* // this->WidgetRep->SetSize(newsize);
|
||
|
* // }
|
||
|
* // else
|
||
|
* // {
|
||
|
* // this->WidgetRep->IncrementSizeByDelta();
|
||
|
* // }
|
||
|
* }
|
||
|
* \endcode
|
||
|
*
|
||
|
* @warning
|
||
|
* Actions are always dispatched first to the activeWidget, the one calling
|
||
|
* the set, and then to the other widgets in the set.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#ifndef vtkWidgetSet_h
|
||
|
#define vtkWidgetSet_h
|
||
|
|
||
|
#include "vtkInteractionWidgetsModule.h" // For export macro
|
||
|
#include "vtkObject.h"
|
||
|
#include <vector> // Required for vector
|
||
|
|
||
|
class vtkAbstractWidget;
|
||
|
|
||
|
// Pointer to a member function that takes a vtkAbstractWidget (the active
|
||
|
// child) and another vtkAbstractWidget (the widget to dispatch an action)
|
||
|
// to. All "Action" functions in a widget must conform to this signature.
|
||
|
template <class TWidget>
|
||
|
struct ActionFunction
|
||
|
{
|
||
|
typedef void (TWidget::*TActionFunctionPointer)(TWidget* dispatcher);
|
||
|
};
|
||
|
|
||
|
class VTKINTERACTIONWIDGETS_EXPORT vtkWidgetSet : public vtkObject
|
||
|
{
|
||
|
public:
|
||
|
/**
|
||
|
* Instantiate this class.
|
||
|
*/
|
||
|
static vtkWidgetSet* New();
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Standard methods for a VTK class.
|
||
|
*/
|
||
|
vtkTypeMacro(vtkWidgetSet, vtkObject);
|
||
|
void PrintSelf(ostream& os, vtkIndent indent) override;
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Method for activating and deactivating all widgets in the group.
|
||
|
*/
|
||
|
virtual void SetEnabled(vtkTypeBool);
|
||
|
vtkBooleanMacro(Enabled, vtkTypeBool);
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
* Add a widget to the set.
|
||
|
*/
|
||
|
void AddWidget(vtkAbstractWidget*);
|
||
|
|
||
|
/**
|
||
|
* Remove a widget from the set
|
||
|
*/
|
||
|
void RemoveWidget(vtkAbstractWidget*);
|
||
|
|
||
|
/**
|
||
|
* Get number of widgets in the set.
|
||
|
*/
|
||
|
unsigned int GetNumberOfWidgets();
|
||
|
|
||
|
/**
|
||
|
* Get the Nth widget in the set.
|
||
|
*/
|
||
|
vtkAbstractWidget* GetNthWidget(unsigned int);
|
||
|
|
||
|
// TODO: Move this to the protected section. The class vtkAbstractWidget
|
||
|
// should be a friend of this class.
|
||
|
typedef std::vector<vtkAbstractWidget*> WidgetContainerType;
|
||
|
typedef WidgetContainerType::iterator WidgetIteratorType;
|
||
|
typedef WidgetContainerType::const_iterator WidgetConstIteratorType;
|
||
|
WidgetContainerType Widget;
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Dispatch an "Action" to every widget in this set. This is meant to be
|
||
|
* invoked from a "Callback" in a widget.
|
||
|
*/
|
||
|
template <class TWidget>
|
||
|
void DispatchAction(
|
||
|
TWidget* caller, typename ActionFunction<TWidget>::TActionFunctionPointer action)
|
||
|
{
|
||
|
// Dispatch action to the caller first.
|
||
|
for (WidgetIteratorType it = this->Widget.begin(); it != this->Widget.end(); ++it)
|
||
|
{
|
||
|
TWidget* w = static_cast<TWidget*>(*it);
|
||
|
if (caller == w)
|
||
|
{
|
||
|
((*w).*(action))(caller);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
//@}
|
||
|
|
||
|
// Dispatch action to all other widgets
|
||
|
for (WidgetIteratorType it = this->Widget.begin(); it != this->Widget.end(); ++it)
|
||
|
{
|
||
|
TWidget* w = static_cast<TWidget*>(*it);
|
||
|
if (caller != w)
|
||
|
((*w).*(action))(caller);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
vtkWidgetSet();
|
||
|
~vtkWidgetSet() override;
|
||
|
|
||
|
private:
|
||
|
vtkWidgetSet(const vtkWidgetSet&) = delete;
|
||
|
void operator=(const vtkWidgetSet&) = delete;
|
||
|
};
|
||
|
|
||
|
#endif
|