3
-----------------------------------------------------------------------------
5
This doc describes the way that events from Enable are propagated through
6
the Chaco object stack. It assumes that the reader is familiar with the
7
way Enable dispatches events from the top-level Window to containers and
10
Plot interactions in Chaco are implemented as "tools". A Tool has state
11
and responds to events. Technically, this covers just about everything
12
in Chaco, since anything that subclasses PlotComponent can respond to
13
events, and most objects in Chaco are stateful. However, Tools are a
14
special kind of PlotComponent that generally to handle events on
15
*other* components, and draw as overlays on other components.
19
-----------------------------------------------------------------------------
21
There are two types of interactors in the Chaco world: captive tools and
22
listeners. Captive tools "capture" the user's focus, and give the distinct
23
impression that the user is performing a single, particular task through
24
using the tool. In general, only a single captive tool can be active at
25
the same time on a component. Listeners, on the other hand, respond to events in
26
ways that don't "capture" the user's focus or require a stateful sequence of
27
interactions. Many listeners can be enabled at the same time, and their
28
individual behaviors don't interfere with one another.
30
Examples of listener tools are tools that draw crosshairs or guide lines,
31
tools that print out the cursor location, and other inspection tools.
32
Examples of captive tools are panning/scrolling interactors, drawing tools,
33
and stateful selection tools (lasso, box, etc.). The key difference is
34
that most captive tools can't (or shouldn't) be interrupted by other captive
35
tools consuming the events.
37
Most captive tools actually have a listener component to them, since they
38
become activated through user interactions. (If the tools are being
39
managed by some external component like a toolbar, then this doesn't
40
apply.) For instance, a rectangular zoom box tool will be waiting for
41
a drag operation before it can become the active tool and "capture" the
42
user's further actions. In these cases, the tool should have a "listening"
43
state, and activate itself when it gets certain events. However, in order to
44
cooperate with other tools, tools should never activate themselves if there
45
is already an active_tool defined.
48
PlotComponent event handling
49
-----------------------------------------------------------------------------
51
Every PlotComponent has two tool-related attributes: "tools", and
52
"active_tool". When a PlotComponent receives an event, by default, it passes
53
that event on to all of the tools in its list. Regardless of how each
54
tool flags event.handled, all of the tools in the list will get a notification.
55
These tools are referred to as "listeners" because while they might modify
56
state elsewhere in the application (e.g. updating values on a status bar,
57
setting the tooltip at the cursor, etc.), they don't represent a stateful,
58
"captive" interaction with the user.
60
In contrast, if a PlotComponent has an active_tool, then it passes all
61
received events on to that tool. The active_tool gets a chance to handle
62
the event, and after it returns, if the event's "handled" attribute is set,
63
then event propagation is terminated. In this way, the active tool has
64
complete control over the user interaction, and can veto events from reaching
67
In addition to all this, PlotComponents participate in the "normal" event
68
propagation that all Enable widgets have. The exact order of event handling
78
Container event handling
79
-----------------------------------------------------------------------------
81
By default, Enable containers only offset the coordinate systems of their
82
contained components and do simple bounding-box culling of possible listeners
83
for any given event. Since Chaco containers frequently have a large amount of
84
interesting state that user tools should be able to manipulate,
85
BasePlotContainer hooks into the _container_handle_mouse_event() dispatch
86
method (defined in the base class enable.Container) and explicitly calls
87
the _dispatch_stateful_event() defined in Interactor, which converts mouse
88
events into the familiar "self.normal_mouse_move()"-type of calls.