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
|
@classmethod
|
||||||
def from_value(cls, value):
|
def from_value(cls, value):
|
||||||
try:
|
if isinstance(value, cls):
|
||||||
return cls(*value)
|
return value
|
||||||
except TypeError:
|
else:
|
||||||
return cls()
|
try:
|
||||||
|
return cls(*value)
|
||||||
|
except TypeError:
|
||||||
|
return cls()
|
||||||
|
|
||||||
class Position(StructureBase):
|
class Position(StructureBase):
|
||||||
def __init__(self, x=0, y=0):
|
def __init__(self, x=0, y=0):
|
||||||
|
|
@ -87,8 +90,7 @@ class Position(StructureBase):
|
||||||
raise Exception("Cannot multiply position by {}.".format(value.__class__.__name__))
|
raise Exception("Cannot multiply position by {}.".format(value.__class__.__name__))
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield self.x
|
return iter([self.x, self.y])
|
||||||
yield self.y
|
|
||||||
|
|
||||||
|
|
||||||
class Size(StructureBase):
|
class Size(StructureBase):
|
||||||
|
|
@ -122,8 +124,7 @@ class Size(StructureBase):
|
||||||
return self.width*self.height
|
return self.width*self.height
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield self.width
|
return iter([self.width, self.height])
|
||||||
yield self.height
|
|
||||||
|
|
||||||
|
|
||||||
class FourValueStructure(StructureBase):
|
class FourValueStructure(StructureBase):
|
||||||
|
|
@ -146,7 +147,10 @@ class FourValueStructure(StructureBase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_value(cls, value):
|
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):
|
class BorderRadius(FourValueStructure):
|
||||||
|
|
@ -158,10 +162,7 @@ class BorderRadius(FourValueStructure):
|
||||||
self.bottomleft = kwargs.get('bottomleft', values[3])
|
self.bottomleft = kwargs.get('bottomleft', values[3])
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield self.topleft
|
return iter([self.topleft, self.topright, self.bottomright, self.bottomleft])
|
||||||
yield self.topright
|
|
||||||
yield self.bottomright
|
|
||||||
yield self.bottomleft
|
|
||||||
|
|
||||||
|
|
||||||
class Padding(FourValueStructure):
|
class Padding(FourValueStructure):
|
||||||
|
|
@ -173,10 +174,7 @@ class Padding(FourValueStructure):
|
||||||
self.left = kwargs.get('left', values[3])
|
self.left = kwargs.get('left', values[3])
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield self.top
|
return iter([self.top, self.right, self.bottom, self.left])
|
||||||
yield self.right
|
|
||||||
yield self.bottom
|
|
||||||
yield self.left
|
|
||||||
|
|
||||||
|
|
||||||
class Color(StructureBase):
|
class Color(StructureBase):
|
||||||
|
|
@ -218,10 +216,7 @@ class Color(StructureBase):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield self.r
|
return iter([self.r, self.g, self.b, self.a])
|
||||||
yield self.g
|
|
||||||
yield self.b
|
|
||||||
yield self.a
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def hex_to_rgba(cls, hex_val):
|
def hex_to_rgba(cls, hex_val):
|
||||||
|
|
@ -244,6 +239,8 @@ class Color(StructureBase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_value(cls, value):
|
def from_value(cls, value):
|
||||||
|
if isinstance(value, cls):
|
||||||
|
return value
|
||||||
try:
|
try:
|
||||||
return cls(*value)
|
return cls(*value)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|
@ -272,8 +269,7 @@ class Rectangle(StructureBase):
|
||||||
self._position = Position.from_value(position)
|
self._position = Position.from_value(position)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield list(self.position)
|
return iter([list(self.position), list(self.size)])
|
||||||
yield list(self.size)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self):
|
||||||
|
|
@ -292,16 +288,20 @@ class Rectangle(StructureBase):
|
||||||
|
|
||||||
def intersection(self, other):
|
def intersection(self, other):
|
||||||
other = Rectangle.from_value(other)
|
other = Rectangle.from_value(other)
|
||||||
|
if self.contains(other):
|
||||||
|
return other
|
||||||
if other.contains(self):
|
if other.contains(self):
|
||||||
return self
|
return self
|
||||||
elif self.contains(other):
|
|
||||||
return other
|
newx = max(self.position.x, other.position.x)
|
||||||
if self.intersects_with(other.position):
|
newy = max(self.position.y, other.position.y)
|
||||||
return Rectangle(other.position, self.position + self.size - other.position)
|
|
||||||
elif other.intersects_with(self.position):
|
new_width = min(self.position.x + self.size.width, other.position.x + other.size.width) - newx
|
||||||
return Rectangle(self.position, other.position + other.size - self.position)
|
new_height = min(self.position.y + self.size.height, other.position.y + other.size.height) - newy
|
||||||
else:
|
|
||||||
|
if new_width <= 0 or new_height <= 0:
|
||||||
return Rectangle()
|
return Rectangle()
|
||||||
|
return Rectangle([newx, newy], [new_width, new_height])
|
||||||
|
|
||||||
def intersects_with(self, position):
|
def intersects_with(self, position):
|
||||||
"""Checks if the position is within the bounds of the rectangle including the edges"""
|
"""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__()
|
super(Window, self).__init__()
|
||||||
self._draggable = False
|
self._draggable = False
|
||||||
self._resizable = False
|
self._resizable = False
|
||||||
|
self._root = None
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
|
@ -638,6 +639,16 @@ class Window(WindowEventSource, WindowSurface):
|
||||||
def hide(self):
|
def hide(self):
|
||||||
self.visible = False
|
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):
|
def inject_mouse_down(self, button):
|
||||||
if self.mouse_inside():
|
if self.mouse_inside():
|
||||||
log(button, self.name)
|
log(button, self.name)
|
||||||
|
|
@ -706,34 +717,45 @@ class Window(WindowEventSource, WindowSurface):
|
||||||
self.mouse_inputs[key] = False
|
self.mouse_inputs[key] = False
|
||||||
self.dispatch('focus-lost', self)
|
self.dispatch('focus-lost', self)
|
||||||
|
|
||||||
def get_root(self):
|
@property
|
||||||
parent = self.parent
|
def root(self):
|
||||||
if parent is None:
|
if self._root is None:
|
||||||
return self
|
parent = self.parent
|
||||||
|
if parent is None:
|
||||||
|
return self
|
||||||
|
|
||||||
while parent is not None:
|
while parent is not None:
|
||||||
root = parent
|
root = parent
|
||||||
parent = parent.parent
|
parent = parent.parent
|
||||||
|
|
||||||
return root
|
self._root = root
|
||||||
|
return self._root
|
||||||
|
|
||||||
def mouse_inside(self):
|
def mouse_inside(self):
|
||||||
"""
|
"""
|
||||||
Checks if the mouse is inside the window taking into account
|
Checks if the mouse is inside the window taking into account
|
||||||
all other windows and draw priorities.
|
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:
|
if not res:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
#Check all children of root to see if there is a higher priority
|
#Check all children of root to see if there is a higher priority
|
||||||
#window than the current one
|
#window than the current one
|
||||||
root = self.get_root()
|
root = self.root
|
||||||
stack = [root]
|
stack = [root]
|
||||||
visited = set()
|
visited = set()
|
||||||
while stack:
|
while stack:
|
||||||
item = stack[-1]
|
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):
|
if item.children and not set(item.children).issubset(visited):
|
||||||
stack.extend(item.children)
|
stack.extend(item.children)
|
||||||
else:
|
else:
|
||||||
|
|
@ -748,7 +770,7 @@ class Window(WindowEventSource, WindowSurface):
|
||||||
|
|
||||||
def mouse_held(self):
|
def mouse_held(self):
|
||||||
res = self.mouse_down
|
res = self.mouse_down
|
||||||
stack = [self.get_root()]
|
stack = [self.root]
|
||||||
visited = set()
|
visited = set()
|
||||||
while len(stack) > 0:
|
while len(stack) > 0:
|
||||||
item = stack[-1]
|
item = stack[-1]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue