e2D 1.4.20__tar.gz → 1.4.21__tar.gz
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.
- {e2d-1.4.20 → e2d-1.4.21}/PKG-INFO +1 -1
- {e2d-1.4.20 → e2d-1.4.21}/e2D/__init__.py +50 -7
- {e2d-1.4.20 → e2d-1.4.21}/e2D/__init__.pyi +245 -5
- {e2d-1.4.20 → e2d-1.4.21}/e2D/colors.py +40 -20
- {e2d-1.4.20 → e2d-1.4.21}/e2D/envs.py +34 -10
- {e2d-1.4.20 → e2d-1.4.21}/e2D/utils.py +104 -72
- {e2d-1.4.20 → e2d-1.4.21}/e2D.egg-info/PKG-INFO +1 -1
- {e2d-1.4.20 → e2d-1.4.21}/setup.cfg +1 -1
- {e2d-1.4.20 → e2d-1.4.21}/LICENSE +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/README.md +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D/def_colors.py +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D/plots.py +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D/winrec.py +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D.egg-info/SOURCES.txt +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D.egg-info/dependency_links.txt +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D.egg-info/requires.txt +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/e2D.egg-info/top_level.txt +0 -0
- {e2d-1.4.20 → e2d-1.4.21}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: e2D
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.21
|
|
4
4
|
Summary: Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
|
|
5
5
|
Home-page: https://github.com/marick-py/e2D
|
|
6
6
|
Author: Riccardo Mariani
|
|
@@ -35,6 +35,22 @@ class Vector2D:
|
|
|
35
35
|
@angle.setter
|
|
36
36
|
def angle(self, new_angle) -> None:
|
|
37
37
|
self.rotate(new_angle - self.angle)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def aspect_x(self) -> float:
|
|
41
|
+
return self.x / self.y if self.y != 0 else 0
|
|
42
|
+
|
|
43
|
+
@aspect_x.setter
|
|
44
|
+
def aspect_x(self, new_aspect) -> None:
|
|
45
|
+
self.x = self.y * new_aspect
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def aspect_y(self) -> float:
|
|
49
|
+
return self.y / self.x if self.x != 0 else 0
|
|
50
|
+
|
|
51
|
+
@aspect_y.setter
|
|
52
|
+
def aspect_y(self, new_aspect) -> None:
|
|
53
|
+
self.y = self.x * new_aspect
|
|
38
54
|
|
|
39
55
|
@property
|
|
40
56
|
def copy(self) -> "Vector2D":
|
|
@@ -52,7 +68,7 @@ class Vector2D:
|
|
|
52
68
|
self.y = clamp(self.y, min_val.y, max_val.y)
|
|
53
69
|
|
|
54
70
|
@property
|
|
55
|
-
def
|
|
71
|
+
def normalized(self) -> "Vector2D":
|
|
56
72
|
if (mag:=self.length) == 0:
|
|
57
73
|
return self.copy
|
|
58
74
|
return Vector2D(self.x / mag, self.y / mag)
|
|
@@ -60,11 +76,31 @@ class Vector2D:
|
|
|
60
76
|
@property
|
|
61
77
|
def length(self) -> float:
|
|
62
78
|
return (self.x ** 2 + self.y ** 2) ** .5
|
|
63
|
-
|
|
79
|
+
|
|
80
|
+
@length.setter
|
|
81
|
+
def length(self, new_length: float) -> None:
|
|
82
|
+
current_length = self.length
|
|
83
|
+
if current_length == 0:
|
|
84
|
+
self.x = new_length
|
|
85
|
+
self.y = 0
|
|
86
|
+
else:
|
|
87
|
+
self.x *= new_length / current_length
|
|
88
|
+
self.y *= new_length / current_length
|
|
89
|
+
|
|
64
90
|
@property
|
|
65
91
|
def length_sqrd(self) -> float:
|
|
66
92
|
return self.x ** 2 + self.y ** 2
|
|
67
|
-
|
|
93
|
+
|
|
94
|
+
@length_sqrd.setter
|
|
95
|
+
def length_sqrd(self, new_length_sqrd: float) -> None:
|
|
96
|
+
current_length = self.length
|
|
97
|
+
if current_length == 0:
|
|
98
|
+
self.x = _mt.sqrt(new_length_sqrd)
|
|
99
|
+
self.y = 0
|
|
100
|
+
else:
|
|
101
|
+
self.x *= _mt.sqrt(new_length_sqrd) / current_length
|
|
102
|
+
self.y *= _mt.sqrt(new_length_sqrd) / current_length
|
|
103
|
+
|
|
68
104
|
@property
|
|
69
105
|
def inverse(self) -> "Vector2D":
|
|
70
106
|
return self.mult(-1)
|
|
@@ -119,6 +155,13 @@ class Vector2D:
|
|
|
119
155
|
def complex_to_cartesian(cls, complex_n) -> "Vector2D":
|
|
120
156
|
return cls(complex_n.real, complex_n.imag)
|
|
121
157
|
|
|
158
|
+
def cartesian_to_linear(self, size) -> int:
|
|
159
|
+
return int(self.x + self.y * size)
|
|
160
|
+
|
|
161
|
+
@classmethod
|
|
162
|
+
def linear_to_cartesian(cls, linear, size) -> "Vector2D":
|
|
163
|
+
return cls(linear % size, linear // size)
|
|
164
|
+
|
|
122
165
|
def lerp(self, other, t=.1) -> "Vector2D":
|
|
123
166
|
return Vector2D(self.x + (other.x - self.x) * t, self.y + (other.y - self.y) * t)
|
|
124
167
|
|
|
@@ -495,10 +538,10 @@ V2down_right = Vector2D(1, -1)
|
|
|
495
538
|
V2up_left = Vector2D(-1, 1)
|
|
496
539
|
V2down_left = Vector2D(-1, -1)
|
|
497
540
|
|
|
498
|
-
V2up_right_norm = V2up_right.
|
|
499
|
-
V2down_right_norm = V2down_right.
|
|
500
|
-
V2up_left_norm = V2up_left.
|
|
501
|
-
V2down_left_norm = V2down_left.
|
|
541
|
+
V2up_right_norm = V2up_right.normalized
|
|
542
|
+
V2down_right_norm = V2down_right.normalized
|
|
543
|
+
V2up_left_norm = V2up_left.normalized
|
|
544
|
+
V2down_left_norm = V2down_left.normalized
|
|
502
545
|
|
|
503
546
|
VECTORS_4_DIRECTIONS = (V2right, V2down, V2left, V2up)
|
|
504
547
|
VECTORS_4_SEMIDIRECTIONS = (V2down_right, V2down_left, V2up_left, V2up_right)
|
|
@@ -141,10 +141,59 @@ class Vector2D:
|
|
|
141
141
|
...
|
|
142
142
|
|
|
143
143
|
@property
|
|
144
|
-
def angle(self:"Vector2D") -> int|float:
|
|
144
|
+
def angle(self:"Vector2D") -> int|float:
|
|
145
|
+
"""
|
|
146
|
+
# Vector Angle
|
|
147
|
+
## Returns:
|
|
148
|
+
float: The angle (in radians) of the vector from the positive x-axis.
|
|
149
|
+
## Example:
|
|
150
|
+
v = Vector2D(1, 1)
|
|
151
|
+
angle = v.angle
|
|
152
|
+
print(angle) # Output: 0.7853981633974483
|
|
153
|
+
## Explanation:
|
|
154
|
+
This property calculates the angle of the vector from the positive x-axis using the `atan2` function.
|
|
155
|
+
"""
|
|
156
|
+
...
|
|
145
157
|
|
|
146
158
|
@angle.setter
|
|
147
|
-
def angle(self:"Vector2D", argv) -> None:
|
|
159
|
+
def angle(self:"Vector2D", argv) -> None:
|
|
160
|
+
...
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def aspect_x(self: "Vector2D") -> float:
|
|
164
|
+
"""
|
|
165
|
+
# Aspect Ratio (X over Y)
|
|
166
|
+
## Returns:
|
|
167
|
+
float: The aspect ratio of the vector, calculated as the x component divided by the y component. Returns 0 if the y component is zero.
|
|
168
|
+
## Example:
|
|
169
|
+
v = Vector2D(4, 2)
|
|
170
|
+
aspect = v.aspect_x
|
|
171
|
+
print(aspect) # Output: 2.0
|
|
172
|
+
## Explanation:
|
|
173
|
+
This property computes the ratio of the x component to the y component of the vector. If the y component is zero, it returns 0 to avoid division by zero.
|
|
174
|
+
"""
|
|
175
|
+
...
|
|
176
|
+
|
|
177
|
+
@aspect_x.setter
|
|
178
|
+
def aspect_x(self: "Vector2D", new_aspect) -> None: ...
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def aspect_y(self: "Vector2D") -> float:
|
|
182
|
+
"""
|
|
183
|
+
# Aspect Ratio (Y over X)
|
|
184
|
+
## Returns:
|
|
185
|
+
float: The aspect ratio of the vector, calculated as the y component divided by the x component. Returns 0 if the x component is zero.
|
|
186
|
+
## Example:
|
|
187
|
+
v = Vector2D(2, 4)
|
|
188
|
+
aspect = v.aspect_y
|
|
189
|
+
print(aspect) # Output: 2.0
|
|
190
|
+
## Explanation:
|
|
191
|
+
This property computes the ratio of the y component to the x component of the vector. If the x component is zero, it returns 0 to avoid division by zero.
|
|
192
|
+
"""
|
|
193
|
+
...
|
|
194
|
+
|
|
195
|
+
@aspect_y.setter
|
|
196
|
+
def aspect_y(self: "Vector2D", new_aspect) -> None: ...
|
|
148
197
|
|
|
149
198
|
@property
|
|
150
199
|
def copy(self:"Vector2D") -> "Vector2D":
|
|
@@ -261,7 +310,7 @@ class Vector2D:
|
|
|
261
310
|
...
|
|
262
311
|
|
|
263
312
|
@property
|
|
264
|
-
def
|
|
313
|
+
def normalized(self:"Vector2D") -> "Vector2D":
|
|
265
314
|
"""
|
|
266
315
|
# Vector Normalization
|
|
267
316
|
|
|
@@ -273,7 +322,7 @@ class Vector2D:
|
|
|
273
322
|
|
|
274
323
|
## Example:
|
|
275
324
|
v = Vector2D(3, 4)
|
|
276
|
-
normalized_v = v.
|
|
325
|
+
normalized_v = v.normalized() # Normalize the vector (3, 4)
|
|
277
326
|
print(normalized_v) # Output: (0.6, 0.8)
|
|
278
327
|
|
|
279
328
|
## Explanation:
|
|
@@ -293,23 +342,123 @@ class Vector2D:
|
|
|
293
342
|
|
|
294
343
|
@property
|
|
295
344
|
def length(self:"Vector2D") -> float:
|
|
345
|
+
"""
|
|
346
|
+
# Vector Length
|
|
347
|
+
|
|
348
|
+
## Returns:
|
|
349
|
+
float: The length (magnitude) of the vector.
|
|
350
|
+
|
|
351
|
+
## Example:
|
|
352
|
+
v = Vector2D(3, 4)
|
|
353
|
+
length = v.length
|
|
354
|
+
print(length) # Output: 5.0
|
|
355
|
+
|
|
356
|
+
## Explanation:
|
|
357
|
+
This property calculates the length (magnitude) of the vector using the Pythagorean theorem.
|
|
358
|
+
"""
|
|
296
359
|
...
|
|
297
360
|
|
|
298
361
|
@property
|
|
299
362
|
def length_sqrd(self:"Vector2D") -> float:
|
|
363
|
+
"""
|
|
364
|
+
# Vector Length Squared
|
|
365
|
+
|
|
366
|
+
## Returns:
|
|
367
|
+
float: The squared length (magnitude) of the vector.
|
|
368
|
+
|
|
369
|
+
## Example:
|
|
370
|
+
v = Vector2D(3, 4)
|
|
371
|
+
length_sqrd = v.length_sqrd
|
|
372
|
+
print(length_sqrd) # Output: 25
|
|
373
|
+
|
|
374
|
+
## Explanation:
|
|
375
|
+
This property calculates the squared length (magnitude) of the vector.
|
|
376
|
+
It is more efficient than calculating the actual length, as it avoids the
|
|
377
|
+
square root calculation.
|
|
378
|
+
"""
|
|
300
379
|
...
|
|
301
380
|
|
|
302
381
|
@property
|
|
303
382
|
def inverse(self:"Vector2D") -> "Vector2D":
|
|
383
|
+
"""
|
|
384
|
+
# Vector Inversion
|
|
385
|
+
|
|
386
|
+
## Returns:
|
|
387
|
+
Vector2D: A new vector with inverted components.
|
|
388
|
+
|
|
389
|
+
## Example:
|
|
390
|
+
v = Vector2D(3, 4)
|
|
391
|
+
inverted_v = v.inverse()
|
|
392
|
+
print(inverted_v) # Output: (-3, -4)
|
|
393
|
+
|
|
394
|
+
## Explanation:
|
|
395
|
+
This method calculates the inverted version of the current vector, which means a new vector with the same magnitude
|
|
396
|
+
but opposite direction.
|
|
397
|
+
|
|
398
|
+
The inverted vector is obtained by negating each component of the current vector.
|
|
399
|
+
|
|
400
|
+
The resulting inverted vector is returned.
|
|
401
|
+
"""
|
|
304
402
|
...
|
|
305
403
|
|
|
306
404
|
def floor(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
|
|
405
|
+
"""
|
|
406
|
+
# Round the Vector2D components down to the nearest integer or specified decimal place.
|
|
407
|
+
|
|
408
|
+
## Parameters:
|
|
409
|
+
n (int|float|Vector2D, optional): The decimal place to round down to. Default is 1.
|
|
410
|
+
|
|
411
|
+
## Returns:
|
|
412
|
+
Vector2D: A new vector with rounded-down components.
|
|
413
|
+
|
|
414
|
+
## Example:
|
|
415
|
+
v = Vector2D(3.14159, 2.71828)
|
|
416
|
+
rounded_v = v.floor(2)
|
|
417
|
+
print(rounded_v) # Output: (3.14, 2.71)
|
|
418
|
+
|
|
419
|
+
## Explanation:
|
|
420
|
+
This method rounds each component of the vector down to the nearest integer or specified decimal place.
|
|
421
|
+
"""
|
|
307
422
|
...
|
|
308
423
|
|
|
309
424
|
def ceil(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
|
|
425
|
+
"""
|
|
426
|
+
# Round the Vector2D components up to the nearest integer or specified decimal place.
|
|
427
|
+
|
|
428
|
+
## Parameters:
|
|
429
|
+
n (int|float|Vector2D, optional): The decimal place to round up to. Default is 1.
|
|
430
|
+
|
|
431
|
+
## Returns:
|
|
432
|
+
Vector2D: A new vector with rounded-up components.
|
|
433
|
+
|
|
434
|
+
## Example:
|
|
435
|
+
v = Vector2D(3.14159, 2.71828)
|
|
436
|
+
rounded_v = v.ceil(2)
|
|
437
|
+
print(rounded_v) # Output: (3.15, 2.72)
|
|
438
|
+
|
|
439
|
+
## Explanation:
|
|
440
|
+
This method rounds each component of the vector up to the nearest integer or specified decimal place.
|
|
441
|
+
"""
|
|
310
442
|
...
|
|
311
443
|
|
|
312
444
|
def round(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
|
|
445
|
+
"""
|
|
446
|
+
# Round the Vector2D components to the nearest integer or specified decimal place.
|
|
447
|
+
|
|
448
|
+
## Parameters:
|
|
449
|
+
n (int|float|Vector2D, optional): The decimal place to round to. Default is 1.
|
|
450
|
+
|
|
451
|
+
## Returns:
|
|
452
|
+
Vector2D: A new vector with rounded components.
|
|
453
|
+
|
|
454
|
+
## Example:
|
|
455
|
+
v = Vector2D(3.14159, 2.71828)
|
|
456
|
+
rounded_v = v.round(2)
|
|
457
|
+
print(rounded_v) # Output: (3.14, 2.72)
|
|
458
|
+
|
|
459
|
+
## Explanation:
|
|
460
|
+
This method rounds each component of the vector to the nearest integer or specified decimal place.
|
|
461
|
+
"""
|
|
313
462
|
...
|
|
314
463
|
|
|
315
464
|
@classmethod
|
|
@@ -500,7 +649,65 @@ class Vector2D:
|
|
|
500
649
|
def cartesian_to_complex(self:"Vector2D") -> complex: ...
|
|
501
650
|
|
|
502
651
|
@classmethod
|
|
503
|
-
def complex_to_cartesian(cls, complex_n: complex) -> "Vector2D":
|
|
652
|
+
def complex_to_cartesian(cls, complex_n: complex) -> "Vector2D":
|
|
653
|
+
"""
|
|
654
|
+
# Convert a Complex Number to Cartesian Coordinates
|
|
655
|
+
|
|
656
|
+
## Parameters:
|
|
657
|
+
complex_n (complex): The complex number to convert.
|
|
658
|
+
|
|
659
|
+
## Returns:
|
|
660
|
+
Vector2D: The corresponding (x, y) coordinates as a Vector2D.
|
|
661
|
+
|
|
662
|
+
## Example:
|
|
663
|
+
v = Vector2D.complex_to_cartesian(3 + 4j) # v = Vector2D(3, 4)
|
|
664
|
+
|
|
665
|
+
## Explanation:
|
|
666
|
+
This class method converts a complex number (a + bi) to Cartesian coordinates (x, y).
|
|
667
|
+
The real part 'a' becomes the x-coordinate, and the imaginary part 'b' becomes the y-coordinate.
|
|
668
|
+
"""
|
|
669
|
+
...
|
|
670
|
+
|
|
671
|
+
def cartesian_to_linear(self:"Vector2D", size:int|float) -> int:
|
|
672
|
+
"""
|
|
673
|
+
# Convert 2D Cartesian coordinates to a linear index.
|
|
674
|
+
|
|
675
|
+
## Parameters:
|
|
676
|
+
size (int|float): The width of the grid (number of columns).
|
|
677
|
+
|
|
678
|
+
## Returns:
|
|
679
|
+
int: The linear index corresponding to the (x, y) coordinates.
|
|
680
|
+
|
|
681
|
+
## Example:
|
|
682
|
+
v = Vector2D(3, 2)
|
|
683
|
+
idx = v.cartesian_to_linear(5) # idx = 3 + 2*5 = 13
|
|
684
|
+
|
|
685
|
+
## Explanation:
|
|
686
|
+
This method converts the (x, y) coordinates of the vector to a single linear index,
|
|
687
|
+
assuming row-major order in a 2D grid of the given width.
|
|
688
|
+
"""
|
|
689
|
+
...
|
|
690
|
+
|
|
691
|
+
@classmethod
|
|
692
|
+
def linear_to_cartesian(cls, linear:int, size:int|float) -> "Vector2D":
|
|
693
|
+
"""
|
|
694
|
+
# Convert a linear index to 2D Cartesian coordinates.
|
|
695
|
+
|
|
696
|
+
## Parameters:
|
|
697
|
+
linear (int): The linear index.
|
|
698
|
+
size (int|float): The width of the grid (number of columns).
|
|
699
|
+
|
|
700
|
+
## Returns:
|
|
701
|
+
Vector2D: The corresponding (x, y) coordinates as a Vector2D.
|
|
702
|
+
|
|
703
|
+
## Example:
|
|
704
|
+
v = Vector2D.linear_to_cartesian(13, 5) # v = Vector2D(3, 2)
|
|
705
|
+
|
|
706
|
+
## Explanation:
|
|
707
|
+
This class method converts a linear index to (x, y) coordinates,
|
|
708
|
+
assuming row-major order in a 2D grid of the given width.
|
|
709
|
+
"""
|
|
710
|
+
...
|
|
504
711
|
|
|
505
712
|
def lerp(self:"Vector2D", other:"int|float|Vector2D|list|tuple", t:float=.1) -> "Vector2D":
|
|
506
713
|
"""
|
|
@@ -1095,4 +1302,37 @@ def distance_line_point(line_point_a:Vector2D, line_point_b:Vector2D, point_c:Ve
|
|
|
1095
1302
|
...
|
|
1096
1303
|
|
|
1097
1304
|
def optimize_value_string(value: int|float, precision: int) -> str:
|
|
1305
|
+
"""
|
|
1306
|
+
# Optimize the string representation of a numeric value based on its magnitude and the specified precision.
|
|
1307
|
+
|
|
1308
|
+
## Parameters:
|
|
1309
|
+
value (int | float): The numeric value to be formatted.
|
|
1310
|
+
precision (int): The number of decimal places or significant digits to use in the formatted string.
|
|
1311
|
+
|
|
1312
|
+
## Returns:
|
|
1313
|
+
str: The optimized string representation of the value.
|
|
1314
|
+
|
|
1315
|
+
## Example:
|
|
1316
|
+
value = 0.000012345
|
|
1317
|
+
precision = 3
|
|
1318
|
+
result = optimize_value_string(value, precision)
|
|
1319
|
+
print(result)
|
|
1320
|
+
# Output: '1.235e-05'
|
|
1321
|
+
|
|
1322
|
+
value = 123.456789
|
|
1323
|
+
precision = 2
|
|
1324
|
+
result = optimize_value_string(value, precision)
|
|
1325
|
+
print(result)
|
|
1326
|
+
# Output: '123.46'
|
|
1327
|
+
|
|
1328
|
+
## Explanation:
|
|
1329
|
+
The function formats the input value as a string, choosing between fixed-point and scientific notation
|
|
1330
|
+
based on the magnitude of the value relative to the specified precision:
|
|
1331
|
+
- If the absolute value is very small (less than 1 divided by 10 to the power of precision, but not zero),
|
|
1332
|
+
scientific notation is used.
|
|
1333
|
+
- If the absolute value is less than 10 to the power of precision, fixed-point notation is used,
|
|
1334
|
+
with trailing zeros and decimal points removed for brevity.
|
|
1335
|
+
- Otherwise, scientific notation is used.
|
|
1336
|
+
This ensures that the string representation is concise and readable, while maintaining the requested precision.
|
|
1337
|
+
"""
|
|
1098
1338
|
...
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from colorsys import hsv_to_rgb as __hsv_to_rgb_def__, hls_to_rgb as __hls_to_rgb_def__, rgb_to_hls as __rgb_to_hls__, rgb_to_hsv as __rgb_to_hsv__
|
|
2
3
|
from typing import Any, Callable, Generator, Literal
|
|
3
4
|
from pygame.color import Color as __color_pygame__
|
|
4
|
-
from random import
|
|
5
|
+
from random import random as __rand__
|
|
5
6
|
|
|
6
7
|
RGB_COLOR_MODE = "rgb"
|
|
7
8
|
RGBA_COLOR_MODE = "rgba"
|
|
@@ -15,11 +16,11 @@ HLS_COLOR_MODE = "hls"
|
|
|
15
16
|
|
|
16
17
|
__LITERAL_COLOR_MODES__ = Literal["rgb","rgba","bgr","bgra","g","hsv","hls"] #,"cmyk","lab"]
|
|
17
18
|
|
|
18
|
-
def __hsv_to_rgb__(h:int|float, s:int|float, v:int|float) -> tuple[int|float, int|float, int|float]:
|
|
19
|
+
def __hsv_to_rgb__(h:"int|float", s:"int|float", v:"int|float") -> tuple["int|float", "int|float", "int|float"]:
|
|
19
20
|
r,g,b = __hsv_to_rgb_def__(h, s, v)
|
|
20
21
|
return r*255, g*255, b*255
|
|
21
22
|
|
|
22
|
-
def __hls_to_rgb__(h:int|float, s:int|float, v:int|float) -> tuple[int|float, int|float, int|float]:
|
|
23
|
+
def __hls_to_rgb__(h:"int|float", s:"int|float", v:"int|float") -> tuple["int|float", "int|float", "int|float"]:
|
|
23
24
|
r,g,b = __hls_to_rgb_def__(h, s, v)
|
|
24
25
|
return r*255, g*255, b*255
|
|
25
26
|
|
|
@@ -110,35 +111,35 @@ class Color:
|
|
|
110
111
|
return (d ** .5) if rooted else d
|
|
111
112
|
|
|
112
113
|
@classmethod
|
|
113
|
-
def new_rgb(cls, r:int|float, g:int|float, b:int|float) -> "Color":
|
|
114
|
+
def new_rgb(cls, r:"int|float", g:"int|float", b:"int|float") -> "Color":
|
|
114
115
|
return Color(r,g,b, mode=RGB_COLOR_MODE)
|
|
115
116
|
@classmethod
|
|
116
|
-
def new_rgba(cls, r:int|float, g:int|float, b:int|float, a:int|float) -> "Color":
|
|
117
|
+
def new_rgba(cls, r:"int|float", g:"int|float", b:"int|float", a:"int|float") -> "Color":
|
|
117
118
|
return Color(r,g,b,a, mode=RGBA_COLOR_MODE)
|
|
118
119
|
@classmethod
|
|
119
|
-
def new_bgr(cls, b:int|float, g:int|float, r:int|float) -> "Color":
|
|
120
|
+
def new_bgr(cls, b:"int|float", g:"int|float", r:"int|float") -> "Color":
|
|
120
121
|
return Color(b,g,r, mode=BGR_COLOR_MODE)
|
|
121
122
|
@classmethod
|
|
122
|
-
def new_bgra(cls, b:int|float, g:int|float, r:int|float, a:int|float) -> "Color":
|
|
123
|
+
def new_bgra(cls, b:"int|float", g:"int|float", r:"int|float", a:"int|float") -> "Color":
|
|
123
124
|
return Color(b,g,r,a, mode=BGRA_COLOR_MODE)
|
|
124
125
|
@classmethod
|
|
125
126
|
def new_g(cls, g) -> "Color":
|
|
126
127
|
return Color(g, mode=GRAY_COLOR_MODE)
|
|
127
128
|
@classmethod
|
|
128
|
-
def new_hsv(cls, h:int|float, s:int|float, v:int|float) -> "Color":
|
|
129
|
+
def new_hsv(cls, h:"int|float", s:"int|float", v:"int|float") -> "Color":
|
|
129
130
|
return Color(h,s,v, mode=HSV_COLOR_MODE)
|
|
130
131
|
@classmethod
|
|
131
|
-
def new_hls(cls, h:int|float, l:int|float, s:int|float) -> "Color":
|
|
132
|
+
def new_hls(cls, h:"int|float", l:"int|float", s:"int|float") -> "Color":
|
|
132
133
|
return Color(h,l,s, mode=HLS_COLOR_MODE)
|
|
133
134
|
# @classmethod
|
|
134
|
-
# def new_cmyk(cls, c:int|float, m:int|float, y:int|float, k:int|float) -> Color:
|
|
135
|
+
# def new_cmyk(cls, c:"int|float", m:"int|float", y:"int|float", k:"int|float") -> Color:
|
|
135
136
|
# return Color(c,m,y,k, mode=CMYK_COLOR_MODE)
|
|
136
137
|
# @classmethod
|
|
137
|
-
# def new_lab(cls, l:int|float, a:int|float, b:int|float) -> Color:
|
|
138
|
+
# def new_lab(cls, l:"int|float", a:"int|float", b:"int|float") -> Color:
|
|
138
139
|
# return Color(l,a,b, mode=LAB_COLOR_MODE)
|
|
139
140
|
|
|
140
141
|
@property
|
|
141
|
-
def values(self) -> tuple[int|float, ...]:
|
|
142
|
+
def values(self) -> tuple["int|float", ...]:
|
|
142
143
|
return tuple(self.__dict__.values())[:-1]
|
|
143
144
|
|
|
144
145
|
@property
|
|
@@ -146,7 +147,7 @@ class Color:
|
|
|
146
147
|
return tuple(self.__dict__.keys())[:-1]
|
|
147
148
|
|
|
148
149
|
@property
|
|
149
|
-
def items(self) -> tuple[tuple[str, int|float], ...]:
|
|
150
|
+
def items(self) -> tuple[tuple[str, "int|float"], ...]:
|
|
150
151
|
return tuple(self.__dict__.items())[:-1]
|
|
151
152
|
|
|
152
153
|
def copy(self) -> "Color":
|
|
@@ -392,7 +393,7 @@ class Color:
|
|
|
392
393
|
def __float__(self) -> "Color":
|
|
393
394
|
return Color(float(self.r), float(self.g), float(self.b))
|
|
394
395
|
|
|
395
|
-
def __getitem__(self, n) -> int|float:
|
|
396
|
+
def __getitem__(self, n) -> "int|float":
|
|
396
397
|
return self.values[n] if isinstance(n, int) else self.values[self.keys.index(n)]
|
|
397
398
|
|
|
398
399
|
def __iter__(self) -> Generator[float, Any, None]:
|
|
@@ -412,7 +413,7 @@ class Color:
|
|
|
412
413
|
try:
|
|
413
414
|
return cls(*other.values, mode=other.mode)
|
|
414
415
|
except:
|
|
415
|
-
raise TypeError(f"The value {other} of type {type(other)} is not a num type: [{int|float}] nor an array type: [{list|tuple}]")
|
|
416
|
+
raise TypeError(f"The value {other} of type {type(other)} is not a num type: [{"int|float"}] nor an array type: [{list|tuple}]")
|
|
416
417
|
|
|
417
418
|
@classmethod
|
|
418
419
|
def transparent(cls) -> "Color": return Color(0,0,0,0, mode=RGBA_COLOR_MODE)
|
|
@@ -426,13 +427,26 @@ class Color:
|
|
|
426
427
|
def green(cls) -> "Color": return Color(0,255,0)
|
|
427
428
|
@classmethod
|
|
428
429
|
def blue(cls) -> "Color": return Color(0,0,255)
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
430
|
+
@classmethod
|
|
431
|
+
def cyan(cls) -> "Color": return Color(0,255,255)
|
|
432
|
+
@classmethod
|
|
433
|
+
def magenta(cls) -> "Color": return Color(255,0,255)
|
|
434
|
+
@classmethod
|
|
435
|
+
def yellow(cls) -> "Color": return Color(255,255,0)
|
|
432
436
|
|
|
433
437
|
@classmethod
|
|
434
|
-
def randomize(cls) -> "Color":
|
|
435
|
-
|
|
438
|
+
def randomize(cls, start=0, end=255, func=lambda val:val) -> "Color":
|
|
439
|
+
if not isinstance(start, Color):
|
|
440
|
+
if isinstance(start, (int, float)):
|
|
441
|
+
start = Color(start, start, start)
|
|
442
|
+
else:
|
|
443
|
+
raise Exception(f"\nArg start must be in [Color, int, float, tuple, list] not a [{type(start)}]\n")
|
|
444
|
+
if not isinstance(end, Color):
|
|
445
|
+
if isinstance(end, (int, float)):
|
|
446
|
+
end = Color(end, end, end)
|
|
447
|
+
else:
|
|
448
|
+
raise Exception(f"\nArg end must be in [Color, int, float, tuple, list] not a [{type(end)}]\n")
|
|
449
|
+
return start + Color(func(__rand__()), func(__rand__()), func(__rand__())) * (end - start)
|
|
436
450
|
|
|
437
451
|
|
|
438
452
|
TRANSPARENT_COLOR = Color.transparent()
|
|
@@ -441,6 +455,9 @@ BLACK_COLOR = Color.black()
|
|
|
441
455
|
RED_COLOR = Color.red()
|
|
442
456
|
GREEN_COLOR = Color.green()
|
|
443
457
|
BLUE_COLOR = Color.blue()
|
|
458
|
+
CYAN_COLOR = Color.cyan()
|
|
459
|
+
MAGENTA_COLOR = Color.magenta()
|
|
460
|
+
YELLOW_COLOR = Color.yellow()
|
|
444
461
|
|
|
445
462
|
TRANSPARENT_COLOR_PYG = TRANSPARENT_COLOR()
|
|
446
463
|
WHITE_COLOR_PYG = WHITE_COLOR()
|
|
@@ -448,3 +465,6 @@ BLACK_COLOR_PYG = BLACK_COLOR()
|
|
|
448
465
|
RED_COLOR_PYG = RED_COLOR()
|
|
449
466
|
GREEN_COLOR_PYG = GREEN_COLOR()
|
|
450
467
|
BLUE_COLOR_PYG = BLUE_COLOR()
|
|
468
|
+
CYAN_COLOR_PYG = CYAN_COLOR()
|
|
469
|
+
MAGENTA_COLOR_PYG = MAGENTA_COLOR()
|
|
470
|
+
YELLOW_COLOR_PYG = YELLOW_COLOR()
|
|
@@ -42,13 +42,15 @@ class RootEnv:
|
|
|
42
42
|
quit_on_key_pressed : None|int = pg.K_x,
|
|
43
43
|
vsync : bool = True,
|
|
44
44
|
window_flags : int = pg.DOUBLEBUF,
|
|
45
|
+
display_index : int = 0,
|
|
45
46
|
clear_screen_each_frame : bool = True) -> None:
|
|
46
47
|
self.quit = False
|
|
47
48
|
self.__screen_size__ :Vector2D= screen_size
|
|
48
49
|
|
|
49
50
|
self.__vsync__ = vsync
|
|
50
51
|
self.__flags__ = window_flags
|
|
51
|
-
self.
|
|
52
|
+
self.__display_index__ = display_index
|
|
53
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
52
54
|
|
|
53
55
|
self.clock = pg.time.Clock()
|
|
54
56
|
self.keyboard = Keyboard()
|
|
@@ -56,6 +58,7 @@ class RootEnv:
|
|
|
56
58
|
|
|
57
59
|
self.target_fps = target_fps
|
|
58
60
|
self.current_fps = self.target_fps if self.target_fps != 0 else 1
|
|
61
|
+
self.__dt__ = 1 / self.current_fps
|
|
59
62
|
self.current_frame = 0
|
|
60
63
|
self.show_fps = show_fps
|
|
61
64
|
self.events :list[pg.event.Event]= []
|
|
@@ -67,6 +70,13 @@ class RootEnv:
|
|
|
67
70
|
self.selected_util :Util|None = None
|
|
68
71
|
self.__quit_on_key_pressed__ = quit_on_key_pressed
|
|
69
72
|
|
|
73
|
+
self.fps_label = Label(str(round(self.current_fps,2)), self.screen_size * .01, V2(250, 50), BLACK_COLOR_PYG, TRANSPARENT_COLOR_PYG, WHITE_COLOR_PYG, border_width=0, starting_hidden=(not self.show_fps), pivot_position="top_left", font=FONT_ARIAL_32)
|
|
74
|
+
self.add_utils(self.fps_label)
|
|
75
|
+
|
|
76
|
+
def init_rec(self, fps:int=30, path:str='output.mp4') -> None:
|
|
77
|
+
from .winrec import WinRec
|
|
78
|
+
self.__winrecorder__ = WinRec(self, fps=fps, path=path)
|
|
79
|
+
|
|
70
80
|
@property
|
|
71
81
|
def background_color(self) -> Color:
|
|
72
82
|
return unpygamize_color(self.__background_color__)
|
|
@@ -81,19 +91,24 @@ class RootEnv:
|
|
|
81
91
|
@screen_size.setter
|
|
82
92
|
def screen_size(self, new_size:Vector2D) -> None:
|
|
83
93
|
self.__screen_size__ = new_size
|
|
84
|
-
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__)
|
|
94
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
95
|
+
|
|
96
|
+
def update_screen_to_new_size(self) -> None:
|
|
97
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
85
98
|
|
|
86
99
|
@property
|
|
87
100
|
def delta(self) -> int:
|
|
88
|
-
return self.
|
|
101
|
+
return self.__dt__
|
|
89
102
|
|
|
90
103
|
def get_teoric_max_fps(self) -> float:
|
|
91
104
|
rawdelta = self.clock.get_rawtime()
|
|
92
105
|
return (1000 / rawdelta) if rawdelta != 0 else 1
|
|
93
106
|
|
|
94
|
-
def update_screen_mode(self, vsync:None|bool=None, flags=None) -> None:
|
|
107
|
+
def update_screen_mode(self, vsync:None|bool=None, flags=None, display_index=None) -> None:
|
|
95
108
|
self.__vsync__ = vsync
|
|
96
109
|
self.__flags__ = flags
|
|
110
|
+
self.__display_index__ = display_index
|
|
111
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
97
112
|
|
|
98
113
|
def sleep(self, seconds:int|float, precise_delay=False) -> None:
|
|
99
114
|
if precise_delay:
|
|
@@ -106,7 +121,7 @@ class RootEnv:
|
|
|
106
121
|
if util.surface == None: util.surface = self.screen
|
|
107
122
|
util.rootEnv = self
|
|
108
123
|
util.id = self.__new_util_id__()
|
|
109
|
-
util.
|
|
124
|
+
util.__render__()
|
|
110
125
|
self.utils[util.id] = util
|
|
111
126
|
|
|
112
127
|
def remove_utils(self, *utils:int|str|Util) -> None:
|
|
@@ -169,24 +184,32 @@ class RootEnv:
|
|
|
169
184
|
surface.blit(text_box, pivotted_position())
|
|
170
185
|
|
|
171
186
|
def __draw__(self) -> None:
|
|
172
|
-
self.clock.tick(self.target_fps)
|
|
187
|
+
self.__dt__ = self.clock.tick(self.target_fps) / 1000.0
|
|
173
188
|
self.current_fps = self.clock.get_fps()
|
|
189
|
+
self.fps_label.text = str(round(self.current_fps, 2))
|
|
190
|
+
|
|
174
191
|
if self.clear_screen_each_frame: self.clear()
|
|
175
192
|
|
|
176
193
|
self.env.draw()
|
|
177
|
-
for util in self.utils.values(): util.
|
|
194
|
+
for util in self.utils.values(): util.__draw__()
|
|
178
195
|
|
|
179
|
-
if self.show_fps: self.print(str(round(self.current_fps,2)), self.screen_size * .01, bg_color=BLACK_COLOR_PYG)
|
|
180
196
|
pg.display.flip()
|
|
181
197
|
|
|
182
198
|
def __update__(self) -> None:
|
|
183
199
|
self.mouse.update()
|
|
184
200
|
self.keyboard.update()
|
|
185
201
|
self.env.update()
|
|
186
|
-
for util in self.utils.values(): util.
|
|
202
|
+
for util in self.utils.values(): util.__update__()
|
|
203
|
+
|
|
204
|
+
if hasattr(self, "__winrecorder__"):
|
|
205
|
+
self.__winrecorder__.update()
|
|
206
|
+
self.__winrecorder__.draw()
|
|
187
207
|
|
|
188
208
|
def frame(self) -> None:
|
|
189
|
-
|
|
209
|
+
try:
|
|
210
|
+
self.events = pg.event.get()
|
|
211
|
+
except SystemError:
|
|
212
|
+
raise Warning(f"Pygame error with event drivers. Try restarting the program. If the error persists, try restarting your computer.")
|
|
190
213
|
self.current_frame += 1
|
|
191
214
|
self.__update__()
|
|
192
215
|
self.__draw__()
|
|
@@ -194,4 +217,5 @@ class RootEnv:
|
|
|
194
217
|
for event in self.events:
|
|
195
218
|
if event.type == pg.QUIT or ((event.type == pg.KEYDOWN and event.key == self.__quit_on_key_pressed__ and self.selected_util == None) if self.__quit_on_key_pressed__ != None else False):
|
|
196
219
|
pg.quit()
|
|
220
|
+
if hasattr(self, "__winrecorder__"): self.__winrecorder__.quit()
|
|
197
221
|
self.quit = True
|
|
@@ -33,32 +33,51 @@ __PIVOT_POSITIONS_MULTIPLIER__ = dict(zip(("top_left", "top_center", "top_right"
|
|
|
33
33
|
class Mouse:
|
|
34
34
|
def __init__(self, parent) -> None:
|
|
35
35
|
self.parent = parent
|
|
36
|
-
self.
|
|
37
|
-
self.__last_frame_position__ = Vector2D.new_zero()
|
|
38
|
-
self.
|
|
39
|
-
self.__last_frame_movement__ = Vector2D.new_zero()
|
|
40
|
-
|
|
36
|
+
self.__last_frame_position_number__ :int= 0
|
|
37
|
+
self.__last_frame_position__ :Vector2D= Vector2D.new_zero()
|
|
38
|
+
self.__last_frame_movement_number__ :int= 0
|
|
39
|
+
self.__last_frame_movement__ :Vector2D= Vector2D.new_zero()
|
|
40
|
+
self.__last_frame_wheel_number__ :int= 0
|
|
41
|
+
self.__last_frame_wheel_delta__ :int= 0
|
|
42
|
+
|
|
41
43
|
self.__pressed__ : tuple[bool, bool, bool] = (False, False, False)
|
|
42
|
-
self.update()
|
|
44
|
+
self.update()
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def wheel_delta(self) -> int:
|
|
48
|
+
for event in self.parent.events:
|
|
49
|
+
if event.type == pg.MOUSEWHEEL:
|
|
50
|
+
if self.__last_frame_wheel_number__ != self.parent.current_frame:
|
|
51
|
+
self.__last_frame_wheel_delta__ = event.y
|
|
52
|
+
self.__last_frame_wheel_number__ = self.parent.current_frame
|
|
53
|
+
return self.__last_frame_wheel_delta__
|
|
54
|
+
|
|
55
|
+
self.__last_frame_wheel_delta__ = 0
|
|
56
|
+
self.__last_frame_wheel_number__ = self.parent.current_frame
|
|
57
|
+
return self.__last_frame_wheel_delta__
|
|
43
58
|
|
|
44
59
|
@property
|
|
45
60
|
def position(self) -> Vector2D:
|
|
46
|
-
if self.
|
|
61
|
+
if self.__last_frame_position_number__ != self.parent.current_frame:
|
|
47
62
|
self.__last_frame_position__ = Vector2D(*pg.mouse.get_pos())
|
|
48
|
-
self.
|
|
63
|
+
self.__last_frame_position_number__ = self.parent.current_frame
|
|
49
64
|
return self.__last_frame_position__
|
|
50
65
|
@position.setter
|
|
51
66
|
def position(self, new_position:Vector2D) -> None:
|
|
52
|
-
self.
|
|
67
|
+
self.__last_frame_position_number__ = self.parent.current_frame
|
|
53
68
|
self.__last_frame_position__ = new_position
|
|
54
69
|
pg.mouse.set_pos(self.__last_frame_position__())
|
|
55
70
|
|
|
56
71
|
@property
|
|
57
72
|
def last_frame_movement(self) -> Vector2D:
|
|
58
|
-
if self.
|
|
73
|
+
if self.__last_frame_movement_number__ != self.parent.current_frame:
|
|
59
74
|
self.__last_frame_movement__ = Vector2D(*pg.mouse.get_rel())
|
|
60
|
-
self.
|
|
75
|
+
self.__last_frame_movement_number__ = self.parent.current_frame
|
|
61
76
|
return self.__last_frame_movement__
|
|
77
|
+
@last_frame_movement.setter
|
|
78
|
+
def last_frame_movement(self, new_movement:Vector2D) -> None:
|
|
79
|
+
self.__last_frame_movement_number__ = self.parent.current_frame
|
|
80
|
+
self.__last_frame_movement__ = new_movement
|
|
62
81
|
|
|
63
82
|
def update(self) -> None:
|
|
64
83
|
self.__last_pressed__ = self.__pressed__
|
|
@@ -95,8 +114,8 @@ class Keyboard:
|
|
|
95
114
|
|
|
96
115
|
class Util:
|
|
97
116
|
def __init__(self) -> None:
|
|
98
|
-
self.rootEnv
|
|
99
|
-
self.surface : pg.Surface
|
|
117
|
+
self.rootEnv : Any
|
|
118
|
+
self.surface : pg.Surface= None # type: ignore
|
|
100
119
|
self.id : int|str
|
|
101
120
|
self.is_hovered :bool= False
|
|
102
121
|
self.hidden :bool= False
|
|
@@ -104,9 +123,9 @@ class Util:
|
|
|
104
123
|
self.hidden = True
|
|
105
124
|
def show(self) -> None:
|
|
106
125
|
self.hidden = False
|
|
107
|
-
def
|
|
108
|
-
def
|
|
109
|
-
def
|
|
126
|
+
def __render__(self) -> None: pass
|
|
127
|
+
def __draw__(self) -> None: pass
|
|
128
|
+
def __update__(self) -> None: pass
|
|
110
129
|
|
|
111
130
|
class InputCell(Util):
|
|
112
131
|
def __init__(self,
|
|
@@ -176,7 +195,7 @@ class InputCell(Util):
|
|
|
176
195
|
def border_color(self, new_color:Color|pg.Color) -> None:
|
|
177
196
|
self.__border_color__ = pygamize_color(new_color)
|
|
178
197
|
|
|
179
|
-
def
|
|
198
|
+
def __draw__(self) -> None:
|
|
180
199
|
if self.hidden: return
|
|
181
200
|
self.text_surface.fill(TRANSPARENT_COLOR_PYG)
|
|
182
201
|
|
|
@@ -194,7 +213,7 @@ class InputCell(Util):
|
|
|
194
213
|
|
|
195
214
|
self.surface.blit(self.text_surface, self.position())
|
|
196
215
|
|
|
197
|
-
def
|
|
216
|
+
def __update__(self) -> None:
|
|
198
217
|
if self.hidden: return
|
|
199
218
|
self.is_hovered = self.position.x < self.rootEnv.mouse.position.x < self.position.x + self.size.x and\
|
|
200
219
|
self.position.y < self.rootEnv.mouse.position.y < self.position.y + self.size.y
|
|
@@ -261,7 +280,7 @@ class Slider(Util):
|
|
|
261
280
|
self.text_pivot = text_pivot
|
|
262
281
|
|
|
263
282
|
self.handleRadius = handleRadius
|
|
264
|
-
self.surface = personalized_surface
|
|
283
|
+
self.surface = personalized_surface # type: ignore
|
|
265
284
|
|
|
266
285
|
self.hidden = False
|
|
267
286
|
|
|
@@ -281,21 +300,21 @@ class Slider(Util):
|
|
|
281
300
|
def handleColour(self, new_color:Color|pg.Color) -> None:
|
|
282
301
|
self.__handleColour__ = pygamize_color(new_color)
|
|
283
302
|
|
|
284
|
-
def
|
|
303
|
+
def __draw__(self) -> None:
|
|
285
304
|
if self.hidden: return
|
|
286
|
-
pg.draw.rect(self.
|
|
305
|
+
pg.draw.rect(self.surface, self.__color__, self.position() + self.size())
|
|
287
306
|
|
|
288
307
|
if self.radius:
|
|
289
|
-
pg.draw.circle(self.
|
|
290
|
-
pg.draw.circle(self.
|
|
308
|
+
pg.draw.circle(self.surface, self.__color__, (self.position.x, self.position.y + self.size.y // 2), self.radius)
|
|
309
|
+
pg.draw.circle(self.surface, self.__color__, (self.position.x + self.size.x, self.position.y + self.size.y // 2), self.radius)
|
|
291
310
|
|
|
292
311
|
circle = V2(int(self.position.x + (self.value - self.min) / (self.max - self.min) * self.size.x), self.position.y + self.size.y // 2)
|
|
293
312
|
|
|
294
|
-
pg.draw.circle(self.
|
|
295
|
-
pg.draw.circle(self.
|
|
313
|
+
pg.draw.circle(self.surface, self.__color__, circle(), self.handleRadius * 1.25)
|
|
314
|
+
pg.draw.circle(self.surface, self.__handleColour__, circle(), self.handleRadius)
|
|
296
315
|
self.rootEnv.print(self.text.format(round(self.value, 2)), self.position + self.size * self.text_offset, pivot_position=self.text_pivot)
|
|
297
316
|
|
|
298
|
-
def
|
|
317
|
+
def __update__(self) -> None:
|
|
299
318
|
if self.hidden: return
|
|
300
319
|
x,y = self.rootEnv.mouse.position
|
|
301
320
|
|
|
@@ -324,22 +343,22 @@ class Button(Util):
|
|
|
324
343
|
text : str,
|
|
325
344
|
position : V2|Vector2D,
|
|
326
345
|
size : V2|Vector2D,
|
|
327
|
-
callback : Callable[[
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
border_color : Color|pg.Color,
|
|
346
|
+
callback : Callable[[], None]|Callable[[], None] = lambda: None,
|
|
347
|
+
default_bg_color : Color|pg.Color = BLUE_COLOR_PYG,
|
|
348
|
+
hovered_bg_color : Color|pg.Color = CYAN_COLOR_PYG,
|
|
349
|
+
border_color : Color|pg.Color = WHITE_COLOR_PYG,
|
|
331
350
|
text_color : Color|pg.Color = WHITE_COLOR_PYG,
|
|
332
351
|
font : pg.font.Font = FONT_ARIAL_32,
|
|
333
352
|
border_radius : float = 10,
|
|
334
353
|
border_width : float = 10,
|
|
335
|
-
|
|
354
|
+
starting_hidden : bool = False,
|
|
336
355
|
args : list = [],
|
|
337
356
|
activation_mode : __LITERAL_KEY_MODE_TYPES__ = "just_pressed",
|
|
338
357
|
pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
|
|
339
358
|
personalized_surface : pg.Surface|None = None,
|
|
340
359
|
) -> None:
|
|
341
360
|
super().__init__()
|
|
342
|
-
|
|
361
|
+
|
|
343
362
|
self.text = text
|
|
344
363
|
self.font = font
|
|
345
364
|
|
|
@@ -348,10 +367,11 @@ class Button(Util):
|
|
|
348
367
|
self.border_radius = border_radius
|
|
349
368
|
self.__size__ = size
|
|
350
369
|
self.__border_width__ = border_width
|
|
351
|
-
|
|
352
|
-
self.update_position(position, pivot_position)
|
|
353
370
|
|
|
354
|
-
self.
|
|
371
|
+
self.pivot_position :__LITERAL_PIVOT_POSITIONS__= pivot_position
|
|
372
|
+
self.update_position(position)
|
|
373
|
+
|
|
374
|
+
self.hidden = starting_hidden
|
|
355
375
|
self.args = args
|
|
356
376
|
|
|
357
377
|
self.activation_mode = activation_mode
|
|
@@ -359,19 +379,23 @@ class Button(Util):
|
|
|
359
379
|
self.hovered = False
|
|
360
380
|
|
|
361
381
|
self.text_color = text_color
|
|
362
|
-
self.
|
|
382
|
+
self.default_bg_color = default_bg_color
|
|
363
383
|
self.border_color = border_color
|
|
364
|
-
self.
|
|
384
|
+
self.hovered_bg_color = hovered_bg_color
|
|
365
385
|
|
|
366
|
-
self.surface = personalized_surface
|
|
386
|
+
self.surface = personalized_surface #type: ignore
|
|
367
387
|
self.update_surface()
|
|
368
388
|
|
|
369
|
-
def update_position(self, new_position:V2
|
|
370
|
-
self.position = new_position -
|
|
389
|
+
def update_position(self, new_position:V2) -> None:
|
|
390
|
+
self.position = new_position - self.__size__ * __PIVOT_POSITIONS_MULTIPLIER__[self.pivot_position]
|
|
391
|
+
|
|
392
|
+
def update_pivoting(self, new_pivot_position:__LITERAL_PIVOT_POSITIONS__) -> None:
|
|
393
|
+
self.pivot_position = new_pivot_position
|
|
394
|
+
self.update_position(self.position)
|
|
371
395
|
|
|
372
396
|
def update_surface(self, render=False) -> None:
|
|
373
397
|
self.buffer_surface = pg.Surface((self.__size__ + self.__border_width__ * 2)(), pg.SRCALPHA, 32).convert_alpha()
|
|
374
|
-
if render: self.
|
|
398
|
+
if render: self.__render__()
|
|
375
399
|
|
|
376
400
|
@property
|
|
377
401
|
def size(self) -> V2:
|
|
@@ -386,6 +410,7 @@ class Button(Util):
|
|
|
386
410
|
return self.__border_width__
|
|
387
411
|
@border_width.setter
|
|
388
412
|
def border_width(self, new_width:float) -> None:
|
|
413
|
+
# self.position -= (self.__border_width__ - new_width) * .5
|
|
389
414
|
self.__border_width__ = new_width
|
|
390
415
|
self.update_surface(render=True)
|
|
391
416
|
|
|
@@ -396,11 +421,11 @@ class Button(Util):
|
|
|
396
421
|
def text_color(self, new_color:Color|pg.Color) -> None:
|
|
397
422
|
self.__text_color__ = pygamize_color(new_color)
|
|
398
423
|
@property
|
|
399
|
-
def
|
|
400
|
-
return unpygamize_color(self.
|
|
401
|
-
@
|
|
402
|
-
def
|
|
403
|
-
self.
|
|
424
|
+
def default_bg_color(self) -> Color:
|
|
425
|
+
return unpygamize_color(self.__default_bg_color__)
|
|
426
|
+
@default_bg_color.setter
|
|
427
|
+
def default_bg_color(self, new_color:Color|pg.Color) -> None:
|
|
428
|
+
self.__default_bg_color__ = pygamize_color(new_color)
|
|
404
429
|
@property
|
|
405
430
|
def border_color(self) -> Color:
|
|
406
431
|
return unpygamize_color(self.__border_color__)
|
|
@@ -408,27 +433,28 @@ class Button(Util):
|
|
|
408
433
|
def border_color(self, new_color:Color|pg.Color) -> None:
|
|
409
434
|
self.__border_color__ = pygamize_color(new_color)
|
|
410
435
|
@property
|
|
411
|
-
def
|
|
412
|
-
return unpygamize_color(self.
|
|
413
|
-
@
|
|
414
|
-
def
|
|
415
|
-
self.
|
|
416
|
-
|
|
417
|
-
def
|
|
418
|
-
print("rendering button")
|
|
436
|
+
def hovered_bg_color(self) -> Color:
|
|
437
|
+
return unpygamize_color(self.__hovered_bg_color__)
|
|
438
|
+
@hovered_bg_color.setter
|
|
439
|
+
def hovered_bg_color(self, new_color:Color|pg.Color) -> None:
|
|
440
|
+
self.__hovered_bg_color__ = pygamize_color(new_color)
|
|
441
|
+
|
|
442
|
+
def __render__(self) -> None:
|
|
419
443
|
self.buffer_surface.fill(TRANSPARENT_COLOR_PYG)
|
|
420
444
|
|
|
421
|
-
color = self.
|
|
445
|
+
color = self.__hovered_bg_color__ if self.hovered else self.__default_bg_color__
|
|
422
446
|
pg.draw.rect(self.buffer_surface, self.__border_color__, V2.zero()() + (self.size + self.border_width * 2)(), border_radius=self.border_radius)
|
|
423
447
|
pg.draw.rect(self.buffer_surface, color, (V2.zero() + self.border_width)() + self.size(), border_radius=self.border_radius)
|
|
424
448
|
|
|
449
|
+
# TODO:
|
|
450
|
+
# not only size * .5 but also internal pivoting on the corners and sides
|
|
425
451
|
self.rootEnv.print(self.text, self.border_width + self.size * .5, color=self.__text_color__, font=self.font, pivot_position="center_center", personalized_surface=self.buffer_surface)
|
|
426
452
|
|
|
427
|
-
def
|
|
453
|
+
def __draw__(self) -> None:
|
|
428
454
|
if self.hidden: return
|
|
429
455
|
self.surface.blit(self.buffer_surface, (self.position)())
|
|
430
456
|
|
|
431
|
-
def
|
|
457
|
+
def __update__(self) -> None:
|
|
432
458
|
if self.hidden: return
|
|
433
459
|
|
|
434
460
|
old_overed = self.hovered
|
|
@@ -436,15 +462,15 @@ class Button(Util):
|
|
|
436
462
|
self.position.x < self.rootEnv.mouse.position.x < self.position.x + self.size.x and \
|
|
437
463
|
self.position.y < self.rootEnv.mouse.position.y < self.position.y + self.size.y
|
|
438
464
|
if self.hovered != old_overed:
|
|
439
|
-
self.
|
|
465
|
+
self.__render__()
|
|
440
466
|
|
|
441
467
|
if self.hovered and self.rootEnv.mouse.get_key(0, self.activation_mode):
|
|
442
468
|
self.callback(*self.args)
|
|
443
469
|
self.rootEnv.selected_util = self
|
|
444
|
-
self.
|
|
470
|
+
self.__render__()
|
|
445
471
|
elif self.rootEnv.selected_util == self:
|
|
446
472
|
self.rootEnv.selected_util = None
|
|
447
|
-
self.
|
|
473
|
+
self.__render__()
|
|
448
474
|
|
|
449
475
|
class Label(Util):
|
|
450
476
|
def __init__(self,
|
|
@@ -457,7 +483,7 @@ class Label(Util):
|
|
|
457
483
|
font : pg.font.Font = FONT_ARIAL_32,
|
|
458
484
|
border_radius : float = 10,
|
|
459
485
|
border_width : float = 10,
|
|
460
|
-
|
|
486
|
+
starting_hidden : bool = False,
|
|
461
487
|
personalized_surface : pg.Surface|None = None,
|
|
462
488
|
pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
|
|
463
489
|
) -> None:
|
|
@@ -470,23 +496,28 @@ class Label(Util):
|
|
|
470
496
|
self.__size__ = size
|
|
471
497
|
self.__border_width__ = border_width
|
|
472
498
|
|
|
473
|
-
self.
|
|
499
|
+
self.pivot_position :__LITERAL_PIVOT_POSITIONS__= pivot_position
|
|
500
|
+
self.update_position(position)
|
|
474
501
|
|
|
475
|
-
self.hidden =
|
|
502
|
+
self.hidden = starting_hidden
|
|
476
503
|
|
|
477
504
|
self.text_color = text_color
|
|
478
505
|
self.default_color = default_color
|
|
479
506
|
self.border_color = border_color
|
|
480
507
|
|
|
481
|
-
self.surface = personalized_surface
|
|
508
|
+
self.surface = personalized_surface # type: ignore
|
|
482
509
|
self.update_surface()
|
|
483
510
|
|
|
484
|
-
def update_position(self, new_position:V2
|
|
485
|
-
self.position = new_position - (self.__size__ + self.border_width * 2) * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position]
|
|
486
|
-
|
|
511
|
+
def update_position(self, new_position:V2) -> None:
|
|
512
|
+
self.position = new_position - (self.__size__ + self.border_width * 2) * __PIVOT_POSITIONS_MULTIPLIER__[self.pivot_position]
|
|
513
|
+
|
|
514
|
+
def update_pivoting(self, new_pivot_position:__LITERAL_PIVOT_POSITIONS__="top_left") -> None:
|
|
515
|
+
self.pivot_position = new_pivot_position
|
|
516
|
+
self.update_position(self.position)
|
|
517
|
+
|
|
487
518
|
def update_surface(self, render=False) -> None:
|
|
488
519
|
self.buffer_surface = pg.Surface((self.__size__ + self.__border_width__ * 2)(), pg.SRCALPHA, 32).convert_alpha()
|
|
489
|
-
if render: self.
|
|
520
|
+
if render: self.__render__()
|
|
490
521
|
|
|
491
522
|
@property
|
|
492
523
|
def text(self) -> str:
|
|
@@ -494,7 +525,7 @@ class Label(Util):
|
|
|
494
525
|
@text.setter
|
|
495
526
|
def text(self, new_text:str) -> None:
|
|
496
527
|
self.__text__ = new_text
|
|
497
|
-
self.
|
|
528
|
+
self.__render__()
|
|
498
529
|
|
|
499
530
|
@property
|
|
500
531
|
def size(self) -> V2:
|
|
@@ -531,15 +562,16 @@ class Label(Util):
|
|
|
531
562
|
def border_color(self, new_color:Color|pg.Color) -> None:
|
|
532
563
|
self.__border_color__ = pygamize_color(new_color)
|
|
533
564
|
|
|
534
|
-
def
|
|
535
|
-
print("rendering label")
|
|
565
|
+
def __render__(self) -> None:
|
|
536
566
|
self.buffer_surface.fill(TRANSPARENT_COLOR_PYG)
|
|
537
567
|
|
|
538
568
|
pg.draw.rect(self.buffer_surface, self.__border_color__, V2.zero()() + (self.size + self.border_width * 2)(), border_radius=self.border_radius)
|
|
539
569
|
pg.draw.rect(self.buffer_surface, self.__default_color__, (V2.zero() + self.border_width)() + self.size(), border_radius=self.border_radius)
|
|
540
570
|
|
|
571
|
+
# TODO:
|
|
572
|
+
# not only size * .5 but also internal pivoting on the corners and sides
|
|
541
573
|
self.rootEnv.print(self.text, self.border_width + self.size * .5, color=self.__text_color__, font=self.font, pivot_position="center_center", personalized_surface=self.buffer_surface)
|
|
542
574
|
|
|
543
|
-
def
|
|
575
|
+
def __draw__(self) -> None:
|
|
544
576
|
if self.hidden: return
|
|
545
577
|
self.surface.blit(self.buffer_surface, (self.position)())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: e2D
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.21
|
|
4
4
|
Summary: Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
|
|
5
5
|
Home-page: https://github.com/marick-py/e2D
|
|
6
6
|
Author: Riccardo Mariani
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = e2D
|
|
3
|
-
version = 1.4.
|
|
3
|
+
version = 1.4.21
|
|
4
4
|
author = Riccardo Mariani
|
|
5
5
|
author_email = ricomari2006@gmail.com
|
|
6
6
|
description = Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|