From 2cae09a0f096f38a27ff0cc68dae07d4b7904eb6 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Thu, 6 Feb 2014 21:22:44 -0700 Subject: [PATCH] Made the from_value code way more efficient. Added clipping rectangles so that when a child is hidden by it's parent, it can't be clicked. --- jgui/surface/structures.py | 60 +++++++++++++++++++------------------- jgui/surface/surface.py | 46 +++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/jgui/surface/structures.py b/jgui/surface/structures.py index 1378ecd..6074b88 100644 --- a/jgui/surface/structures.py +++ b/jgui/surface/structures.py @@ -63,10 +63,13 @@ class StructureBase(object): @classmethod def from_value(cls, value): - try: - return cls(*value) - except TypeError: - return cls() + if isinstance(value, cls): + return value + else: + try: + return cls(*value) + except TypeError: + return cls() class Position(StructureBase): def __init__(self, x=0, y=0): @@ -87,8 +90,7 @@ class Position(StructureBase): raise Exception("Cannot multiply position by {}.".format(value.__class__.__name__)) def __iter__(self): - yield self.x - yield self.y + return iter([self.x, self.y]) class Size(StructureBase): @@ -122,8 +124,7 @@ class Size(StructureBase): return self.width*self.height def __iter__(self): - yield self.width - yield self.height + return iter([self.width, self.height]) class FourValueStructure(StructureBase): @@ -146,7 +147,10 @@ class FourValueStructure(StructureBase): @classmethod def from_value(cls, value): - return cls(*cls._parse_value(value)) + if isinstance(value, cls): + return value + else: + return cls(*cls._parse_value(value)) class BorderRadius(FourValueStructure): @@ -158,10 +162,7 @@ class BorderRadius(FourValueStructure): self.bottomleft = kwargs.get('bottomleft', values[3]) def __iter__(self): - yield self.topleft - yield self.topright - yield self.bottomright - yield self.bottomleft + return iter([self.topleft, self.topright, self.bottomright, self.bottomleft]) class Padding(FourValueStructure): @@ -173,10 +174,7 @@ class Padding(FourValueStructure): self.left = kwargs.get('left', values[3]) def __iter__(self): - yield self.top - yield self.right - yield self.bottom - yield self.left + return iter([self.top, self.right, self.bottom, self.left]) class Color(StructureBase): @@ -218,10 +216,7 @@ class Color(StructureBase): return self def __iter__(self): - yield self.r - yield self.g - yield self.b - yield self.a + return iter([self.r, self.g, self.b, self.a]) @classmethod def hex_to_rgba(cls, hex_val): @@ -244,6 +239,8 @@ class Color(StructureBase): @classmethod def from_value(cls, value): + if isinstance(value, cls): + return value try: return cls(*value) except TypeError: @@ -272,8 +269,7 @@ class Rectangle(StructureBase): self._position = Position.from_value(position) def __iter__(self): - yield list(self.position) - yield list(self.size) + return iter([list(self.position), list(self.size)]) @property def size(self): @@ -292,16 +288,20 @@ class Rectangle(StructureBase): def intersection(self, other): other = Rectangle.from_value(other) + if self.contains(other): + return other if other.contains(self): return self - elif self.contains(other): - return other - if self.intersects_with(other.position): - return Rectangle(other.position, self.position + self.size - other.position) - elif other.intersects_with(self.position): - return Rectangle(self.position, other.position + other.size - self.position) - else: + + newx = max(self.position.x, other.position.x) + newy = max(self.position.y, other.position.y) + + new_width = min(self.position.x + self.size.width, other.position.x + other.size.width) - newx + new_height = min(self.position.y + self.size.height, other.position.y + other.size.height) - newy + + if new_width <= 0 or new_height <= 0: return Rectangle() + return Rectangle([newx, newy], [new_width, new_height]) def intersects_with(self, position): """Checks if the position is within the bounds of the rectangle including the edges""" diff --git a/jgui/surface/surface.py b/jgui/surface/surface.py index 2984737..6cc5b14 100644 --- a/jgui/surface/surface.py +++ b/jgui/surface/surface.py @@ -285,6 +285,7 @@ class Window(WindowEventSource, WindowSurface): super(Window, self).__init__() self._draggable = False self._resizable = False + self._root = None self.name = name @@ -638,6 +639,16 @@ class Window(WindowEventSource, WindowSurface): def hide(self): self.visible = False + def get_clip_parent(self): + parent = self.parent + l = [] + while parent is not None: + if parent.clip_children: + l.append(parent) + parent = parent.parent + if l: + return l[-1] + def inject_mouse_down(self, button): if self.mouse_inside(): log(button, self.name) @@ -706,34 +717,45 @@ class Window(WindowEventSource, WindowSurface): self.mouse_inputs[key] = False self.dispatch('focus-lost', self) - def get_root(self): - parent = self.parent - if parent is None: - return self + @property + def root(self): + if self._root is None: + parent = self.parent + if parent is None: + return self - while parent is not None: - root = parent - parent = parent.parent + while parent is not None: + root = parent + parent = parent.parent - return root + self._root = root + return self._root def mouse_inside(self): """ Checks if the mouse is inside the window taking into account all other windows and draw priorities. """ - res = self.rectangle.intersects_with(self.mouse_pos) + rec = self.rectangle + clip_parent = self.get_clip_parent() + if clip_parent is not None: + rec = self.rectangle.intersection(clip_parent.rectangle) + res = rec.intersects_with(self.mouse_pos) if not res: return False #Check all children of root to see if there is a higher priority #window than the current one - root = self.get_root() + root = self.root stack = [root] visited = set() while stack: item = stack[-1] - intersects_mouse = item.rectangle.intersects_with(self.mouse_pos) + rec = item.rectangle + clip_parent = item.get_clip_parent() + if clip_parent is not None: + rec = item.rectangle.intersection(clip_parent.rectangle) + intersects_mouse = rec.intersects_with(self.mouse_pos) if item.children and not set(item.children).issubset(visited): stack.extend(item.children) else: @@ -748,7 +770,7 @@ class Window(WindowEventSource, WindowSurface): def mouse_held(self): res = self.mouse_down - stack = [self.get_root()] + stack = [self.root] visited = set() while len(stack) > 0: item = stack[-1]