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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
|
from __future__ import with_statement
from enable.api import Container, Component, ColorTrait
from kiva.constants import FILL, FILL_STROKE
from kiva.trait_defs.kiva_font_trait import KivaFont
from traits.api import Any, Bool, Delegate, Enum, Instance, Int, List, Str
class Button(Component):
color = ColorTrait("lightblue")
down_color = ColorTrait("darkblue")
border_color = ColorTrait("blue")
label = Str
label_font = KivaFont("modern 12")
label_color = ColorTrait("white")
down_label_color = ColorTrait("white")
button_state = Enum("up", "down")
# A reference to the radio group that this button belongs to
radio_group = Any
# Default size of the button if no label is present
bounds=[32,32]
# Generally, buttons are not resizable
resizable = ""
_got_mousedown = Bool(False)
def perform(self, event):
"""
Called when the button is depressed. 'event' is the Enable mouse event
that triggered this call.
"""
pass
def _draw_mainlayer(self, gc, view_bounds, mode="default"):
if self.button_state == "up":
self.draw_up(gc, view_bounds)
else:
self.draw_down(gc, view_bounds)
return
def draw_up(self, gc, view_bounds):
with gc:
gc.set_fill_color(self.color_)
gc.set_stroke_color(self.border_color_)
gc.draw_rect((int(self.x), int(self.y), int(self.width)-1, int(self.height)-1), FILL_STROKE)
self._draw_label(gc)
return
def draw_down(self, gc, view_bounds):
with gc:
gc.set_fill_color(self.down_color_)
gc.set_stroke_color(self.border_color_)
gc.draw_rect((int(self.x), int(self.y), int(self.width)-1, int(self.height)-1), FILL_STROKE)
self._draw_label(gc, color=self.down_label_color_)
return
def _draw_label(self, gc, color=None):
if self.label != "":
gc.set_font(self.label_font)
x,y,w,h = gc.get_text_extent(self.label)
if color is None:
color = self.label_color_
gc.set_fill_color(color)
gc.set_stroke_color(color)
gc.show_text(self.label, (self.x+(self.width-w-x)/2,
self.y+(self.height-h-y)/2))
return
def normal_left_down(self, event):
self.button_state = "down"
self._got_mousedown = True
self.request_redraw()
event.handled = True
return
def normal_left_up(self, event):
self.button_state = "up"
self._got_mousedown = False
self.request_redraw()
self.perform(event)
event.handled = True
return
class ToolbarButton(Button):
toolbar = Any
canvas = Delegate("toolbar")
def __init__(self, *args, **kw):
toolbar = kw.pop("toolbar", None)
super(ToolbarButton, self).__init__(*args, **kw)
if toolbar:
self.toolbar = toolbar
toolbar.add(self)
return
class DrawingCanvasToolbar(Container):
"""
The tool bar hosts Buttons and also consumes other mouse events, so that tools
on the underlying canvas don't get them.
FIXME: Right now this toolbar only supports the addition of buttons, and not
button removal. (Why would you ever want to remove a useful button?)
"""
canvas = Instance("DrawingCanvas")
button_spacing = Int(5)
auto_size = False
_last_button_position = Int(0)
def add_button(self, *buttons):
for button in buttons:
self.add(button)
button.toolbar = self
# Compute the new position for the button
button.x = self.button_spacing + self._last_button_position
self._last_button_position += button.width + self.button_spacing * 2
button.y = int((self.height - button.height) / 2)
return
def _canvas_changed(self, old, new):
if old:
old.on_trait_change(self._canvas_bounds_changed, "bounds", remove=True)
old.on_trait_change(self._canvas_bounds_changed, "bounds_items", remove=True)
if new:
new.on_trait_change(self._canvas_bounds_changed, "bounds")
new.on_trait_change(self._canvas_bounds_changed, "bounds_items")
return
def _canvas_bounds_changed(self):
self.width = self.canvas.width
self.y = self.canvas.height - self.height
return
def _dispatch_stateful_event(self, event, suffix):
super(DrawingCanvasToolbar, self)._dispatch_stateful_event(event, suffix)
event.handled = True
return
class DrawingCanvas(Container):
"""
A DrawingCanvas has some buttons which toggle what kind of drawing tools
are active on the canvas, then allow arbitrary painting on the canvas.
"""
# The active tool is the primary interactor on the canvas. It gets
# a chance to handle events before they are passed on to other components
# and listener tools.
active_tool = Any
# Listening tools are always enabled and get all events (unless the active
# tool has vetoed it), but they cannot prevent other tools from getting events.
listening_tools = List
# The background color of the canvas
bgcolor = ColorTrait("white")
toolbar = Instance(DrawingCanvasToolbar, args=())
fit_window = True
def dispatch(self, event, suffix):
# See if the event happened on the toolbar:
event.offset_xy(*self.position)
if self.toolbar.is_in(event.x, event.y):
self.toolbar.dispatch(event, suffix)
event.pop()
if event.handled:
return
if self.active_tool is not None:
self.active_tool.dispatch(event, suffix)
if event.handled:
return
for tool in self.listening_tools:
tool.dispatch(event, suffix)
super(DrawingCanvas, self).dispatch(event, suffix)
return
def activate(self, tool):
"""
Makes the indicated tool the active tool on the canvas and moves the
current active tool back into the list of tools.
"""
self.active_tool = tool
return
def _draw_container_mainlayer(self, gc, view_bounds=None, mode="default"):
active_tool = self.active_tool
if active_tool and active_tool.draw_mode == "exclusive":
active_tool.draw(gc, view_bounds, mode)
else:
#super(DrawingCanvas, self)._draw(gc, view_bounds, mode)
for tool in self.listening_tools:
tool.draw(gc, view_bounds, mode)
if active_tool:
active_tool.draw(gc, view_bounds, mode)
self.toolbar.draw(gc, view_bounds, mode)
return
def _draw_container_background(self, gc, view_bounds=None, mode="default"):
if self.bgcolor not in ("clear", "transparent", "none"):
with gc:
gc.set_antialias(False)
gc.set_fill_color(self.bgcolor_)
gc.draw_rect((int(self.x), int(self.y), int(self.width)-1, int(self.height)-1), FILL)
return
#------------------------------------------------------------------------
# Event listeners
#------------------------------------------------------------------------
def _tools_items_changed(self):
self.request_redraw()
return
# EOF
|