It is a common situation that a Widget needs some extra behaviour that would require deriving a new widget class and overriding some of the virtual functions.
For example, one would want to limit the size of a widget to a certain maximum, or make the widget rotate towards the hands of the user. It is also very common that the same behaviour is required over and over again.
Operators provide a way to enrich widget behaviour without having to create new widget classes. This makes it a very flexible way to add functionality to any existing widget. This kind of behaviour-adding is known as the Decorator design pattern.
In many cases the new behaviour is related to animating some of the widgets attributes (location, scale, rotation, etc). For this purpose there is a special category of operators called Animators, which are explained more thoroughly in the Animations-section.
Operators always operate on a host MultiWidgets::Widget which is the target of the operations and the operator is attached to the widget it manipulates. The host widget assumes the ownership of the operator and makes sure the operator is deleted when the widget gets deleted.
All operators are derived from MultiWidgets::Operator class. Here are the two main functions of the class:
Both functions are by default empty and are overloaded in derived classes. The host widget is given as a reference which can therefore be targeted for the wanted behaviour. In most cases the operator logic is inside the update function, which is called after widgets motion for that frame has been updated. This way the operator can react immediately to new coordinates before they are rendered on the screen.
Operators are added to widgets using the addOperator-method, which takes a shared pointer of the operator as an argument. Use std::make_shared to create the operator. The widget takes care of the instance after that, making sure it is cleaned up properly.
Some of the operators are usually added at the time of widget creation. For example, it might be meaningful to limit the possible scale of the widget. This could be achived using a MultiWidgets::LimitScaleOperator.
Some of the operators are usually added as a result of some event such as user input or timed event. Following code might be added as a result for some user input, which would remove the widget after certain timeout.
There is no limit how many operators can be added to a widget. Single operators are usually quite simple but by adding multiple operators it is possible to achieve more complex behaviour. List of standard operators implemented in Cornerstone can be found in the MultiWidgets-namespace.
Creating a new operator is quite easy and straightforward:
Notice that if the host widget class has overloaded it's update-method, it is possible that the widget implementation starts to "fight against" an operator. This would be the case when both the widget and the operator want to change same attribute into different directions. This can show up as a strange behaviour.
It is also recommended that you create a plugin from the operator. This makes the serialization work for your operators. Creating a plugin is very easy, just add following macro to your operator source file: