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.
The return value here is important when multiple operators are active. Multiple operators live in an operator stack (see this section 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:
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 update notifiers.
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:
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.
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.
Reverse mouse wheel zoom
Here's another example. This one shows how you'd override the OnMouseWheel function to reverse the direction of zoom when scrolling with the mouse wheel:
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.