xulbux 1.6.1__py3-none-any.whl → 1.6.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xulbux might be problematic. Click here for more details.
- xulbux/__init__.py +1 -1
- xulbux/_consts_.py +18 -18
- xulbux/xx_color.py +102 -92
- xulbux/xx_console.py +0 -12
- xulbux/xx_env_path.py +1 -1
- xulbux/xx_format_codes.py +219 -95
- xulbux/xx_regex.py +41 -30
- xulbux/xx_system.py +53 -1
- {xulbux-1.6.1.dist-info → xulbux-1.6.3.dist-info}/METADATA +15 -15
- xulbux-1.6.3.dist-info/RECORD +21 -0
- xulbux-1.6.1.dist-info/RECORD +0 -21
- {xulbux-1.6.1.dist-info → xulbux-1.6.3.dist-info}/LICENSE +0 -0
- {xulbux-1.6.1.dist-info → xulbux-1.6.3.dist-info}/WHEEL +0 -0
- {xulbux-1.6.1.dist-info → xulbux-1.6.3.dist-info}/entry_points.txt +0 -0
- {xulbux-1.6.1.dist-info → xulbux-1.6.3.dist-info}/top_level.txt +0 -0
xulbux/xx_color.py
CHANGED
|
@@ -59,7 +59,10 @@ class rgba:
|
|
|
59
59
|
- `with_alpha(alpha)` to create a new color with different alpha
|
|
60
60
|
- `complementary()` to get the complementary color"""
|
|
61
61
|
|
|
62
|
-
def __init__(self, r: int, g: int, b: int, a: float = None):
|
|
62
|
+
def __init__(self, r: int, g: int, b: int, a: float = None, _validate: bool = True):
|
|
63
|
+
if not _validate:
|
|
64
|
+
self.r, self.g, self.b, self.a = r, g, b, a
|
|
65
|
+
return
|
|
63
66
|
if any(isinstance(x, rgba) for x in (r, g, b)):
|
|
64
67
|
raise ValueError("Color is already a rgba() color")
|
|
65
68
|
elif not all(isinstance(x, int) and 0 <= x <= 255 for x in (r, g, b)):
|
|
@@ -70,25 +73,25 @@ class rgba:
|
|
|
70
73
|
elif a is not None and not (isinstance(a, (int, float)) and 0 <= a <= 1):
|
|
71
74
|
raise ValueError(f"Alpha channel must be a float/int in [0.0, 1.0]: got '{a}'")
|
|
72
75
|
self.r, self.g, self.b = r, g, b
|
|
73
|
-
self.a = (1.0 if a > 1.0 else float(a))
|
|
76
|
+
self.a = None if a is None else (1.0 if a > 1.0 else float(a))
|
|
74
77
|
|
|
75
78
|
def __len__(self):
|
|
76
|
-
return
|
|
79
|
+
return 3 if self.a is None else 4
|
|
77
80
|
|
|
78
81
|
def __iter__(self):
|
|
79
|
-
return iter((self.r, self.g, self.b) + ((
|
|
82
|
+
return iter((self.r, self.g, self.b) + (() if self.a is None else (self.a,)))
|
|
80
83
|
|
|
81
84
|
def __dict__(self):
|
|
82
85
|
return self.dict()
|
|
83
86
|
|
|
84
87
|
def __getitem__(self, index):
|
|
85
|
-
return ((self.r, self.g, self.b) + ((
|
|
88
|
+
return ((self.r, self.g, self.b) + (() if self.a is None else (self.a,)))[index]
|
|
86
89
|
|
|
87
90
|
def __repr__(self):
|
|
88
|
-
return f'rgba({self.r}, {self.g}, {self.b}{
|
|
91
|
+
return f'rgba({self.r}, {self.g}, {self.b}{"" if self.a is None else f", {self.a}"})'
|
|
89
92
|
|
|
90
93
|
def __str__(self):
|
|
91
|
-
return f'({self.r}, {self.g}, {self.b}{
|
|
94
|
+
return f'({self.r}, {self.g}, {self.b}{"" if self.a is None else f", {self.a}"})'
|
|
92
95
|
|
|
93
96
|
def __eq__(self, other):
|
|
94
97
|
if not isinstance(other, rgba):
|
|
@@ -102,7 +105,7 @@ class rgba:
|
|
|
102
105
|
|
|
103
106
|
def dict(self) -> dict:
|
|
104
107
|
"""Returns the color components as a dictionary with keys `'r'`, `'g'`, `'b'` and optionally `'a'`"""
|
|
105
|
-
return dict(r=self.r, g=self.g, b=self.b
|
|
108
|
+
return dict(r=self.r, g=self.g, b=self.b) if self.a is None else dict(r=self.r, g=self.g, b=self.b, a=self.a)
|
|
106
109
|
|
|
107
110
|
def values(self) -> tuple:
|
|
108
111
|
"""Returns the color components as separate values `r, g, b, a`"""
|
|
@@ -110,11 +113,11 @@ class rgba:
|
|
|
110
113
|
|
|
111
114
|
def to_hsla(self) -> "hsla":
|
|
112
115
|
"""Returns the color as a `hsla()` color"""
|
|
113
|
-
return hsla(*self._rgb_to_hsl(self.r, self.g, self.b), self.a)
|
|
116
|
+
return hsla(*self._rgb_to_hsl(self.r, self.g, self.b), self.a, _validate=False)
|
|
114
117
|
|
|
115
118
|
def to_hexa(self) -> "hexa":
|
|
116
119
|
"""Returns the color as a `hexa()` color"""
|
|
117
|
-
return hexa(
|
|
120
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
118
121
|
|
|
119
122
|
def has_alpha(self) -> bool:
|
|
120
123
|
"""Returns `True` if the color has an alpha channel and `False` otherwise"""
|
|
@@ -123,39 +126,39 @@ class rgba:
|
|
|
123
126
|
def lighten(self, amount: float) -> "rgba":
|
|
124
127
|
"""Increases the colors lightness by the specified amount (`0.0`-`1.0`)"""
|
|
125
128
|
self.r, self.g, self.b, self.a = self.to_hsla().lighten(amount).to_rgba().values()
|
|
126
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
129
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
127
130
|
|
|
128
131
|
def darken(self, amount: float) -> "rgba":
|
|
129
132
|
"""Decreases the colors lightness by the specified amount (`0.0`-`1.0`)"""
|
|
130
133
|
self.r, self.g, self.b, self.a = self.to_hsla().darken(amount).to_rgba().values()
|
|
131
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
134
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
132
135
|
|
|
133
136
|
def saturate(self, amount: float) -> "rgba":
|
|
134
137
|
"""Increases the colors saturation by the specified amount (`0.0`-`1.0`)"""
|
|
135
138
|
self.r, self.g, self.b, self.a = self.to_hsla().saturate(amount).to_rgba().values()
|
|
136
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
139
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
137
140
|
|
|
138
141
|
def desaturate(self, amount: float) -> "rgba":
|
|
139
142
|
"""Decreases the colors saturation by the specified amount (`0.0`-`1.0`)"""
|
|
140
143
|
self.r, self.g, self.b, self.a = self.to_hsla().desaturate(amount).to_rgba().values()
|
|
141
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
144
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
142
145
|
|
|
143
146
|
def rotate(self, degrees: int) -> "rgba":
|
|
144
147
|
"""Rotates the colors hue by the specified number of degrees"""
|
|
145
148
|
self.r, self.g, self.b, self.a = self.to_hsla().rotate(degrees).to_rgba().values()
|
|
146
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
149
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
147
150
|
|
|
148
151
|
def invert(self, invert_alpha: bool = False) -> "rgba":
|
|
149
152
|
"""Inverts the color by rotating hue by 180 degrees and inverting lightness"""
|
|
150
153
|
self.r, self.g, self.b = 255 - self.r, 255 - self.g, 255 - self.b
|
|
151
154
|
if invert_alpha:
|
|
152
155
|
self.a = 1 - self.a
|
|
153
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
156
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
154
157
|
|
|
155
158
|
def grayscale(self) -> "rgba":
|
|
156
159
|
"""Converts the color to grayscale using the luminance formula"""
|
|
157
160
|
self.r = self.g = self.b = Color.luminance(self.r, self.g, self.b)
|
|
158
|
-
return rgba(self.r, self.g, self.b, self.a)
|
|
161
|
+
return rgba(self.r, self.g, self.b, self.a, _validate=False)
|
|
159
162
|
|
|
160
163
|
def blend(self, other: "rgba", ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
|
|
161
164
|
"""Blends the current color with another color using the specified ratio (`0.0`-`1.0`):
|
|
@@ -166,7 +169,7 @@ class rgba:
|
|
|
166
169
|
raise ValueError("'ratio' must be a float/int in [0.0, 1.0]")
|
|
167
170
|
elif not isinstance(other, rgba):
|
|
168
171
|
if Color.is_valid_rgba(other):
|
|
169
|
-
other = rgba(*other)
|
|
172
|
+
other = rgba(*other, _validate=False)
|
|
170
173
|
else:
|
|
171
174
|
raise TypeError("'other' must be a valid RGBA color")
|
|
172
175
|
ratio *= 2
|
|
@@ -175,7 +178,7 @@ class rgba:
|
|
|
175
178
|
self.b = max(0, min(255, int(round((self.b * (2 - ratio)) + (other.b * ratio)))))
|
|
176
179
|
none_alpha = self.a is None and (len(other) <= 3 or other[3] is None)
|
|
177
180
|
if not none_alpha:
|
|
178
|
-
self_a =
|
|
181
|
+
self_a = 1 if self.a is None else self.a
|
|
179
182
|
other_a = (other[3] if other[3] is not None else 1) if len(other) > 3 else 1
|
|
180
183
|
if additive_alpha:
|
|
181
184
|
self.a = max(0, min(1, (self_a * (2 - ratio)) + (other_a * ratio)))
|
|
@@ -189,11 +192,11 @@ class rgba:
|
|
|
189
192
|
)
|
|
190
193
|
else:
|
|
191
194
|
self.a = None
|
|
192
|
-
return rgba(self.r, self.g, self.b, None if none_alpha else self.a)
|
|
195
|
+
return rgba(self.r, self.g, self.b, None if none_alpha else self.a, _validate=False)
|
|
193
196
|
|
|
194
197
|
def is_dark(self) -> bool:
|
|
195
198
|
"""Returns `True` if the color is considered dark (`lightness < 50%`)"""
|
|
196
|
-
return
|
|
199
|
+
return self.to_hsla().is_dark()
|
|
197
200
|
|
|
198
201
|
def is_light(self) -> bool:
|
|
199
202
|
"""Returns `True` if the color is considered light (`lightness >= 50%`)"""
|
|
@@ -211,7 +214,7 @@ class rgba:
|
|
|
211
214
|
"""Returns a new color with the specified alpha value"""
|
|
212
215
|
if not (isinstance(alpha, (int, float)) and 0 <= alpha <= 1):
|
|
213
216
|
raise ValueError("'alpha' must be a float/int in [0.0, 1.0]")
|
|
214
|
-
return rgba(self.r, self.g, self.b, alpha)
|
|
217
|
+
return rgba(self.r, self.g, self.b, alpha, _validate=False)
|
|
215
218
|
|
|
216
219
|
def complementary(self) -> "rgba":
|
|
217
220
|
"""Returns the complementary color (180 degrees on the color wheel)"""
|
|
@@ -259,7 +262,10 @@ class hsla:
|
|
|
259
262
|
- `with_alpha(alpha)` to create a new color with different alpha
|
|
260
263
|
- `complementary()` to get the complementary color"""
|
|
261
264
|
|
|
262
|
-
def __init__(self, h: int, s: int, l: int, a: float = None):
|
|
265
|
+
def __init__(self, h: int, s: int, l: int, a: float = None, _validate: bool = True):
|
|
266
|
+
if not _validate:
|
|
267
|
+
self.h, self.s, self.l, self.a = h, s, l, a
|
|
268
|
+
return
|
|
263
269
|
if any(isinstance(x, hsla) for x in (h, s, l)):
|
|
264
270
|
raise ValueError("Color is already a hsla() color")
|
|
265
271
|
elif not (isinstance(h, int) and (0 <= h <= 360) and all(isinstance(x, int) and (0 <= x <= 100) for x in (s, l))):
|
|
@@ -270,25 +276,25 @@ class hsla:
|
|
|
270
276
|
elif a is not None and (not isinstance(a, (int, float)) or not 0 <= a <= 1):
|
|
271
277
|
raise ValueError(f"Alpha channel must be a float/int in [0.0, 1.0]: got '{a}'")
|
|
272
278
|
self.h, self.s, self.l = h, s, l
|
|
273
|
-
self.a = (1.0 if a > 1.0 else float(a))
|
|
279
|
+
self.a = None if a is None else (1.0 if a > 1.0 else float(a))
|
|
274
280
|
|
|
275
281
|
def __len__(self):
|
|
276
|
-
return
|
|
282
|
+
return 3 if self.a is None else 4
|
|
277
283
|
|
|
278
284
|
def __iter__(self):
|
|
279
|
-
return iter((self.h, self.s, self.l) + ((
|
|
285
|
+
return iter((self.h, self.s, self.l) + (() if self.a is None else (self.a,)))
|
|
280
286
|
|
|
281
287
|
def __dict__(self):
|
|
282
288
|
return self.dict()
|
|
283
289
|
|
|
284
290
|
def __getitem__(self, index):
|
|
285
|
-
return ((self.h, self.s, self.l) + ((
|
|
291
|
+
return ((self.h, self.s, self.l) + (() if self.a is None else (self.a,)))[index]
|
|
286
292
|
|
|
287
293
|
def __repr__(self):
|
|
288
|
-
return f'hsla({self.h}, {self.s}, {self.l}{
|
|
294
|
+
return f'hsla({self.h}, {self.s}, {self.l}{"" if self.a is None else f", {self.a}"})'
|
|
289
295
|
|
|
290
296
|
def __str__(self):
|
|
291
|
-
return f'({self.h}, {self.s}, {self.l}{
|
|
297
|
+
return f'({self.h}, {self.s}, {self.l}{"" if self.a is None else f", {self.a}"})'
|
|
292
298
|
|
|
293
299
|
def __eq__(self, other):
|
|
294
300
|
if not isinstance(other, hsla):
|
|
@@ -302,7 +308,7 @@ class hsla:
|
|
|
302
308
|
|
|
303
309
|
def dict(self) -> dict:
|
|
304
310
|
"""Returns the color components as a dictionary with keys `'h'`, `'s'`, `'l'` and optionally `'a'`"""
|
|
305
|
-
return dict(h=self.h, s=self.s, l=self.l
|
|
311
|
+
return dict(h=self.h, s=self.s, l=self.l) if self.a is None else dict(h=self.h, s=self.s, l=self.l, a=self.a)
|
|
306
312
|
|
|
307
313
|
def values(self) -> tuple:
|
|
308
314
|
"""Returns the color components as separate values `h, s, l, a`"""
|
|
@@ -310,12 +316,12 @@ class hsla:
|
|
|
310
316
|
|
|
311
317
|
def to_rgba(self) -> "rgba":
|
|
312
318
|
"""Returns the color as a `rgba()` color"""
|
|
313
|
-
return rgba(*self._hsl_to_rgb(self.h, self.s, self.l), self.a)
|
|
319
|
+
return rgba(*self._hsl_to_rgb(self.h, self.s, self.l), self.a, _validate=False)
|
|
314
320
|
|
|
315
321
|
def to_hexa(self) -> "hexa":
|
|
316
322
|
"""Returns the color as a `hexa()` color"""
|
|
317
323
|
r, g, b = self._hsl_to_rgb(self.h, self.s, self.l)
|
|
318
|
-
return hexa(
|
|
324
|
+
return hexa("", r, g, b, self.a)
|
|
319
325
|
|
|
320
326
|
def has_alpha(self) -> bool:
|
|
321
327
|
"""Returns `True` if the color has an alpha channel and `False` otherwise"""
|
|
@@ -326,33 +332,33 @@ class hsla:
|
|
|
326
332
|
if not (isinstance(amount, (int, float)) and 0 <= amount <= 1):
|
|
327
333
|
raise ValueError("'amount' must be a float/int in [0.0, 1.0]")
|
|
328
334
|
self.l = int(min(100, self.l + (100 - self.l) * amount))
|
|
329
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
335
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
330
336
|
|
|
331
337
|
def darken(self, amount: float) -> "hsla":
|
|
332
338
|
"""Decreases the colors lightness by the specified amount (`0.0`-`1.0`)"""
|
|
333
339
|
if not (isinstance(amount, (int, float)) and 0 <= amount <= 1):
|
|
334
340
|
raise ValueError("'amount' must be a float/int in [0.0, 1.0]")
|
|
335
341
|
self.l = int(max(0, self.l * (1 - amount)))
|
|
336
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
342
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
337
343
|
|
|
338
344
|
def saturate(self, amount: float) -> "hsla":
|
|
339
345
|
"""Increases the colors saturation by the specified amount (`0.0`-`1.0`)"""
|
|
340
346
|
if not (isinstance(amount, (int, float)) and 0 <= amount <= 1):
|
|
341
347
|
raise ValueError("'amount' must be a float/int in [0.0, 1.0]")
|
|
342
348
|
self.s = int(min(100, self.s + (100 - self.s) * amount))
|
|
343
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
349
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
344
350
|
|
|
345
351
|
def desaturate(self, amount: float) -> "hsla":
|
|
346
352
|
"""Decreases the colors saturation by the specified amount (`0.0`-`1.0`)"""
|
|
347
353
|
if not (isinstance(amount, (int, float)) and 0 <= amount <= 1):
|
|
348
354
|
raise ValueError("'amount' must be a float/int in [0.0, 1.0]")
|
|
349
355
|
self.s = int(max(0, self.s * (1 - amount)))
|
|
350
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
356
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
351
357
|
|
|
352
358
|
def rotate(self, degrees: int) -> "hsla":
|
|
353
359
|
"""Rotates the colors hue by the specified number of degrees"""
|
|
354
360
|
self.h = (self.h + degrees) % 360
|
|
355
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
361
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
356
362
|
|
|
357
363
|
def invert(self, invert_alpha: bool = False) -> "hsla":
|
|
358
364
|
"""Inverts the color by rotating hue by 180 degrees and inverting lightness"""
|
|
@@ -360,13 +366,13 @@ class hsla:
|
|
|
360
366
|
self.l = 100 - self.l
|
|
361
367
|
if invert_alpha:
|
|
362
368
|
self.a = 1 - self.a
|
|
363
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
369
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
364
370
|
|
|
365
371
|
def grayscale(self) -> "hsla":
|
|
366
372
|
"""Converts the color to grayscale using the luminance formula"""
|
|
367
373
|
l = Color.luminance(*self._hsl_to_rgb(self.h, self.s, self.l))
|
|
368
|
-
self.h, self.s, self.l, _ = rgba(l, l, l).to_hsla().values()
|
|
369
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
374
|
+
self.h, self.s, self.l, _ = rgba(l, l, l, _validate=False).to_hsla().values()
|
|
375
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
370
376
|
|
|
371
377
|
def blend(self, other: "hsla", ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
|
|
372
378
|
"""Blends the current color with another color using the specified ratio (`0.0`-`1.0`):
|
|
@@ -374,7 +380,7 @@ class hsla:
|
|
|
374
380
|
- if `ratio` is `0.5` it means 50% of both colors (1:1 mixture)
|
|
375
381
|
- if `ratio` is `1.0` it means 0% of the current color and 100% of the `other` color (0:2 mixture)"""
|
|
376
382
|
self.h, self.s, self.l, self.a = self.to_rgba().blend(Color.to_rgba(other), ratio, additive_alpha).to_hsla().values()
|
|
377
|
-
return hsla(self.h, self.s, self.l, self.a)
|
|
383
|
+
return hsla(self.h, self.s, self.l, self.a, _validate=False)
|
|
378
384
|
|
|
379
385
|
def is_dark(self) -> bool:
|
|
380
386
|
"""Returns `True` if the color is considered dark (`lightness < 50%`)"""
|
|
@@ -396,11 +402,11 @@ class hsla:
|
|
|
396
402
|
"""Returns a new color with the specified alpha value"""
|
|
397
403
|
if not (isinstance(alpha, (int, float)) and 0 <= alpha <= 1):
|
|
398
404
|
raise ValueError("'alpha' must be a float/int in [0.0, 1.0]")
|
|
399
|
-
return hsla(self.h, self.s, self.l, alpha)
|
|
405
|
+
return hsla(self.h, self.s, self.l, alpha, _validate=False)
|
|
400
406
|
|
|
401
407
|
def complementary(self) -> "hsla":
|
|
402
408
|
"""Returns the complementary color (180 degrees on the color wheel)"""
|
|
403
|
-
return hsla((self.h + 180) % 360, self.s, self.l, self.a)
|
|
409
|
+
return hsla((self.h + 180) % 360, self.s, self.l, self.a, _validate=False)
|
|
404
410
|
|
|
405
411
|
def _hsl_to_rgb(self, h: int, s: int, l: int) -> tuple:
|
|
406
412
|
h, s, l = h / 360, s / 100, l / 100
|
|
@@ -452,7 +458,10 @@ class hexa:
|
|
|
452
458
|
- `with_alpha(alpha)` to create a new color with different alpha
|
|
453
459
|
- `complementary()` to get the complementary color"""
|
|
454
460
|
|
|
455
|
-
def __init__(self, color: str | int):
|
|
461
|
+
def __init__(self, color: str | int, _r: int = None, _g: int = None, _b: int = None, _a: float = None):
|
|
462
|
+
if all(x is not None for x in (_r, _g, _b)):
|
|
463
|
+
self.r, self.g, self.b, self.a = _r, _g, _b, _a
|
|
464
|
+
return
|
|
456
465
|
if isinstance(color, hexa):
|
|
457
466
|
raise ValueError("Color is already a hexa() color")
|
|
458
467
|
if isinstance(color, str):
|
|
@@ -491,27 +500,31 @@ class hexa:
|
|
|
491
500
|
else:
|
|
492
501
|
raise ValueError(f"Invalid HEX format '{color}'")
|
|
493
502
|
elif isinstance(color, int):
|
|
494
|
-
self.r, self.g, self.b, self.a = Color.hex_int_to_rgba(color)
|
|
503
|
+
self.r, self.g, self.b, self.a = Color.hex_int_to_rgba(color).values()
|
|
495
504
|
else:
|
|
496
505
|
raise TypeError(f"HEX color must be of type 'str' or 'int': got '{type(color)}'")
|
|
497
506
|
|
|
498
507
|
def __len__(self):
|
|
499
|
-
return
|
|
508
|
+
return 3 if self.a is None else 4
|
|
500
509
|
|
|
501
510
|
def __iter__(self):
|
|
502
|
-
return iter(
|
|
511
|
+
return iter(
|
|
512
|
+
(f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}") + (() if self.a is None else (f"{int(self.a * 255):02X}",))
|
|
513
|
+
)
|
|
503
514
|
|
|
504
515
|
def __dict__(self):
|
|
505
516
|
return self.dict()
|
|
506
517
|
|
|
507
518
|
def __getitem__(self, index):
|
|
508
|
-
return (
|
|
519
|
+
return (
|
|
520
|
+
(f"{self.r:02X}", f"{self.g:02X}", f"{self.b:02X}") + (() if self.a is None else (f"{int(self.a * 255):02X}",))
|
|
521
|
+
)[index]
|
|
509
522
|
|
|
510
523
|
def __repr__(self):
|
|
511
|
-
return f'hexa(#{self.r:02X}{self.g:02X}{self.b:02X}{f"{int(self.a * 255):02X}"
|
|
524
|
+
return f'hexa(#{self.r:02X}{self.g:02X}{self.b:02X}{"" if self.a is None else f"{int(self.a * 255):02X}"})'
|
|
512
525
|
|
|
513
526
|
def __str__(self):
|
|
514
|
-
return f'#{self.r:02X}{self.g:02X}{self.b:02X}{f"{int(self.a * 255):02X}"
|
|
527
|
+
return f'#{self.r:02X}{self.g:02X}{self.b:02X}{"" if self.a is None else f"{int(self.a * 255):02X}"}'
|
|
515
528
|
|
|
516
529
|
def __eq__(self, other):
|
|
517
530
|
if not isinstance(other, hexa):
|
|
@@ -526,14 +539,14 @@ class hexa:
|
|
|
526
539
|
def dict(self) -> dict:
|
|
527
540
|
"""Returns the color components as a dictionary with hex string values for keys `'r'`, `'g'`, `'b'` and optionally `'a'`"""
|
|
528
541
|
return (
|
|
529
|
-
dict(
|
|
542
|
+
dict(r=f"{self.r:02X}", g=f"{self.g:02X}", b=f"{self.b:02X}")
|
|
543
|
+
if self.a is None
|
|
544
|
+
else dict(
|
|
530
545
|
r=f"{self.r:02X}",
|
|
531
546
|
g=f"{self.g:02X}",
|
|
532
547
|
b=f"{self.b:02X}",
|
|
533
548
|
a=f"{int(self.a * 255):02X}",
|
|
534
549
|
)
|
|
535
|
-
if self.a
|
|
536
|
-
else dict(r=f"{self.r:02X}", g=f"{self.g:02X}", b=f"{self.b:02X}")
|
|
537
550
|
)
|
|
538
551
|
|
|
539
552
|
def values(self) -> tuple:
|
|
@@ -546,7 +559,8 @@ class hexa:
|
|
|
546
559
|
self.r,
|
|
547
560
|
self.g,
|
|
548
561
|
self.b,
|
|
549
|
-
(round(self.a, 2) if round_alpha else self.a)
|
|
562
|
+
None if self.a is None else (round(self.a, 2) if round_alpha else self.a),
|
|
563
|
+
_validate=False,
|
|
550
564
|
)
|
|
551
565
|
|
|
552
566
|
def to_hsla(self, round_alpha: bool = True) -> "hsla":
|
|
@@ -560,39 +574,39 @@ class hexa:
|
|
|
560
574
|
def lighten(self, amount: float) -> "hexa":
|
|
561
575
|
"""Increases the colors lightness by the specified amount (`0.0`-`1.0`)"""
|
|
562
576
|
self.r, self.g, self.b, self.a = self.to_rgba(False).lighten(amount).values()
|
|
563
|
-
return hexa(
|
|
577
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
564
578
|
|
|
565
579
|
def darken(self, amount: float) -> "hexa":
|
|
566
580
|
"""Decreases the colors lightness by the specified amount (`0.0`-`1.0`)"""
|
|
567
581
|
self.r, self.g, self.b, self.a = self.to_rgba(False).darken(amount).values()
|
|
568
|
-
return hexa(
|
|
582
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
569
583
|
|
|
570
584
|
def saturate(self, amount: float) -> "hexa":
|
|
571
585
|
"""Increases the colors saturation by the specified amount (`0.0`-`1.0`)"""
|
|
572
586
|
self.r, self.g, self.b, self.a = self.to_rgba(False).saturate(amount).values()
|
|
573
|
-
return hexa(
|
|
587
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
574
588
|
|
|
575
589
|
def desaturate(self, amount: float) -> "hexa":
|
|
576
590
|
"""Decreases the colors saturation by the specified amount (`0.0`-`1.0`)"""
|
|
577
591
|
self.r, self.g, self.b, self.a = self.to_rgba(False).desaturate(amount).values()
|
|
578
|
-
return hexa(
|
|
592
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
579
593
|
|
|
580
594
|
def rotate(self, degrees: int) -> "hexa":
|
|
581
595
|
"""Rotates the colors hue by the specified number of degrees"""
|
|
582
596
|
self.r, self.g, self.b, self.a = self.to_rgba(False).rotate(degrees).values()
|
|
583
|
-
return hexa(
|
|
597
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
584
598
|
|
|
585
599
|
def invert(self, invert_alpha: bool = False) -> "hexa":
|
|
586
600
|
"""Inverts the color by rotating hue by 180 degrees and inverting lightness"""
|
|
587
601
|
self.r, self.g, self.b, self.a = self.to_rgba(False).invert().values()
|
|
588
602
|
if invert_alpha:
|
|
589
603
|
self.a = 1 - self.a
|
|
590
|
-
return hexa(
|
|
604
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
591
605
|
|
|
592
606
|
def grayscale(self) -> "hexa":
|
|
593
607
|
"""Converts the color to grayscale using the luminance formula"""
|
|
594
608
|
self.r = self.g = self.b = Color.luminance(self.r, self.g, self.b)
|
|
595
|
-
return hexa(
|
|
609
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
596
610
|
|
|
597
611
|
def blend(self, other: "hexa", ratio: float = 0.5, additive_alpha: bool = False) -> "rgba":
|
|
598
612
|
"""Blends the current color with another color using the specified ratio (`0.0`-`1.0`):
|
|
@@ -600,7 +614,7 @@ class hexa:
|
|
|
600
614
|
- if `ratio` is `0.5` it means 50% of both colors (1:1 mixture)
|
|
601
615
|
- if `ratio` is `1.0` it means 0% of the current color and 100% of the `other` color (0:2 mixture)"""
|
|
602
616
|
self.r, self.g, self.b, self.a = self.to_rgba(False).blend(Color.to_rgba(other), ratio, additive_alpha).values()
|
|
603
|
-
return hexa(
|
|
617
|
+
return hexa("", self.r, self.g, self.b, self.a)
|
|
604
618
|
|
|
605
619
|
def is_dark(self) -> bool:
|
|
606
620
|
"""Returns `True` if the color is considered dark (`lightness < 50%`)"""
|
|
@@ -608,7 +622,7 @@ class hexa:
|
|
|
608
622
|
|
|
609
623
|
def is_light(self) -> bool:
|
|
610
624
|
"""Returns `True` if the color is considered light (`lightness >= 50%`)"""
|
|
611
|
-
return self.
|
|
625
|
+
return not self.is_dark()
|
|
612
626
|
|
|
613
627
|
def is_grayscale(self) -> bool:
|
|
614
628
|
"""Returns `True` if the color is grayscale (`saturation == 0`)"""
|
|
@@ -616,13 +630,13 @@ class hexa:
|
|
|
616
630
|
|
|
617
631
|
def is_opaque(self) -> bool:
|
|
618
632
|
"""Returns `True` if the color has no transparency (`alpha == 1.0`)"""
|
|
619
|
-
return self.
|
|
633
|
+
return self.a == 1 or self.a is None
|
|
620
634
|
|
|
621
635
|
def with_alpha(self, alpha: float) -> "hexa":
|
|
622
636
|
"""Returns a new color with the specified alpha value"""
|
|
623
637
|
if not (isinstance(alpha, (int, float)) and 0 <= alpha <= 1):
|
|
624
638
|
raise ValueError("'alpha' must be in [0.0, 1.0]")
|
|
625
|
-
return hexa(
|
|
639
|
+
return hexa("", self.r, self.g, self.b, alpha)
|
|
626
640
|
|
|
627
641
|
def complementary(self) -> "hexa":
|
|
628
642
|
"""Returns the complementary color (180 degrees on the color wheel)"""
|
|
@@ -748,15 +762,11 @@ class Color:
|
|
|
748
762
|
if isinstance(color, (hsla, hexa)):
|
|
749
763
|
return color.to_rgba()
|
|
750
764
|
elif Color.is_valid_hsla(color):
|
|
751
|
-
return hsla(*color
|
|
765
|
+
return hsla(*color, _validate=False).to_rgba()
|
|
752
766
|
elif Color.is_valid_hexa(color):
|
|
753
767
|
return hexa(color).to_rgba()
|
|
754
768
|
elif Color.is_valid_rgba(color):
|
|
755
|
-
return (
|
|
756
|
-
color
|
|
757
|
-
if isinstance(color, rgba)
|
|
758
|
-
else (rgba(*color) if Color.has_alpha(color) else rgba(color[0], color[1], color[2]))
|
|
759
|
-
)
|
|
769
|
+
return color if isinstance(color, rgba) else (rgba(*color, _validate=False))
|
|
760
770
|
raise ValueError(f"Invalid color format '{color}'")
|
|
761
771
|
|
|
762
772
|
@staticmethod
|
|
@@ -765,15 +775,11 @@ class Color:
|
|
|
765
775
|
if isinstance(color, (rgba, hexa)):
|
|
766
776
|
return color.to_hsla()
|
|
767
777
|
elif Color.is_valid_rgba(color):
|
|
768
|
-
return rgba(*color
|
|
778
|
+
return rgba(*color, _validate=False).to_hsla()
|
|
769
779
|
elif Color.is_valid_hexa(color):
|
|
770
780
|
return hexa(color).to_hsla()
|
|
771
781
|
elif Color.is_valid_hsla(color):
|
|
772
|
-
return (
|
|
773
|
-
color
|
|
774
|
-
if isinstance(color, hsla)
|
|
775
|
-
else (hsla(*color) if Color.has_alpha(color) else hsla(color[0], color[1], color[2]))
|
|
776
|
-
)
|
|
782
|
+
return color if isinstance(color, hsla) else (hsla(*color, _validate=False))
|
|
777
783
|
raise ValueError(f"Invalid color format '{color}'")
|
|
778
784
|
|
|
779
785
|
@staticmethod
|
|
@@ -782,11 +788,11 @@ class Color:
|
|
|
782
788
|
if isinstance(color, (rgba, hsla)):
|
|
783
789
|
return color.to_hexa()
|
|
784
790
|
elif Color.is_valid_rgba(color):
|
|
785
|
-
return rgba(*color
|
|
791
|
+
return rgba(*color, _validate=False).to_hexa()
|
|
786
792
|
elif Color.is_valid_hsla(color):
|
|
787
|
-
return hsla(*color
|
|
793
|
+
return hsla(*color, _validate=False).to_hexa()
|
|
788
794
|
elif Color.is_valid_hexa(color):
|
|
789
|
-
return color if isinstance(color, hexa) else hexa(
|
|
795
|
+
return color if isinstance(color, hexa) else hexa(color)
|
|
790
796
|
raise ValueError(f"Invalid color format '{color}'")
|
|
791
797
|
|
|
792
798
|
@staticmethod
|
|
@@ -804,6 +810,7 @@ class Color:
|
|
|
804
810
|
int(m[1]),
|
|
805
811
|
int(m[2]),
|
|
806
812
|
((int(m[3]) if "." not in m[3] else float(m[3])) if m[3] else None),
|
|
813
|
+
_validate=False,
|
|
807
814
|
)
|
|
808
815
|
else:
|
|
809
816
|
matches = _re.findall(Regex.rgb_str(allow_alpha=True), string)
|
|
@@ -815,6 +822,7 @@ class Color:
|
|
|
815
822
|
int(m[1]),
|
|
816
823
|
int(m[2]),
|
|
817
824
|
((int(m[3]) if "." not in m[3] else float(m[3])) if m[3] else None),
|
|
825
|
+
_validate=False,
|
|
818
826
|
)
|
|
819
827
|
for m in matches
|
|
820
828
|
]
|
|
@@ -838,19 +846,19 @@ class Color:
|
|
|
838
846
|
r = max(0, min(255, int(r)))
|
|
839
847
|
g = max(0, min(255, int(g)))
|
|
840
848
|
b = max(0, min(255, int(b)))
|
|
841
|
-
if a is
|
|
849
|
+
if a is None:
|
|
850
|
+
hex_int = (r << 16) | (g << 8) | b
|
|
851
|
+
if not preserve_original and (hex_int & 0xF00000) == 0:
|
|
852
|
+
hex_int |= 0x010000
|
|
853
|
+
else:
|
|
842
854
|
a = max(0, min(255, int(a * 255)))
|
|
843
855
|
hex_int = (r << 24) | (g << 16) | (b << 8) | a
|
|
844
856
|
if not preserve_original and r == 0:
|
|
845
857
|
hex_int |= 0x01000000
|
|
846
|
-
else:
|
|
847
|
-
hex_int = (r << 16) | (g << 8) | b
|
|
848
|
-
if not preserve_original and (hex_int & 0xF00000) == 0:
|
|
849
|
-
hex_int |= 0x010000
|
|
850
858
|
return hex_int
|
|
851
859
|
|
|
852
860
|
@staticmethod
|
|
853
|
-
def hex_int_to_rgba(hex_int: int, preserve_original: bool = False) ->
|
|
861
|
+
def hex_int_to_rgba(hex_int: int, preserve_original: bool = False) -> rgba:
|
|
854
862
|
"""Convert a HEX integer to RGBA channels.\n
|
|
855
863
|
-------------------------------------------------------------------------------------------
|
|
856
864
|
If the red channel is `1` after conversion, it will be set to `0`, because when converting
|
|
@@ -862,19 +870,21 @@ class Color:
|
|
|
862
870
|
hex_str = f"{hex_int:x}"
|
|
863
871
|
if len(hex_str) <= 6:
|
|
864
872
|
hex_str = hex_str.zfill(6)
|
|
865
|
-
return (
|
|
873
|
+
return rgba(
|
|
866
874
|
r if (r := int(hex_str[0:2], 16)) != 1 or preserve_original else 0,
|
|
867
875
|
int(hex_str[2:4], 16),
|
|
868
876
|
int(hex_str[4:6], 16),
|
|
869
877
|
None,
|
|
878
|
+
_validate=False,
|
|
870
879
|
)
|
|
871
880
|
elif len(hex_str) <= 8:
|
|
872
881
|
hex_str = hex_str.zfill(8)
|
|
873
|
-
return (
|
|
882
|
+
return rgba(
|
|
874
883
|
r if (r := int(hex_str[0:2], 16)) != 1 or preserve_original else 0,
|
|
875
884
|
int(hex_str[2:4], 16),
|
|
876
885
|
int(hex_str[4:6], 16),
|
|
877
886
|
int(hex_str[6:8], 16) / 255.0,
|
|
887
|
+
_validate=False,
|
|
878
888
|
)
|
|
879
889
|
else:
|
|
880
890
|
raise ValueError(f"Invalid HEX integer '0x{hex_str}': expected in range [0x000000, 0xFFFFFF]")
|
|
@@ -911,9 +921,9 @@ class Color:
|
|
|
911
921
|
text_bg_color = Color.to_rgba(text_bg_color)
|
|
912
922
|
brightness = 0.2126 * text_bg_color[0] + 0.7152 * text_bg_color[1] + 0.0722 * text_bg_color[2]
|
|
913
923
|
return (
|
|
914
|
-
(hexa("
|
|
924
|
+
(hexa("", 255, 255, 255) if was_hexa else rgba(255, 255, 255, _validate=False))
|
|
915
925
|
if brightness < 128
|
|
916
|
-
else ((0x000 if was_int else hexa("
|
|
926
|
+
else ((0x000 if was_int else hexa("", 0, 0, 0)) if was_hexa else rgba(0, 0, 0, _validate=False))
|
|
917
927
|
)
|
|
918
928
|
|
|
919
929
|
@staticmethod
|
|
@@ -933,7 +943,7 @@ class Color:
|
|
|
933
943
|
color[3] if Color.has_alpha(color) else None,
|
|
934
944
|
)
|
|
935
945
|
l = int(max(0, min(100, l + lightness_change * 100)))
|
|
936
|
-
return
|
|
946
|
+
return hsla(h, s, l, a, _validate=False).to_hexa() if was_hexa else hsla(h, s, l, a, _validate=False).to_rgba()
|
|
937
947
|
|
|
938
948
|
@staticmethod
|
|
939
949
|
def adjust_saturation(color: rgba | hexa, saturation_change: float) -> rgba | hexa:
|
|
@@ -952,4 +962,4 @@ class Color:
|
|
|
952
962
|
color[3] if Color.has_alpha(color) else None,
|
|
953
963
|
)
|
|
954
964
|
s = int(max(0, min(100, s + saturation_change * 100)))
|
|
955
|
-
return
|
|
965
|
+
return hsla(h, s, l, a, _validate=False).to_hexa() if was_hexa else hsla(h, s, l, a, _validate=False).to_rgba()
|
xulbux/xx_console.py
CHANGED
|
@@ -29,7 +29,6 @@ from contextlib import suppress
|
|
|
29
29
|
import pyperclip as _pyperclip
|
|
30
30
|
import keyboard as _keyboard
|
|
31
31
|
import getpass as _getpass
|
|
32
|
-
import ctypes as _ctypes
|
|
33
32
|
import shutil as _shutil
|
|
34
33
|
import mouse as _mouse
|
|
35
34
|
import sys as _sys
|
|
@@ -67,17 +66,6 @@ class Console:
|
|
|
67
66
|
def user() -> str:
|
|
68
67
|
return _os.getenv("USER") or _os.getenv("USERNAME") or _getpass.getuser()
|
|
69
68
|
|
|
70
|
-
def is_admin() -> bool:
|
|
71
|
-
try:
|
|
72
|
-
if _os.name == "nt":
|
|
73
|
-
return _ctypes.windll.shell32.IsUserAnAdmin() != 0
|
|
74
|
-
elif _os.name == "posix":
|
|
75
|
-
return _os.geteuid() == 0
|
|
76
|
-
else:
|
|
77
|
-
return False
|
|
78
|
-
except Exception:
|
|
79
|
-
return False
|
|
80
|
-
|
|
81
69
|
@staticmethod
|
|
82
70
|
def pause_exit(
|
|
83
71
|
pause: bool = False,
|