1
""" Defines the TraitsTool and Fifo classes, and get_nested_components90
4
# Enthought library imports
5
from enable.api import BaseTool, Container
6
from traits.api import List, Dict, Str
9
from chaco.api import PlotAxis, ColorBar
13
""" Slightly-modified version of the Fifo class from the Python cookbook:
14
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68436
20
def append(self, value):
21
self.data[self.nextin] = value
23
def extend(self, values):
25
for i,val in enumerate(values):
26
self.data[i+self.nextin] = val
29
return self.nextout >= self.nextin
31
value = self.data[self.nextout]
32
del self.data[self.nextout]
37
def get_nested_components(container, classes):
38
""" Returns a list of fundamental plotting components from a container
39
with nested containers.
41
Performs a breadth-first search of the containment hierarchy. Each element
42
in the returned list is a tuple (component, (x,y)) where (x,y) is the
43
coordinate frame offset of the component from the top-level container.
47
worklist.append((container, (0,0)))
49
item, offset = worklist.pop()
50
if isinstance(item, Container):
51
new_offset = (offset[0]+item.x, offset[1]+item.y)
52
for c in item.components:
53
worklist.append((c, new_offset))
54
for overlay in item.overlays + item.underlays:
55
components.append((overlay, offset))
56
elif any([isinstance(item, klass) for klass in classes]):
57
components.append((item, offset))
58
for overlay in item.overlays + item.underlays:
59
components.append((overlay, offset))
60
if worklist.isempty():
65
class TraitsTool(BaseTool):
66
""" Tool to edit the traits of plots, grids, and axes.
69
# This tool does not have a visual representation (overrides BaseTool).
71
# This tool is not visible (overrides BaseTool).
74
# The classes of components that should trigger a traits view
75
classes = List([PlotAxis, ColorBar])
77
# A dict of Class : View providing alternate views for a particular component
80
# The event to trigger the edit on
81
event = Str('left_dclick')
83
def _dispatch_stateful_event(self, event, suffix):
84
"""If the event type matches the specification in *event*, look for a component that
85
matches one of the classes in *classes* in our containment hierarchy. If one is found,
86
edit it using either the default editor, or an alternate editor specified in *views*
88
if suffix != self.event:
94
# First determine what component or components we are going to hittest
95
# on. If our component is an Axis or PlotRenderer of any sort,
96
# then that is the only candidate. If our component is a container,
97
# then we add its non-container components to the list of candidates;
98
# any nested containers are lower priority than primary plot components.
99
candidates = get_nested_components(self.component, [Container] + self.classes)
101
# Hittest against all the candidate and take the first one
103
for candidate, offset in candidates:
104
if candidate.is_in(x-offset[0], y-offset[1]):
109
self.component.active_tool = self
110
if item.__class__ in self.views:
111
item.edit_traits(kind="livemodal",
112
view=self.views[item.__class__],
113
parent=event.window.control)
115
item.edit_traits(kind="livemodal",
116
parent=event.window.control)
118
self.component.active_tool = None
119
item.request_redraw()