@@ -897,6 +897,35 @@ def _attr_swizzle(attr: str, size: int, write: bool=False) -> Tuple[bool, str]:
897
897
result += groups [0 ][groups [group ].index (c )]
898
898
return True , result
899
899
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
+
900
929
def _flatten (filter_types : List [Type ], * values , map_to : Optional [Type ]= None ) -> list :
901
930
result = []
902
931
for v in values :
@@ -1762,38 +1791,59 @@ def __str__(self) -> str:
1762
1791
def __repr__ (self ) -> str :
1763
1792
return "{}({}, {}, {}, {})" .format (self .__class__ .__qualname__ , self .r , self .g , self .b , self .a )
1764
1793
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 ())
1797
1847
1798
1848
@property
1799
1849
def normalized (self ) -> 'Vector4' :
0 commit comments