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:
parent
49a630e8ac
commit
2cae09a0f0
2 changed files with 64 additions and 42 deletions
|
|
@ -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"""
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue