From d097eec6b67d30c36252c733256505f3aa8bb4f6 Mon Sep 17 00:00:00 2001 From: Thomas Brooks Date: Mon, 23 Jul 2012 13:30:43 -0500 Subject: [PATCH 1/4] optimize intersect_bounds --- enable/base.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/enable/base.py b/enable/base.py index 0b47ce592..dd7fc2803 100644 --- a/enable/base.py +++ b/enable/base.py @@ -138,6 +138,23 @@ def intersect_coordinates ( coordinates1, coordinates2 ): return ( xl, yb, xr, yt ) return empty_rectangle +def intersect_bounds2( bounds1, bounds2 ): + "Compute the intersection of two bounds rectangles" + if (bounds1 is empty_rectangle) or (bounds2 is empty_rectangle): + return empty_rectangle + x1, y1, w1, h1 = bounds1 + x2, y2, w2, h2 = bounds2 + + x = max(x1, x2) + y = max(y1, y2) + w = min(w1 - x2 + x1, w2 - x1 + x2, w1, w2) + h = min(h1 - y2 + y1, h2 - y1 + y2, h1, h2) + if w <= 0 or h <= 0: + return empty_rectangle + else: + return (x,y,w,h) + + def intersect_bounds ( bounds1, bounds2 ): "Compute the intersection of two bounds rectangles" if (bounds1 is empty_rectangle) or (bounds2 is empty_rectangle): From 49a9794b2359717d1c311b5d21b0d09e2ed0e012 Mon Sep 17 00:00:00 2001 From: Thomas Brooks Date: Mon, 23 Jul 2012 13:34:53 -0500 Subject: [PATCH 2/4] short-circuit some layout_needed tests and minor readability improvement in invalidate_draw --- enable/component.py | 21 +++++++++++---------- enable/container.py | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/enable/component.py b/enable/component.py index 9f210f713..7830ed0e1 100644 --- a/enable/component.py +++ b/enable/component.py @@ -5,7 +5,7 @@ # Enthought library imports from traits.api \ import Any, Bool, Delegate, Enum, Float, Instance, Int, List, \ - Property, Str, Trait + Property, Str, Trait, cached_property from kiva.constants import FILL, STROKE # Local relative imports @@ -188,7 +188,7 @@ class Component(CoordinateBox, Interactor): # will not change the padding or bounds. # This returns a tuple because modifying the returned value has no effect. # To modify outer_position element-wise, use set_outer_position(). - outer_position = Property + outer_position = Property() # The number of horizontal and vertical pixels in the padding outer box. # Setting these bounds will modify the bounds of the component, but @@ -196,7 +196,7 @@ class Component(CoordinateBox, Interactor): # the padding. # This returns a tuple because modifying the returned value has no effect. # To modify outer_bounds element-wise, use set_outer_bounds(). - outer_bounds = Property + outer_bounds = Property() outer_x = Property outer_x2 = Property @@ -416,7 +416,7 @@ def draw(self, gc, view_bounds=None, mode="default"): an aesthetic cost. """ if self.layout_needed: - self.do_layout() + self.do_layout(force=True) self._draw(gc, view_bounds, mode) return @@ -543,14 +543,15 @@ def invalidate_draw(self, damaged_regions=None, self_relative=False): Call this method whenever a component's internal state changes such that it must be redrawn on the next draw() call.""" - self.draw_valid = False if damaged_regions is None: damaged_regions = self._default_damaged_regions() + self.draw_valid = False + if self_relative: - damaged_regions = [[region[0] + self.x, region[1] + self.y, - region[2], region[3]] for region in damaged_regions] + damaged_regions = [[x + self.x, y + self.y, + w, h] for x,y,w,h in damaged_regions] for view in self.viewports: view.invalidate_draw(damaged_regions=damaged_regions, self_relative=True, view_relative=True) @@ -633,7 +634,7 @@ def do_layout(self, size=None, force=False): even if *force* is False. """ - if self.layout_needed or force: + if force or self.layout_needed: if size is not None: self.bounds = size self._do_layout() @@ -712,7 +713,7 @@ def _draw(self, gc, view_bounds=None, mode="default"): return if self.layout_needed: - self.do_layout() + self.do_layout(force=True) self.drawn_outer_position = list(self.outer_position[:]) self.drawn_outer_bounds = list(self.outer_bounds[:]) @@ -786,7 +787,7 @@ def _dispatch_draw(self, layer, gc, view_bounds, mode): if layer == "selection" and not self.use_selection: return if self.layout_needed: - self.do_layout() + self.do_layout(force=True) handler = getattr(self, "_draw_" + layer, None) if handler: diff --git a/enable/container.py b/enable/container.py index b5f6d5e7f..9a9692ef2 100644 --- a/enable/container.py +++ b/enable/container.py @@ -302,7 +302,7 @@ def _dispatch_draw(self, layer, gc, view_bounds, mode): return if self.layout_needed: - self.do_layout() + self.do_layout(force=True) # Give the container a chance to draw first for the layers that are # considered "under" or "at" the main layer level From 26d9453d2154c1d62e9523cd075f357dbc27cc77 Mon Sep 17 00:00:00 2001 From: Thomas Brooks Date: Mon, 23 Jul 2012 14:49:18 -0500 Subject: [PATCH 3/4] cache outer_position and outer_bounds --- enable/component.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/enable/component.py b/enable/component.py index 7830ed0e1..66b560a38 100644 --- a/enable/component.py +++ b/enable/component.py @@ -188,7 +188,9 @@ class Component(CoordinateBox, Interactor): # will not change the padding or bounds. # This returns a tuple because modifying the returned value has no effect. # To modify outer_position element-wise, use set_outer_position(). - outer_position = Property() + outer_position = Property(depends_on=["position", "border_visible", + "inset_border", "border_width", + "padding_left", "padding_bottom"]) # The number of horizontal and vertical pixels in the padding outer box. # Setting these bounds will modify the bounds of the component, but @@ -196,7 +198,10 @@ class Component(CoordinateBox, Interactor): # the padding. # This returns a tuple because modifying the returned value has no effect. # To modify outer_bounds element-wise, use set_outer_bounds(). - outer_bounds = Property() + outer_bounds = Property(depends_on=["bounds", "border_visible", + "inset_border", "border_width", + "padding_left", "padding_right", + "padding_top", "padding_bottom"]) outer_x = Property outer_x2 = Property @@ -1179,6 +1184,7 @@ def _get_vpadding(self): # Outer position setters and getters #------------------------------------------------------------------------ + @cached_property def _get_outer_position(self): border = self._get_visible_border() pos = self.position @@ -1219,6 +1225,7 @@ def _set_outer_y2(self, val): # Outer bounds setters and getters #------------------------------------------------------------------------ + @cached_property def _get_outer_bounds(self): bounds = self.bounds return (bounds[0] + self.hpadding, bounds[1] + self.vpadding) From 076b6a18e3f746b12a20066833a74cdcbddd2b40 Mon Sep 17 00:00:00 2001 From: Thomas Brooks Date: Wed, 25 Jul 2012 10:27:26 -0500 Subject: [PATCH 4/4] actually use the optimized intersect_bounds --- enable/base.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/enable/base.py b/enable/base.py index dd7fc2803..7b79de65a 100644 --- a/enable/base.py +++ b/enable/base.py @@ -138,7 +138,7 @@ def intersect_coordinates ( coordinates1, coordinates2 ): return ( xl, yb, xr, yt ) return empty_rectangle -def intersect_bounds2( bounds1, bounds2 ): +def intersect_bounds( bounds1, bounds2 ): "Compute the intersection of two bounds rectangles" if (bounds1 is empty_rectangle) or (bounds2 is empty_rectangle): return empty_rectangle @@ -154,20 +154,6 @@ def intersect_bounds2( bounds1, bounds2 ): else: return (x,y,w,h) - -def intersect_bounds ( bounds1, bounds2 ): - "Compute the intersection of two bounds rectangles" - if (bounds1 is empty_rectangle) or (bounds2 is empty_rectangle): - return empty_rectangle - - intersection = intersect_coordinates( - bounds_to_coordinates( bounds1 ), - bounds_to_coordinates( bounds2 ) ) - if intersection is empty_rectangle: - return empty_rectangle - xl, yb, xr, yt = intersection - return ( xl, yb, xr - xl, yt - yb ) - def union_coordinates ( coordinates1, coordinates2 ): "Compute the union of two coordinate based rectangles" if coordinates1 is empty_rectangle: