================
Custom Operators
================

Many developers wish to provide functionality in addition to what is available in the standard set of HOOPS Visualize operators. You can create a custom operator by subclassing ``HPS::Operator``. Your subclass should then implement the virtual methods required to achieve the desired functionality. A Visualize operator can override any of the mouse, keyboard, or touch-screen handlers simultaneously.

The example below shows how to write an operator to detect when the user clicks the left mouse button while holding the control key.


Step 1: Infrastructure
----------------------

The first step to processing input events is to make a subclass for your operator and implement ``OnMouseDown``. In this example. we'll use the generic class name ``MyCustomOperator``. The ``MouseState`` is passed in to your method by Visualize and contains information related to the event.

.. tabs::

	.. group-tab:: C++
	
		.. code-block:: cpp
		
			bool MyCustomOperator::OnMouseDown(HPS::MouseState const & in_state)
			{
				// implementation details go here - see Step 2
				
				return true;
			}
		   
	.. group-tab:: C#
		
		.. code-block:: c#
		
			class MyCustomOperator : HPS.Operator
			{
			 public override bool OnMouseDown(HPS.MouseState in_state)
				{
					// implementation details go here - see Step 2
					return true;
				}
			}

The return value here is important when multiple operators are active. Multiple operators live in an operator stack (see :doc:`this section <0601_standard_operators>` for more information). The operator that was attached to the view most recently receives the input event first, and has the option to process and consume the event or pass it on to the next operator. When returning ``true``, the event is consumed. Returning ``false`` means Visualize should pass this event on to the next operator in the stack.


Step 2: Get the Information Provided by the HPS::MouseState.
------------------------------------------------------------

When handing a mouse event, HOOPS Visualize will pass a ``HPS::MouseState`` object to your hander function. If you need to detect, for example, when the user has clicked the left mouse button while holding the CTRL key, you could use the following code:

.. tabs::

	.. group-tab:: C++
	
		.. code-block:: cpp
	
			if (in_state.GetButtons().Left()) 
			{
				if (in_state.GetModifierKeys().Control()) 
				{
					// perform your logic
				}
			}
		   
	.. group-tab:: C#
	
		.. code-block:: c#

			if (in_state.GetButtons().Left()) 
			{
				if (in_state.GetModifierKeys().Control()) 
				{
					// perform your logic
				}
			}

**IMPORTANT:** The State objects passed to the event handlers (for example, ``HPS::MouseState``) all describe the state of the device *at the time the event is processed*. Subsequently, if you try to handle a "mouse button up" event, and inspect the ``HPS::MouseState``, you will find no buttons are active (since the event is processed AFTER the button has come up). If you need this information, you should get the original event from the ``HPS::MouseState`` object by calling ``MouseState::GetActiveEvent()``.

Visualize supports mice of up to 5 buttons. The code example above only tests for ``LeftButton``, however, the ``RightButton`` and ``MiddleButton`` enums are also present. The 4th and 5th mouse buttons use the ``XButton1`` and ``XButton2`` enums.


Updating the Display in Response to User Input
----------------------------------------------

Certain events, such as those generated by a mouse move, a touch move, or a timer tick, are often generated rapidly in succession. If your operator includes a display update as part of its logic, you should use synchronous updates to avoid the appearance of the display "lagging behind" the events. Synchronous updates are generated using :ref:`update notifier <prog_guide/0701_rendering:Update notification>`.


.. _touch_events:

Interpreting Touch-Screen Events
================================

``HPS::Operator`` has three overridable methods associated with touch-screen events, ``OnTouchUp``, ``OnTouchDown``, and ``OnTouchMove``. They are handled in the same fashion as the mouse events in the code snippets above. There is no touch-drag event in Visualize. If you need to interpret a touch-drag event, you would need to handle ``OnTouchDown``, set a flag, and then examine the state of the flag in ``OnTouchMove``.

Often, a user will interact with a touch screen using more than one finger. For this reason, examining all touch locations is important. For example, one common action is to pinch two fingers together to zoom out of a scene. For this operation, your operator might compute the distance between the fingers to determine if it is increasing or decreasing, and also compute the midpoint so that the scene could be zoomed around the proper 3D point. Visualize provides methods to get the information needed to complete this action:

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00701_operator_example_step2.cpp
		   :start-after: //! [MyCustomOperator_step2]
		   :end-before: //! [MyCustomOperator_step2]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00701_operator_example_step2.cs
		   :start-after: //! [MyCustomOperator_step2]
		   :end-before: //! [MyCustomOperator_step2]


Avoid Camera Pitfalls When Working With Operators
-------------------------------------------------
An operator is designed to act on a ``View`` object. As the view is backed by a segment, any transformations applied to the scene by the operator are ultimately made manifest by changing the segment's camera. Recall that a camera is an attribute of a segment. As such, it is inherited by subsegments until another segment overrides the camera with its own. Thus, if there happens to be a second camera further down in the segment tree, the geometry viewed by that camera will not be transformed by the current operator. If you try to use an operator and find it is not affecting the scene the way you expect, inspect the segment hierarchy for other cameras that may be overriding the effect of the operator transformation.


.. _mouse_example:

Mouse Operator Example
======================

To sum up everything in this section, we'll create a custom operator that can be used to create a sphere. The user clicks to set the center point and drags to a different spot to set the radius.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_create_sphere_op.cpp
		   :start-after: //! [operator]
		   :end-before: //! [operator]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_create_sphere_op.cs
		   :start-after: //! [operator]
		   :end-before: //! [operator]
		   

.. _touch_example:

Touch-Screen Operator Example
=============================

This example accomplishes the same task as the example about creating a sphere, but is oriented toward developers of touch-screen applications. The user clicks to set the center point and drags to a different spot to set the radius.

.. tabs::

	.. group-tab:: C++
	
		.. literalinclude:: ../../../internals/tests/docs/source/cpp/00700_create_sphere_touch_op.cpp
		   :start-after: //! [operator]
		   :end-before: //! [operator]
		   
	.. group-tab:: C#

		.. literalinclude:: ../../../internals/tests/docs/source/cs/00700_create_sphere_touch_op.cs
		   :start-after: //! [operator]
		   :end-before: //! [operator]
		   