/usr/lib/python2.7/dist-packages/enable/canvas.py is in python-enable 4.5.1-4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 | """ Defines the enable Canvas class """
from __future__ import with_statement
# Enthought library imports
from traits.api import Bool, Trait, Tuple, List
from kiva.constants import FILL
# Local relative imports
from component import Component
from container import Container
class Canvas(Container):
"""
An infinite canvas with components on it. It can optionally be given
a "view region" which will be used as the notional bounds of the
canvas in all operations that require bounds.
A Canvas can be nested inside another container, but usually a
viewport is more appropriate.
Note: A Canvas has infinite bounds, but its .bounds attribute is
overloaded to be something more meaningful, namely, the bounding
box of its child components and the optional view area of the
viewport that is looking at it. (TODO: add support for multiple
viewports.)
"""
# This optional tuple of (x,y,x2,y2) allows viewports to inform the canvas of
# the "region of interest" that it should use when computing its notional
# bounds for clipping and event handling purposes. If this trait is None,
# then the canvas really does behave as if it has no bounds.
view_bounds = Trait(None, None, Tuple)
# The (x,y) position of the lower-left corner of the rectangle corresponding
# to the dimensions in self.bounds. Unlike self.position, this position is
# in the canvas's space, and not in the coordinate space of the parent.
bounds_offset = List
draw_axes = Bool(False)
#------------------------------------------------------------------------
# Inherited traits
#------------------------------------------------------------------------
# Use the auto-size/fit_components mechanism to ensure that the bounding
# box around our inner components gets updated properly.
auto_size = True
fit_components = "hv"
# The following traits are ignored, but we set them to sensible values.
fit_window = False
resizable = "hv"
#------------------------------------------------------------------------
# Protected traits
#------------------------------------------------------------------------
# The (x, y, x2, y2) coordinates of the bounding box of the components
# in our inner coordinate space
_bounding_box = Tuple((0,0,100,100))
def compact(self):
"""
Wraps the superclass method to also take into account the view
bounds (if they are present
"""
self._bounding_box = self._calc_bounding_box()
self._view_bounds_changed()
def is_in(self, x, y):
return True
def remove(self, *components):
""" Removes components from this container """
needs_compact = False
for component in components:
if component in self._components:
component.container = None
self._components.remove(component)
else:
raise RuntimeError, "Unable to remove component from container."
# Check to see if we need to compact.
x, y, x2, y2 = self._bounding_box
if (component.outer_x2 == x2-x) or \
(component.outer_y2 == y2-y) or \
(component.x == 0) or (component.y == 0):
needs_compact = True
if needs_compact:
self.compact()
self.invalidate_draw()
def draw(self, gc, view_bounds=None, mode="normal"):
if self.view_bounds is None:
self.view_bounds = view_bounds
super(Canvas, self).draw(gc, view_bounds, mode)
#------------------------------------------------------------------------
# Protected methods
#------------------------------------------------------------------------
def _should_compact(self):
if self.auto_size:
if self.view_bounds is not None:
llx, lly = self.view_bounds[:2]
else:
llx = lly = 0
for component in self.components:
if (component.outer_x2 >= self.width) or \
(component.outer_y2 >= self.height) or \
(component.outer_x < llx) or (component.outer_y < lly):
return True
else:
return False
def _draw_background(self, gc, view_bounds=None, mode="default"):
if self.bgcolor not in ("clear", "transparent", "none"):
if self.view_bounds is not None:
x, y, x2, y2 = self.view_bounds
else:
x, y, x2, y2 = self._bounding_box
r = (x, y, x2-x+1, y2-y+1)
with gc:
gc.set_antialias(False)
gc.set_fill_color(self.bgcolor_)
gc.draw_rect(r, FILL)
# Call the enable _draw_border routine
if not self.overlay_border and self.border_visible:
# Tell _draw_border to ignore the self.overlay_border
self._draw_border(gc, view_bounds, mode, force_draw=True)
return
def _draw_underlay(self, gc, view_bounds=None, mode="default"):
if self.draw_axes:
x, y, x2, y2 = self.view_bounds
if (x <= 0 <= x2) or (y <= 0 <= y2):
with gc:
gc.set_stroke_color((0,0,0,1))
gc.set_line_width(1.0)
gc.move_to(0, y)
gc.line_to(0, y2)
gc.move_to(x, 0)
gc.line_to(x2, 0)
gc.stroke_path()
super(Container, self)._draw_underlay(gc, view_bounds, mode)
def _transform_view_bounds(self, view_bounds):
# Overload the parent class's implementation to skip visibility test
if view_bounds:
v = view_bounds
new_bounds = (v[0]-self.x, v[1]-self.y, v[2], v[3])
else:
new_bounds = None
return new_bounds
#------------------------------------------------------------------------
# Event handlers
#------------------------------------------------------------------------
def _bounds_offset_default(self):
return [0,0]
def _view_bounds_changed(self):
llx, lly, urx, ury = self._bounding_box
if self.view_bounds is not None:
x, y, x2, y2 = self.view_bounds
llx = min(llx, x)
lly = min(lly, y)
urx = max(urx, x2)
ury = max(ury, y2)
self.bounds_offset = [llx, lly]
self.bounds = [urx - llx + 1, ury - lly + 1]
# Override Container.bounds_changed so that _layout_needed is not
# set. Containers need to invalidate layout because they act as
# sizers, but the Canvas is unbounded and thus does not need to
# invalidate layout.
def _bounds_changed(self, old, new):
Component._bounds_changed(self, old, new)
self.invalidate_draw()
def _bounds_items_changed(self, event):
Component._bounds_items_changed(self, event)
self.invalidate_draw()
|