InteractorChains

InteractorChains is a sample program that illustrates how to chain interactors. It defines a class, TClickOrDragInteractor, that is started when the mouse is clicked and runs either of two other interactors, depending on whether the mouse is double-clicked or moved. These two interactors are generic interactors and have no special knowledge of TClickOrDragInteractor.

Running the sample

Execute InteractorChainsSApp, and click in the view. If the power key is down, the SetColorInteractor is started. It will change the color and leave it set until it is released, at which point it will set it back. If the second power key is down (and the power key is not), the SetPointInteractor is started. It causes the view to report the mouse point while the mouse is held down. If neither modifier key is down, the TClickOrDragInteractor is started, with each of the other interactors as child interactors. Depending on whether the next event is a double-click or a move, either child interactor is started. A double-click starts the set-color interactor, and a drag starts the set-point interactor. Click Close to quit.

Files and classes

TGraphicView is defined in GraphicView.h and GraphicView.C. It is basically the same as the version in MouseInteractors, except it implements MouseDown to start one of the three interactors.

TClickOrDragInteractor is defined in ClickOrDragInteractor.h and ClickOrDragInteractor.C This code illustrates how to write a root interactor that can switch between child interactors and delegate to them.

TSetColorInteractor is defined in SetColorInteractor.h and SetColorInteractor.C. It is a standard interactor, like the one in MouseInteractors. It uses SetColor protocol on TGraphicView to set the color of the view.

TSetPointInteractor is defined in SetPointInteractor.h and SetPointInteractor.C. It is a standard interactor, like the one in MouseInteractors. It uses SetPoint protocol on TGraphicView to set the point that the view displays.

Notes

If you want to compose interactors, you must chain them. In this example, once either of the two subinteractors is started, there is no going back, so you might expect to be able to simply start them using TEvent::StartInteractor. However, this causes an assertion failure, so the first interactor must remain in the loop forwarding events to the subinteractor. This makes it easier for the input system to clean up when the interactor terminates, and makes it possible for the first interactor to regain control from the subinteractor in situations where that is appropriate.

In this example, the ClickOrDragInteractor starts another interactor when the mouse is moved. However, for that interactor to receive mouse-moved events, StartMouseMovedEvents must first be called on its MMouseEventHandler. There are two approaches you can take. Either the first interactor calls StartMouseMovedEvents on the second interactor, or it constructs a TMouseDownEvent and distributes it to the second interactor before distributing the real TMouseMovedEvent (letting the second interactor call StartMouseMovedEvents on itself if it chooses). Each approach requires that the first interactor knows the semantics of the second interactor.

In order for the primary interactor to behave properly, it must own its subinteractor and delete it when the subinteractor is finished, which can happen after any event is dispatched to the subinteractor. It must also handle activate and deactivate requests and distribute them to the subinteractor.


Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.