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