Skip to content

Commit fbf53e3

Browse files
committed
Attr swizzling for Color added; Color emulate container types too.
1 parent 0567961 commit fbf53e3

File tree

1 file changed

+82
-32
lines changed

1 file changed

+82
-32
lines changed

raylibpy/__init__.py

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,35 @@ def _attr_swizzle(attr: str, size: int, write: bool=False) -> Tuple[bool, str]:
897897
result += groups[0][groups[group].index(c)]
898898
return True, result
899899

900+
901+
def _color_swizzle(attr: str, size: int, write: bool=False) -> Tuple[bool, str]:
902+
if len(attr) not in (1, 2, 3, 4):
903+
return False, "Wrong number of components to swizzle (must be 1, 2, 3 or 4; not {}).".format(len(attr))
904+
if size not in (3, 4):
905+
return False, "Wrong vector size (must be 3 or 4; not {}).".format(size)
906+
907+
groups = ['rgba']
908+
if size == 3:
909+
groups = ['rgb']
910+
911+
if attr[0] in groups[0]:
912+
group = 0
913+
else:
914+
return False, "Invalid component '{}' in swizzled Color attribute.".format(attr[0])
915+
916+
already_set = []
917+
result = ''
918+
for i, c in enumerate(attr):
919+
if c not in groups[group]:
920+
return False, "Invalid component '{}' in swizzled attribute.".format(c)
921+
if write and c in already_set:
922+
return False, "Component '{}' in swizzled attribute is set more than once.".format(c)
923+
if write:
924+
already_set.append(c)
925+
result += groups[0][groups[group].index(c)]
926+
return True, result
927+
928+
900929
def _flatten(filter_types: List[Type], *values, map_to: Optional[Type]=None) -> list:
901930
result = []
902931
for v in values:
@@ -1762,38 +1791,59 @@ def __str__(self) -> str:
17621791
def __repr__(self) -> str:
17631792
return "{}({}, {}, {}, {})".format(self.__class__.__qualname__, self.r, self.g, self.b, self.a)
17641793

1765-
def __getitem__(self, key: str) -> 'Color':
1766-
assert isinstance(key, str), "key must be a str of 4 characters."
1767-
assert len(key) == 4, "key must have 4 characters (between 'r', 'g', 'b' and 'a')."
1768-
comps = [self.r, self.g, self.b, self.a]
1769-
values = []
1770-
for i, axis in enumerate(key):
1771-
values.append({
1772-
'r': self.r,
1773-
'g': self.g,
1774-
'b': self.b,
1775-
'a': self.a,
1776-
'R': 255 - self.r,
1777-
'G': 255 - self.g,
1778-
'B': 255 - self.b,
1779-
'A': 255 - self.a,
1780-
'0': 0,
1781-
'1': 255,
1782-
'/': max(0, min(comps[i] // 2, 255)),
1783-
'*': max(0, min(comps[i] * 2, 255)),
1784-
'^': max(0, min(comps[i] ** 2, 255)),
1785-
'.': comps[i],
1786-
'+': comps[i],
1787-
'?': 255 if comps[i] != 0 else 0,
1788-
'>': max(self.r, self.g, self.b),
1789-
'<': min(self.r, self.g, self.b),
1790-
}[axis])
1791-
return {
1792-
1: values[0],
1793-
2: Vector2(*values),
1794-
3: Vector3(*values),
1795-
4: Vector4(*values),
1796-
}[len(values)]
1794+
def __len__(self) -> int:
1795+
return 4
1796+
1797+
def __getattr__(self, name: str) -> Union[int, 'Color']:
1798+
is_valid, result = _color_swizzle(name, 4)
1799+
if is_valid:
1800+
comps = {'r': self.r, 'g': self.g, 'b': self.b, 'a': self.a}
1801+
n = len(result)
1802+
v = [comps[comp] for comp in result]
1803+
if n == 3:
1804+
return Color(*v, 255)
1805+
if n == 4:
1806+
return Color(*v)
1807+
1808+
raise AttributeError(result)
1809+
1810+
def __setattr__(self, name: str, value: Union[int, Seq, 'Color']) -> None:
1811+
is_valid, result = _color_swizzle(name, 4, True) # True for setattr, so components can't be set more than once.
1812+
if is_valid:
1813+
if len(name) == 1:
1814+
v = int(value)
1815+
super(Color, self).__setattr__(result, v)
1816+
else:
1817+
values = _flatten((int, float), *value, map_to=int)
1818+
if len(name) != len(values):
1819+
raise ValueError("Too many or too few values ({} instead of {}".format(
1820+
len(values), len(name)
1821+
))
1822+
for i, c in enumerate(result):
1823+
super(Color, self).__setattr__(c, float(values[i]))
1824+
else:
1825+
raise AttributeError(result)
1826+
1827+
def __getitem__(self, key: Union[str, int, slice]) -> Union[float, Seq]:
1828+
assert isinstance(key, (str, int, slice)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1829+
1830+
if isinstance(key, (int, slice)):
1831+
return [self.r, self.g, self.b, self.a][key]
1832+
elif isinstance(key, str):
1833+
return {'r': self.r, 'g': self.g, 'b': self.b, 'a': self.a}[key]
1834+
1835+
def __setitem__(self, key: Union[str, int], value: Number) -> None:
1836+
assert isinstance(key, (str, int)), "KeyTypeError: {} not supported as subscription key.".format(key.__class__.__name__)
1837+
1838+
if isinstance(key, int):
1839+
a = [self.r, self.g, self.b, self.a]
1840+
a[key] = value
1841+
self.r, self.g, self.b, self.a = a
1842+
elif isinstance(key, str):
1843+
a = {'r': self.r, 'g': self.g, 'b': self.b, 'a': self.a}
1844+
assert key in a, "KeyError: invalid key '{}'.".format(key)
1845+
a[key] = value
1846+
self.r, self.g, self.b, self.a = tuple(a.values())
17971847

17981848
@property
17991849
def normalized(self) -> 'Vector4':

0 commit comments

Comments
 (0)