2
from enable.api import BaseTool, ColorTrait
3
from traits.api import Any, Bool, Dict, Enum, HasTraits, Int, List, Trait, Tuple
5
class RangeController(HasTraits):
9
# The list of active plots and which of their ranges was set
12
# Stores the old ranges
15
def notify(self, axistool, rangename, type, event):
16
plot = axistool.component
17
range = getattr(plot, rangename)
18
if (type == "down") and ((plot, rangename) not in self.plots_ranges):
19
if len(self.plots_ranges) > 0:
20
src_plot, src_rangename = self.plots_ranges[0]
21
src_range = getattr(src_plot, src_rangename)
22
self.link(src_range, plot, rangename)
23
self.plots_ranges.append((plot, rangename))
25
if (plot, rangename) in self.plots_ranges:
26
if len(self.plots_ranges) > 1:
27
self.unlink(plot, rangename)
28
self.plots_ranges.remove((plot, rangename))
31
def link(self, src_range, dst_plot, dst_rangename):
32
self._ranges[(dst_plot, dst_rangename)] = getattr(dst_plot, dst_rangename)
33
setattr(dst_plot, dst_rangename, src_range)
34
dst_plot.request_redraw()
36
def unlink(self, plot, rangename):
37
setattr(plot, rangename, self._ranges.pop((plot, rangename)))
41
class AxisTool(BaseTool):
43
# The object to notify when we've been clicked
44
# We notify by calling its .notify method, which should have the
46
# should_handle_event = notify(axis_tool, axis, down_or_up, event)
48
# It should return a bool indicating whether or not we should process the
50
range_controller = Any
52
down_tick_color = ColorTrait("red")
53
down_axis_line_color = ColorTrait("red")
54
down_tick_label_color = ColorTrait("red")
55
down_bgcolor = ColorTrait("lightgray")
56
down_border_visible = Bool(True)
57
down_border_color = Trait(None, None, ColorTrait)
59
_cached_tick_color = ColorTrait
60
_cached_axis_line_color = ColorTrait
61
_cached_tick_labl_color = ColorTrait
62
_cached_bgcolor = ColorTrait
63
_cached_border_visible = Bool(True)
64
_cached_border_color = ColorTrait
66
attr_list = ("tick_color", "axis_line_color", "tick_label_color", "bgcolor",
67
"border_visible", "border_color")
69
def normal_left_down(self, event):
70
if self.component is None:
73
if plot.index_axis.is_in(event.x, event.y):
74
axis = plot.index_axis
75
rangename = "index_range"
76
elif plot.value_axis.is_in(event.x, event.y):
77
axis = plot.value_axis
78
rangename = "value_range"
82
# If we have a controller, we let it decide whether
83
# or not we get to handle the event.
84
if self.range_controller is not None:
85
should_handle = self.range_controller.notify(self, rangename, "down", event)
89
for attr in self.attr_list:
90
cached = "_cached_" + attr
92
setattr(self, cached, getattr(axis, attr))
93
if getattr(self, down) is not None:
94
setattr(axis, attr, getattr(self, down))
101
def normal_left_up(self, event):
102
if self.component is None:
104
plot = self.component
105
if plot.index_axis.is_in(event.x, event.y):
106
axis = plot.index_axis
107
rangename = "index_range"
108
elif plot.value_axis.is_in(event.x, event.y):
109
axis = plot.value_axis
110
rangename = "value_range"
114
if self.range_controller is not None:
115
should_handle = self.range_controller.notify(self, rangename, "up", event)
116
if not should_handle:
119
for attr in self.attr_list:
120
cached = "_cached_" + attr
121
setattr(axis, attr, getattr(self, cached))
123
axis.request_redraw()
128
class MPAxisTool(AxisTool):
131
_last_blob_pos = Tuple
133
def normal_blob_down(self, event):
134
if self.cur_bid == -1:
135
self.cur_bid = event.bid
136
if hasattr(event, "bid"):
137
event.window.capture_blob(self, event.bid,
138
event.net_transform())
139
self.normal_left_down(event)
140
self._last_blob_pos = (event.x, event.y)
142
def normal_blob_up(self, event):
144
if event.bid == self.cur_bid:
145
if hasattr(event, "bid"):
146
event.window.release_blob(event.bid)
148
event.x, event.y = self._last_blob_pos
149
self.normal_left_up(event)