Add clipping for Buffer draw operations.
class Point:
"""Point in cartesian space.
Implements attribute access (.x, .y) and list-like access([0],[1]).
"""
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __getitem__(self, key):
return (self.x, self.y)[key]
def __repr__(self):
return 'Point(x={0.x},y={0.y})'.format(self)
def update(self, *args, **kwargs):
"""Update point.
Accepts positional or keyword arguments:
- (point: Point)
- (x: int, y: int)
"""
if len(args) == 2:
self.x, self.y = args
elif len(args) == 1:
self.x, self.y = args[0]
elif len(args):
raise ValueError('Too many args.')
for key, val in kwargs.items():
if key == 'point':
self.x, self.y = val
elif key in ('x', 'y'):
setattr(self, key, val)
else:
raise ValueError('Bad keyword arg: %r' % key)
class Size:
"""Size class.
Implements attribute access (.w, .h) and list-like access([0],[1]).
"""
def __init__(self, *args, **kwargs):
self.w = 0
self.h = 0
self.update(*args, **kwargs)
def __getitem__(self, key):
return (self.w, self.h)[key]
def __repr__(self):
return 'Size(w={0.w},h={0.h})'.format(self)
def update(self, *args, **kwargs):
"""Update size.
Accepts positional or keyword arguments:
- (size: Size)
- (w: int, h: int)
"""
if len(args) == 2:
self.w, self.h = args
elif len(args) == 1:
self.w, self.h = args[0]
elif len(args):
raise ValueError('Too many args.')
for key, val in kwargs.items():
if key == 'size':
self.w, self.h = val
elif key in ('w', 'h'):
setattr(self, key, val)
else:
raise ValueError('Bad keyword arg: %r' % key)
def readonly(self):
return ReadonlySize(self)
class ReadonlySize:
"""Wrapper for Size which makes it read-only."""
def __init__(self, size):
self._size = size
@property
def w(self):
return self._size.w
@property
def h(self):
return self._size.h
def __getitem__(self, key):
return self._size[key]
def __repr__(self):
return 'ReadonlySize(w={0.w},h={0.h})'.format(self._size)
class Rect:
"""Rectangle is defined by coordinates and size."""
def __init__(self, x=0, y=0, w=0, h=0):
self.x = x
self.y = y
self.w = w
self.h = h
def __repr__(self):
return 'Rect(x={0.x},y={0.y},w={0.w},h={0.h})'.format(self)
def __contains__(self, point):
"""Test if point is positioned inside rectangle.
`point` should be either Point or pair of int values.
"""
x, y = point
return (self.x <= x < self.x + self.w
and self.y <= y < self.y + self.h)
def intersect(self, other):
x1 = max(self.x, other.x)
y1 = max(self.y, other.y)
x2 = min(self.x + self.w, other.x + other.w)
y2 = min(self.y + self.h, other.y + other.h)
if x1 >= x2 or y1 >= y2:
return Rect()
return Rect(x1, y1, x2-x1, y2-y1)
def union(self, other):
x = min(self.x, other.x)
y = min(self.y, other.y)
w = max(self.x + self.w, other.x + other.w) - x
h = max(self.y + self.h, other.y + other.h) - y
return Rect(x, y, w, h)