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.
This commit is contained in:
Joey Payne 2014-02-06 21:22:44 -07:00
commit 2cae09a0f0
2 changed files with 64 additions and 42 deletions

View file

@ -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"""

View file

@ -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]