
CHAPTER 4 Structured Graphics

You may have already noticed that FiggyViewer does not itself define the handle() operation. Instead, it inherits its handle() behavior from ViewerImpl which is responsible for calling the press(), drag(), and release() operations defined by FiggyViewer.
For our purposes, the behavior of ViewerImpl::handle() can be summarized as follows. (Recall that the ViewerImpl and FiggyViewer are one and the same object.) If the incoming event is a down-click, the viewer establishes an event filter (causing the window to dispatch to it all subsequent events until the filter is removed) and then it calls press() on itself. This executes the code shown in figure 4-14 below. If, instead, the incoming event is a motion event, then the viewer calls drag() on itself. Finally, if the event is an up-click, then the viewer calls release(), and then it removes the event filter, allowing the window to dispatch events in its normal fashion. (The window will start doing pick traversals again and again looking for interested viewers in which to call handle.)
Let's examine FiggyViewer's press() code (figure 4-14) in the context of clicking and dragging an existing circle.
Recall that the handle() operation (figure 4-13) calls press: the traversal object passed to line 1 is the same as that passed to handle(). It is not, however, the same traversal object passed to ViewerImpl::traverse of figure 4-12. Actually, in the click-drag case, the event handling process involves two PickTraversal objects. These are shown in figure 4-15. In fact, these traversals are shown in their actual state when FiggyViewer::press is called.
Recall that at the start of the event handling process, the window needed to do a pick traversal looking for a viewer in which to dispatch events (by calling handle on it). PickTraversal-A is traversal the window uses for this purpose. It was thus the traversal passed to the traverse() call on the window's main viewer and the one that eventually made it to the ViewerImpl::traverse operation of figure 4-12.
PickTraversal-B was created as a result of the circle object's call to hit() on PickTraversal-A. (Recall from above that calling hit() on a pick traversal results in a copy of the traversal being made and then inserted into a chain.) Thus PickTraversal-B represents a trail all the way down to the circle leaf node. And this is the traversal passed to line 1 in figure 4-14 above.
Note that PickTraversal-A represents a trail to nothing. This is because, at the point in time where the Window calls handle() on the FiggyViewer, the traversal had worked its way back up the structure to the main viewer. Thus all the levels have been popped from PickTraversal-A's stack at this point.
So, because the circle object registered a hit during traversal, it is PickTraversal-B that is passed to the press() operation. The press() operation needs to determine if a figure (e.g., the circle) has been hit. It does this using line 4 shown here.
Boolean picked = t->forward();The forward() operation advances the current position of a traversal. If the current position is already at the end of the traversal, then forward() returns false. Upon the call to press(), the current position is at the viewer that filtered events. This is the level labeled FiggyViewer in figure 4-15. Since there are more levels below, the call to forward() returns true indicating that a figure has indeed been picked. The while loop on line 6 advances the current level to the end so that the glyph obtained on line 7 is the circle.
Now let's suppose, when the window initiated the pick traversal, that the mouse was above white space rather than being above the circle. In this case the circle would not register a hit, but, since the FiggyViewer is "opaque", the FiggyViewer would. This hit is shown in line 19 of figure 4-12 above. The PickTraversal object resulting from this hit, PickTraversal-C (shown in figure 4-16 below) is now passed to the press() operation rather than PickTraversal-B. This causes the call to forward() on line 4 to return false, and the code in the else clause of line 14 is executed.
Generated with CERN WebMaker