ConsoleLib 1.3.0__tar.gz → 1.3.2__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.
@@ -0,0 +1,676 @@
1
+ """
2
+ ConsoleLib - The best Console Renderer of the Python.
3
+ By: Suleiman
4
+ Copyright © Suleiman 2026
5
+ All rights are reserved.
6
+ """
7
+ import os
8
+ import sys
9
+ import time
10
+ import subprocess as CMD
11
+ import math
12
+ import random
13
+ from typing import Optional, Iterator, List
14
+ class Animate:
15
+ def clear_screen():
16
+ os.system('cls' if os.name == 'nt' else 'clear')
17
+ class ProgressBar:
18
+ def __init__(
19
+ self,
20
+ total: int,
21
+ prefix: str = "Progress:",
22
+ suffix: str = "Complete",
23
+ length: int = 40,
24
+ fill: str = "█",
25
+ empty: str = "░",
26
+ show_percent: bool = True,
27
+ show_counter: bool = True,
28
+ auto_clear: bool = False,
29
+ clear_delay: float = 0.5,
30
+ ):
31
+ self.total = total
32
+ self.prefix = prefix
33
+ self.suffix = suffix
34
+ self.length = length
35
+ self.fill = fill
36
+ self.empty = empty
37
+ self.show_percent = show_percent
38
+ self.show_counter = show_counter
39
+ self.auto_clear = auto_clear
40
+ self.clear_delay = clear_delay
41
+ self.current = 0
42
+ self._lock = threading.Lock()
43
+ self._finished = False
44
+ self._cleared = False
45
+
46
+ def update(self, increment: int = 1) -> None:
47
+ with self._lock:
48
+ if self._finished:
49
+ return
50
+ self.current = min(self.current + increment, self.total)
51
+ self._print_bar()
52
+
53
+ if self.current >= self.total:
54
+ self._finished = True
55
+ print()
56
+
57
+ def set(self, value: int) -> None:
58
+ with self._lock:
59
+ if self._finished:
60
+ return
61
+ self.current = max(0, min(value, self.total))
62
+ self._print_bar()
63
+ if self.current >= self.total:
64
+ self._finished = True
65
+ print()
66
+ def _print_bar(self) -> None:
67
+ percent = self.current / self.total
68
+ filled_len = int(self.length * percent)
69
+ bar = self.fill * filled_len + self.empty * (self.length - filled_len)
70
+ parts = [self.prefix, f"[{bar}]"]
71
+ if self.show_percent:
72
+ parts.append(f"{percent:.1%}")
73
+ if self.show_counter:
74
+ parts.append(f"({self.current}/{self.total})")
75
+ if self.suffix:
76
+ parts.append(self.suffix)
77
+ line = " ".join(parts)
78
+ sys.stdout.write("\r" + line)
79
+ sys.stdout.flush()
80
+
81
+ def __enter__(self):
82
+ if self.auto_clear and not self._cleared:
83
+ clear_screen()
84
+ self._cleared = True
85
+ if self.clear_delay > 0:
86
+ time.sleep(self.clear_delay)
87
+ return self
88
+ def __exit__(self, exc_type, exc_val, exc_tb):
89
+ if not self._finished:
90
+ self._print_bar()
91
+ print()
92
+ def iterate(self, iterable: Iterator) -> Iterator:
93
+ for i, item in enumerate(iterable):
94
+ yield item
95
+ self.update(1)
96
+ def animate_print(
97
+ text: str,
98
+ delay: float = 0.05,
99
+ end: str = "\n",
100
+ flush: bool = True,
101
+ backspace_effect: bool = False,
102
+ ) -> None:
103
+ if backspace_effect:
104
+ for ch in text:
105
+ sys.stdout.write(ch)
106
+ sys.stdout.flush()
107
+ time.sleep(delay)
108
+ time.sleep(0.2)
109
+ for _ in text:
110
+ sys.stdout.write("\b \b")
111
+ sys.stdout.flush()
112
+ time.sleep(delay / 2)
113
+ for ch in text:
114
+ sys.stdout.write(ch)
115
+ sys.stdout.flush()
116
+ time.sleep(delay)
117
+ sys.stdout.write(end)
118
+ sys.stdout.flush()
119
+ else:
120
+ for ch in text:
121
+ sys.stdout.write(ch)
122
+ if flush:
123
+ sys.stdout.flush()
124
+ time.sleep(delay)
125
+ sys.stdout.write(end)
126
+ if flush:
127
+ sys.stdout.flush()
128
+ def spinning_cursor(
129
+ message: str = "Loading",
130
+ duration: float = 3.0,
131
+ delay: float = 0.1,
132
+ frames: Optional[List[str]] = None,
133
+ clear_before: bool = False,
134
+ ) -> None:
135
+ if clear_before:
136
+ clear_screen()
137
+ if frames is None:
138
+ frames = ["|", "/", "-", r"\\"]
139
+ end_time = time.time() + duration
140
+ idx = 0
141
+ while time.time() < end_time:
142
+ frame = frames[idx % len(frames)]
143
+ sys.stdout.write(f"\r{message} {frame} ")
144
+ sys.stdout.flush()
145
+ time.sleep(delay)
146
+ idx += 1
147
+ sys.stdout.write("\r" + " " * (len(message) + 3) + "\r")
148
+ sys.stdout.flush()
149
+ def countdown(seconds: int, message: str = "Countdown", clear_before: bool = False) -> None:
150
+ if clear_before:
151
+ clear_screen()
152
+ for remaining in range(seconds, 0, -1):
153
+ sys.stdout.write(f"\r{message}: {remaining:2d} seconds remaining ")
154
+ sys.stdout.flush()
155
+ time.sleep(1)
156
+ sys.stdout.write(f"\r{message}: 0 seconds remaining! Done!\n")
157
+ sys.stdout.flush()
158
+ class Render:
159
+ @staticmethod
160
+ def DrawPic(points=None, width=80, height=25, clear_before_draw=False, default_char=' '):
161
+ if clear_before_draw:
162
+ os.system("cls" if os.name == "nt" else "clear")
163
+ field = [[default_char for _ in range(width)] for _ in range(height)]
164
+ if points:
165
+ for item in points:
166
+ if len(item) == 3:
167
+ x, y, char = item
168
+ if 0 <= x < width and 0 <= y < height:
169
+ field[y][x] = char
170
+ for row in field:
171
+ print(''.join(row))
172
+
173
+ @staticmethod
174
+ def get_line_points(x1, y1, x2, y2, char='#'):
175
+ points = []
176
+ dx = abs(x2 - x1)
177
+ dy = abs(y2 - y1)
178
+ sx = 1 if x1 < x2 else -1
179
+ sy = 1 if y1 < y2 else -1
180
+ err = dx - dy
181
+ while True:
182
+ points.append((x1, y1, char))
183
+ if x1 == x2 and y1 == y2:
184
+ break
185
+ e2 = err * 2
186
+ if e2 > -dy:
187
+ err -= dy
188
+ x1 += sx
189
+ if e2 < dx:
190
+ err += dx
191
+ y1 += sy
192
+ return points
193
+
194
+ @staticmethod
195
+ def get_circle_points(cx, cy, r, char='#'):
196
+ points = []
197
+ for angle in range(0, 360, 5):
198
+ rad = angle * math.pi / 180
199
+ x = int(cx + r * math.cos(rad))
200
+ y = int(cy + r * math.sin(rad))
201
+ points.append((x, y, char))
202
+ return points
203
+
204
+ @staticmethod
205
+ def get_filled_circle_points(cx, cy, r, char='#'):
206
+ points = []
207
+ for y in range(cy - r, cy + r + 1):
208
+ for x in range(cx - r, cx + r + 1):
209
+ if (x - cx) ** 2 + (y - cy) ** 2 <= r ** 2:
210
+ points.append((x, y, char))
211
+ return points
212
+
213
+ @staticmethod
214
+ def get_rect_points(x1, y1, x2, y2, char='#'):
215
+ points = []
216
+ for x in range(x1, x2 + 1):
217
+ points.append((x, y1, char))
218
+ points.append((x, y2, char))
219
+ for y in range(y1, y2 + 1):
220
+ points.append((x1, y, char))
221
+ points.append((x2, y, char))
222
+ return points
223
+
224
+ @staticmethod
225
+ def get_fill_rect_points(x1, y1, x2, y2, char='#'):
226
+ points = []
227
+ for y in range(y1, y2 + 1):
228
+ for x in range(x1, x2 + 1):
229
+ points.append((x, y, char))
230
+ return points
231
+
232
+ @staticmethod
233
+ def get_text_points(x, y, text, char=None):
234
+ points = []
235
+ if char is None:
236
+ for i, ch in enumerate(text):
237
+ points.append((x + i, y, ch))
238
+ else:
239
+ for i in range(len(text)):
240
+ points.append((x + i, y, char))
241
+ return points
242
+
243
+ @staticmethod
244
+ def get_triangle_points(x1, y1, x2, y2, x3, y3, char='#'):
245
+ points = []
246
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
247
+ points.extend(Render.get_line_points(x2, y2, x3, y3, char))
248
+ points.extend(Render.get_line_points(x3, y3, x1, y1, char))
249
+ return points
250
+
251
+ @staticmethod
252
+ def get_filled_triangle_points(x1, y1, x2, y2, x3, y3, char='#'):
253
+ points = []
254
+ min_x = min(x1, x2, x3)
255
+ max_x = max(x1, x2, x3)
256
+ min_y = min(y1, y2, y3)
257
+ max_y = max(y1, y2, y3)
258
+ for y in range(min_y, max_y + 1):
259
+ for x in range(min_x, max_x + 1):
260
+ if Render._point_in_triangle(x, y, x1, y1, x2, y2, x3, y3):
261
+ points.append((x, y, char))
262
+ return points
263
+
264
+ @staticmethod
265
+ def get_heart_points(cx, cy, size=5, char='#'):
266
+ points = []
267
+ for y in range(-size, size + 1):
268
+ for x in range(-size, size + 1):
269
+ if ((x * x + y * y - size * size) ** 3 <= size * size * x * x * y * y * 0.5):
270
+ points.append((cx + x, cy - y, char))
271
+ return points
272
+
273
+ @staticmethod
274
+ def get_star_points(cx, cy, radius=5, points_count=5, char='*'):
275
+ points = []
276
+ angle = -math.pi / 2
277
+ step = math.pi / points_count
278
+ outer_points = []
279
+ inner_points = []
280
+ for i in range(points_count * 2):
281
+ r = radius if i % 2 == 0 else radius * 0.4
282
+ x = cx + r * math.cos(angle + i * step)
283
+ y = cy + r * math.sin(angle + i * step)
284
+ if i % 2 == 0:
285
+ outer_points.append((x, y))
286
+ else:
287
+ inner_points.append((x, y))
288
+ for i in range(points_count):
289
+ p1 = outer_points[i]
290
+ p2 = inner_points[i]
291
+ p3 = outer_points[(i + 1) % points_count]
292
+ points.extend(Render.get_line_points(int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), char))
293
+ points.extend(Render.get_line_points(int(p2[0]), int(p2[1]), int(p3[0]), int(p3[1]), char))
294
+ return points
295
+
296
+ @staticmethod
297
+ def get_bezier_points(x1, y1, x2, y2, x3, y3, steps=20, char='#'):
298
+ points = []
299
+ for t in range(steps + 1):
300
+ t = t / steps
301
+ x = (1 - t) ** 2 * x1 + 2 * (1 - t) * t * x2 + t ** 2 * x3
302
+ y = (1 - t) ** 2 * y1 + 2 * (1 - t) * t * y2 + t ** 2 * y3
303
+ points.append((int(x), int(y), char))
304
+ return points
305
+
306
+ @staticmethod
307
+ def get_wave_points(cx, cy, amplitude=5, length=20, char='~'):
308
+ points = []
309
+ for x in range(length):
310
+ y = cy + int(amplitude * math.sin(x * 0.5))
311
+ points.append((cx + x, y, char))
312
+ return points
313
+
314
+ @staticmethod
315
+ def get_spiral_points(cx, cy, turns=3, radius=10, step=0.1, char='*'):
316
+ points = []
317
+ angle = 0
318
+ r = 0
319
+ while r < radius:
320
+ x = int(cx + r * math.cos(angle))
321
+ y = int(cy + r * math.sin(angle))
322
+ points.append((x, y, char))
323
+ angle += step
324
+ r += step * 2
325
+ return points
326
+
327
+ @staticmethod
328
+ def get_grid_points(x1, y1, x2, y2, step=2, char='+'):
329
+ points = []
330
+ for x in range(x1, x2 + 1, step):
331
+ for y in range(y1, y2 + 1, step):
332
+ points.append((x, y, char))
333
+ return points
334
+
335
+ @staticmethod
336
+ def get_noise_points(cx, cy, radius, count=50, char='.'):
337
+ points = []
338
+ for _ in range(count):
339
+ angle = random.uniform(0, 2 * math.pi)
340
+ r = random.uniform(0, radius)
341
+ x = int(cx + r * math.cos(angle))
342
+ y = int(cy + r * math.sin(angle))
343
+ points.append((x, y, char))
344
+ return points
345
+
346
+ @staticmethod
347
+ def _point_in_triangle(px, py, x1, y1, x2, y2, x3, y3):
348
+ def sign(a, b, c):
349
+ return (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
350
+ p = (px, py)
351
+ d1 = sign(p, (x2, y2), (x1, y1))
352
+ d2 = sign(p, (x3, y3), (x2, y2))
353
+ d3 = sign(p, (x1, y1), (x3, y3))
354
+ has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
355
+ has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
356
+ return not (has_neg and has_pos)
357
+
358
+ @staticmethod
359
+ def _rotx(x, y, z, angle):
360
+ rad = math.radians(angle)
361
+ cos_a = math.cos(rad)
362
+ sin_a = math.sin(rad)
363
+ y_new = y * cos_a - z * sin_a
364
+ z_new = y * sin_a + z * cos_a
365
+ return x, y_new, z_new
366
+
367
+ @staticmethod
368
+ def _roty(x, y, z, angle):
369
+ rad = math.radians(angle)
370
+ cos_a = math.cos(rad)
371
+ sin_a = math.sin(rad)
372
+ x_new = x * cos_a + z * sin_a
373
+ z_new = -x * sin_a + z * cos_a
374
+ return x_new, y, z_new
375
+
376
+ @staticmethod
377
+ def _rotz(x, y, z, angle):
378
+ rad = math.radians(angle)
379
+ cos_a = math.cos(rad)
380
+ sin_a = math.sin(rad)
381
+ x_new = x * cos_a - y * sin_a
382
+ y_new = x * sin_a + y * cos_a
383
+ return x_new, y_new, z
384
+
385
+ @staticmethod
386
+ def _project_3d(x, y, z, rotx, roty, rotz, scale, cx, cy):
387
+ x, y, z = Render._rotx(x, y, z, rotx)
388
+ x, y, z = Render._roty(x, y, z, roty)
389
+ x, y, z = Render._rotz(x, y, z, rotz)
390
+ x2d = int(x * scale + cx)
391
+ y2d = int(-y * scale + cy)
392
+ return x2d, y2d
393
+
394
+ @staticmethod
395
+ def get_cube_3d_points(size=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
396
+ s = size / 2
397
+ vertices = [
398
+ (-s, -s, -s), (s, -s, -s), (s, s, -s), (-s, s, -s),
399
+ (-s, -s, s), (s, -s, s), (s, s, s), (-s, s, s)
400
+ ]
401
+ edges = [
402
+ (0,1), (1,2), (2,3), (3,0),
403
+ (4,5), (5,6), (6,7), (7,4),
404
+ (0,4), (1,5), (2,6), (3,7)
405
+ ]
406
+ points = []
407
+ projected = []
408
+ for v in vertices:
409
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
410
+ projected.append((x2d, y2d))
411
+ for edge in edges:
412
+ x1, y1 = projected[edge[0]]
413
+ x2, y2 = projected[edge[1]]
414
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
415
+ return points
416
+
417
+ @staticmethod
418
+ def get_pyramid_3d_points(size=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
419
+ s = size / 2
420
+ vertices = [
421
+ (-s, -s, -s), (s, -s, -s), (s, -s, s), (-s, -s, s),
422
+ (0, s, 0)
423
+ ]
424
+ edges = [
425
+ (0,1), (1,2), (2,3), (3,0),
426
+ (0,4), (1,4), (2,4), (3,4)
427
+ ]
428
+ points = []
429
+ projected = []
430
+ for v in vertices:
431
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
432
+ projected.append((x2d, y2d))
433
+ for edge in edges:
434
+ x1, y1 = projected[edge[0]]
435
+ x2, y2 = projected[edge[1]]
436
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
437
+ return points
438
+
439
+ @staticmethod
440
+ def get_cylinder_3d_points(radius=5, height=10, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
441
+ points = []
442
+ top_points = []
443
+ bottom_points = []
444
+ for i in range(segments):
445
+ rad = i / segments * 2 * math.pi
446
+ x = radius * math.cos(rad)
447
+ z = radius * math.sin(rad)
448
+ top_points.append((x, height/2, z))
449
+ bottom_points.append((x, -height/2, z))
450
+ all_vertices = top_points + bottom_points
451
+ projected = []
452
+ for v in all_vertices:
453
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
454
+ projected.append((x2d, y2d))
455
+ for i in range(segments):
456
+ j = (i + 1) % segments
457
+ x1, y1 = projected[i]
458
+ x2, y2 = projected[j]
459
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
460
+ x1, y1 = projected[i + segments]
461
+ x2, y2 = projected[j + segments]
462
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
463
+ x1, y1 = projected[i]
464
+ x2, y2 = projected[i + segments]
465
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
466
+ return points
467
+
468
+ @staticmethod
469
+ def get_sphere_3d_points(radius=5, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
470
+ points = []
471
+ for i in range(segments):
472
+ theta = i / segments * math.pi
473
+ for j in range(segments):
474
+ phi = j / segments * 2 * math.pi
475
+ x = radius * math.sin(theta) * math.cos(phi)
476
+ y = radius * math.cos(theta)
477
+ z = radius * math.sin(theta) * math.sin(phi)
478
+ x2d, y2d = Render._project_3d(x, y, z, rotx, roty, rotz, scale, cx, cy)
479
+ points.append((x2d, y2d, char))
480
+ return points
481
+
482
+ @staticmethod
483
+ def get_cone_3d_points(radius=5, height=10, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
484
+ points = []
485
+ base_points = []
486
+ for i in range(segments):
487
+ rad = i / segments * 2 * math.pi
488
+ x = radius * math.cos(rad)
489
+ z = radius * math.sin(rad)
490
+ base_points.append((x, -height/2, z))
491
+ apex = (0, height/2, 0)
492
+ all_vertices = base_points + [apex]
493
+ projected = []
494
+ for v in all_vertices:
495
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
496
+ projected.append((x2d, y2d))
497
+ for i in range(segments):
498
+ j = (i + 1) % segments
499
+ x1, y1 = projected[i]
500
+ x2, y2 = projected[j]
501
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
502
+ x1, y1 = projected[i]
503
+ x2, y2 = projected[-1]
504
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
505
+ return points
506
+
507
+ @staticmethod
508
+ def get_torus_3d_points(radius=8, tube=3, segments=16, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
509
+ points = []
510
+ for i in range(segments):
511
+ theta = i / segments * 2 * math.pi
512
+ for j in range(segments):
513
+ phi = j / segments * 2 * math.pi
514
+ x = (radius + tube * math.cos(phi)) * math.cos(theta)
515
+ y = tube * math.sin(phi)
516
+ z = (radius + tube * math.cos(phi)) * math.sin(theta)
517
+ x2d, y2d = Render._project_3d(x, y, z, rotx, roty, rotz, scale, cx, cy)
518
+ points.append((x2d, y2d, char))
519
+ return points
520
+
521
+ @staticmethod
522
+ def get_ico_sphere_3d_points(radius=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#'):
523
+ points = []
524
+ phi = (1 + math.sqrt(5)) / 2
525
+ vertices = [
526
+ (-1, phi, 0), ( 1, phi, 0), (-1, -phi, 0), ( 1, -phi, 0),
527
+ ( 0, -1, phi), ( 0, 1, phi), ( 0, -1, -phi), ( 0, 1, -phi),
528
+ ( phi, 0, -1), ( phi, 0, 1), (-phi, 0, -1), (-phi, 0, 1)
529
+ ]
530
+ vertices = [(x * radius / 1.618, y * radius / 1.618, z * radius / 1.618) for x, y, z in vertices]
531
+ edges = [
532
+ (0,1), (0,4), (0,5), (0,10), (0,11),
533
+ (1,2), (1,5), (1,7), (1,8), (1,9),
534
+ (2,3), (2,6), (2,7), (2,10), (2,11),
535
+ (3,4), (3,6), (3,8), (3,9), (3,11),
536
+ (4,5), (4,9), (4,11),
537
+ (5,7), (5,9),
538
+ (6,7), (6,10),
539
+ (7,8),
540
+ (8,9), (8,10),
541
+ (10,11)
542
+ ]
543
+ projected = []
544
+ for v in vertices:
545
+ x2d, y2d = Render._project_3d(v[0], v[1], v[2], rotx, roty, rotz, scale, cx, cy)
546
+ projected.append((x2d, y2d))
547
+ for edge in edges:
548
+ x1, y1 = projected[edge[0]]
549
+ x2, y2 = projected[edge[1]]
550
+ points.extend(Render.get_line_points(x1, y1, x2, y2, char))
551
+ return points
552
+
553
+ @staticmethod
554
+ def draw_cube_3d(size=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, height=25, clear_before_draw=False):
555
+ points = Render.get_cube_3d_points(size, rotx, roty, rotz, scale, cx, cy, char)
556
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
557
+
558
+ @staticmethod
559
+ def draw_pyramid_3d(size=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, height=25, clear_before_draw=False):
560
+ points = Render.get_pyramid_3d_points(size, rotx, roty, rotz, scale, cx, cy, char)
561
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
562
+
563
+ @staticmethod
564
+ def draw_cylinder_3d(radius=5, height=10, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, clear_before_draw=False):
565
+ points = Render.get_cylinder_3d_points(radius, height, segments, rotx, roty, rotz, scale, cx, cy, char)
566
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
567
+
568
+ @staticmethod
569
+ def draw_sphere_3d(radius=5, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, height=25, clear_before_draw=False):
570
+ points = Render.get_sphere_3d_points(radius, segments, rotx, roty, rotz, scale, cx, cy, char)
571
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
572
+
573
+ @staticmethod
574
+ def draw_cone_3d(radius=5, height=10, segments=12, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, clear_before_draw=False):
575
+ points = Render.get_cone_3d_points(radius, height, segments, rotx, roty, rotz, scale, cx, cy, char)
576
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
577
+
578
+ @staticmethod
579
+ def draw_torus_3d(radius=8, tube=3, segments=16, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, height=25, clear_before_draw=False):
580
+ points = Render.get_torus_3d_points(radius, tube, segments, rotx, roty, rotz, scale, cx, cy, char)
581
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
582
+
583
+ @staticmethod
584
+ def draw_ico_sphere_3d(radius=5, rotx=0, roty=0, rotz=0, scale=10, cx=40, cy=12, char='#', width=80, height=25, clear_before_draw=False):
585
+ points = Render.get_ico_sphere_3d_points(radius, rotx, roty, rotz, scale, cx, cy, char)
586
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
587
+
588
+ @staticmethod
589
+ def draw_line(x1, y1, x2, y2, char='#', width=80, height=25, clear_before_draw=False):
590
+ points = Render.get_line_points(x1, y1, x2, y2, char)
591
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
592
+
593
+ @staticmethod
594
+ def draw_circle(cx, cy, r, char='#', width=80, height=25, clear_before_draw=False):
595
+ points = Render.get_circle_points(cx, cy, r, char)
596
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
597
+
598
+ @staticmethod
599
+ def draw_filled_circle(cx, cy, r, char='#', width=80, height=25, clear_before_draw=False):
600
+ points = Render.get_filled_circle_points(cx, cy, r, char)
601
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
602
+
603
+ @staticmethod
604
+ def draw_rect(x1, y1, x2, y2, char='#', width=80, height=25, clear_before_draw=False):
605
+ points = Render.get_rect_points(x1, y1, x2, y2, char)
606
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
607
+
608
+ @staticmethod
609
+ def fill_rect(x1, y1, x2, y2, char='#', width=80, height=25, clear_before_draw=False):
610
+ points = Render.get_fill_rect_points(x1, y1, x2, y2, char)
611
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
612
+
613
+ @staticmethod
614
+ def draw_text(x, y, text, width=80, height=25, clear_before_draw=False):
615
+ points = Render.get_text_points(x, y, text)
616
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
617
+
618
+ @staticmethod
619
+ def draw_triangle(x1, y1, x2, y2, x3, y3, char='#', width=80, height=25, clear_before_draw=False):
620
+ points = Render.get_triangle_points(x1, y1, x2, y2, x3, y3, char)
621
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
622
+
623
+ @staticmethod
624
+ def fill_triangle(x1, y1, x2, y2, x3, y3, char='#', width=80, height=25, clear_before_draw=False):
625
+ points = Render.get_filled_triangle_points(x1, y1, x2, y2, x3, y3, char)
626
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
627
+
628
+ @staticmethod
629
+ def draw_heart(cx, cy, size=5, char='#', width=80, height=25, clear_before_draw=False):
630
+ points = Render.get_heart_points(cx, cy, size, char)
631
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
632
+
633
+ @staticmethod
634
+ def draw_star(cx, cy, radius=5, points_count=5, char='#', width=80, height=25, clear_before_draw=False):
635
+ points = Render.get_star_points(cx, cy, radius, points_count, char)
636
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
637
+
638
+ @staticmethod
639
+ def draw_bezier(x1, y1, x2, y2, x3, y3, steps=20, char='#', width=80, height=25, clear_before_draw=False):
640
+ points = Render.get_bezier_points(x1, y1, x2, y2, x3, y3, steps, char)
641
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
642
+
643
+ @staticmethod
644
+ def draw_wave(cx, cy, amplitude=5, length=20, char='~', width=80, height=25, clear_before_draw=False):
645
+ points = Render.get_wave_points(cx, cy, amplitude, length, char)
646
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
647
+
648
+ @staticmethod
649
+ def draw_spiral(cx, cy, turns=3, radius=10, step=0.1, char='*', width=80, height=25, clear_before_draw=False):
650
+ points = Render.get_spiral_points(cx, cy, turns, radius, step, char)
651
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
652
+
653
+ @staticmethod
654
+ def draw_grid(x1, y1, x2, y2, step=2, char='+', width=80, height=25, clear_before_draw=False):
655
+ points = Render.get_grid_points(x1, y1, x2, y2, step, char)
656
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
657
+
658
+ @staticmethod
659
+ def draw_noise(cx, cy, radius, count=50, char='.', width=80, height=25, clear_before_draw=False):
660
+ points = Render.get_noise_points(cx, cy, radius, count, char)
661
+ Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
662
+
663
+ class ConsoleInfo:
664
+ @staticmethod
665
+ def GetConsole():
666
+ return sys.stdout
667
+
668
+ @staticmethod
669
+ def GetPipVer():
670
+ try:
671
+ result = CMD.run(['python', '-m', 'pip', '--version'], capture_output=True, text=True, check=True)
672
+ return result.stdout.strip()
673
+ except CMD.CalledProcessError as e:
674
+ return f"Error: pip not found (code {e.returncode})"
675
+ except FileNotFoundError:
676
+ return "Error: Python not installed or not in PATH"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ConsoleLib
3
- Version: 1.3.0
3
+ Version: 1.3.2
4
4
  Summary: The library for easy and best control on the Console.
5
5
  Author-email: Suleiman <steal.apet@mail.ru>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ConsoleLib
3
- Version: 1.3.0
3
+ Version: 1.3.2
4
4
  Summary: The library for easy and best control on the Console.
5
5
  Author-email: Suleiman <steal.apet@mail.ru>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ConsoleLib"
7
- version = "1.3.0"
7
+ version = "1.3.2"
8
8
  description = "The library for easy and best control on the Console."
9
9
  authors = [{name = "Suleiman", email = "steal.apet@mail.ru"}]
10
10
  readme = "README.md"
@@ -1,226 +0,0 @@
1
- """
2
- ConsoleLib - The best Console Renderer of the Python.
3
- By: Suleiman
4
- Copyright © Suleiman 2026
5
- All rights are reserved.
6
- """
7
- import os
8
- import sys
9
- import time
10
- import subprocess as CMD
11
- import math
12
- class Render:
13
- @staticmethod
14
- def DrawPic(points=None, width=80, height=25, clear_before_draw=False, default_char=' '):
15
- if clear_before_draw:
16
- os.system("cls" if os.name == "nt" else "clear")
17
- field = [[default_char for _ in range(width)] for _ in range(height)]
18
- if points:
19
- for item in points:
20
- if len(item) == 3:
21
- x, y, char = item
22
- if 0 <= x < width and 0 <= y < height:
23
- field[y][x] = char
24
- for row in field:
25
- print(''.join(row))
26
- @staticmethod
27
- def get_line_points(x1, y1, x2, y2, char='#'):
28
- points = []
29
- dx = abs(x2 - x1)
30
- dy = abs(y2 - y1)
31
- sx = 1 if x1 < x2 else -1
32
- sy = 1 if y1 < y2 else -1
33
- err = dx - dy
34
- while True:
35
- points.append((x1, y1, char))
36
- if x1 == x2 and y1 == y2:
37
- break
38
- e2 = err * 2
39
- if e2 > -dy:
40
- err -= dy
41
- x1 += sx
42
- if e2 < dx:
43
- err += dx
44
- y1 += sy
45
- return points
46
- @staticmethod
47
- def get_circle_points(cx, cy, r, char='#'):
48
- points = []
49
- for angle in range(0, 360, 5):
50
- rad = angle * math.pi / 180
51
- x = int(cx + r * math.cos(rad))
52
- y = int(cy + r * math.sin(rad))
53
- points.append((x, y, char))
54
- return points
55
- @staticmethod
56
- def get_filled_circle_points(cx, cy, r, char='#'):
57
- points = []
58
- for y in range(cy - r, cy + r + 1):
59
- for x in range(cx - r, cx + r + 1):
60
- if (x - cx) ** 2 + (y - cy) ** 2 <= r ** 2:
61
- points.append((x, y, char))
62
- return points
63
- @staticmethod
64
- def get_rect_points(x1, y1, x2, y2, char='#'):
65
- points = []
66
- for x in range(x1, x2 + 1):
67
- points.append((x, y1, char))
68
- points.append((x, y2, char))
69
- for y in range(y1, y2 + 1):
70
- points.append((x1, y, char))
71
- points.append((x2, y, char))
72
- return points
73
- @staticmethod
74
- def get_fill_rect_points(x1, y1, x2, y2, char='#'):
75
- points = []
76
- for y in range(y1, y2 + 1):
77
- for x in range(x1, x2 + 1):
78
- points.append((x, y, char))
79
- return points
80
- @staticmethod
81
- def get_text_points(x, y, text, char=None):
82
- points = []
83
- if char is None:
84
- for i, ch in enumerate(text):
85
- points.append((x + i, y, ch))
86
- else:
87
- for i in range(len(text)):
88
- points.append((x + i, y, char))
89
- return points
90
- @staticmethod
91
- def get_triangle_points(x1, y1, x2, y2, x3, y3, char='#'):
92
- points = []
93
- points.extend(Render.get_line_points(x1, y1, x2, y2, char))
94
- points.extend(Render.get_line_points(x2, y2, x3, y3, char))
95
- points.extend(Render.get_line_points(x3, y3, x1, y1, char))
96
- return points
97
- @staticmethod
98
- def get_filled_triangle_points(x1, y1, x2, y2, x3, y3, char='#'):
99
- points = []
100
- min_x = min(x1, x2, x3)
101
- max_x = max(x1, x2, x3)
102
- min_y = min(y1, y2, y3)
103
- max_y = max(y1, y2, y3)
104
- for y in range(min_y, max_y + 1):
105
- for x in range(min_x, max_x + 1):
106
- if Render._point_in_triangle(x, y, x1, y1, x2, y2, x3, y3):
107
- points.append((x, y, char))
108
- return points
109
- @staticmethod
110
- def get_heart_points(cx, cy, size=5, char='#'):
111
- points = []
112
- for y in range(-size, size + 1):
113
- for x in range(-size, size + 1):
114
- if ((x * x + y * y - size * size) ** 3 <= size * size * x * x * y * y * 0.5):
115
- points.append((cx + x, cy - y, char))
116
- return points
117
- @staticmethod
118
- def get_star_points(cx, cy, radius=5, points_count=5, char='*'):
119
- points = []
120
- angle = -math.pi / 2
121
- step = math.pi / points_count
122
- outer_points = []
123
- inner_points = []
124
- for i in range(points_count * 2):
125
- r = radius if i % 2 == 0 else radius * 0.4
126
- x = cx + r * math.cos(angle + i * step)
127
- y = cy + r * math.sin(angle + i * step)
128
- if i % 2 == 0:
129
- outer_points.append((x, y))
130
- else:
131
- inner_points.append((x, y))
132
- for i in range(points_count):
133
- p1 = outer_points[i]
134
- p2 = inner_points[i]
135
- p3 = outer_points[(i + 1) % points_count]
136
- points.extend(Render.get_line_points(int(p1[0]), int(p1[1]), int(p2[0]), int(p2[1]), char))
137
- points.extend(Render.get_line_points(int(p2[0]), int(p2[1]), int(p3[0]), int(p3[1]), char))
138
- return points
139
- @staticmethod
140
- def get_bezier_points(x1, y1, x2, y2, x3, y3, steps=20, char='#'):
141
- points = []
142
- for t in range(steps + 1):
143
- t = t / steps
144
- x = (1 - t) ** 2 * x1 + 2 * (1 - t) * t * x2 + t ** 2 * x3
145
- y = (1 - t) ** 2 * y1 + 2 * (1 - t) * t * y2 + t ** 2 * y3
146
- points.append((int(x), int(y), char))
147
- return points
148
- @staticmethod
149
- def get_wave_points(cx, cy, amplitude=5, length=20, char='~'):
150
- points = []
151
- for x in range(length):
152
- y = cy + int(amplitude * math.sin(x * 0.5))
153
- points.append((cx + x, y, char))
154
- return points
155
- @staticmethod
156
- def _point_in_triangle(px, py, x1, y1, x2, y2, x3, y3):
157
- def sign(a, b, c):
158
- return (a[0] - c[0]) * (b[1] - c[1]) - (b[0] - c[0]) * (a[1] - c[1])
159
- p = (px, py)
160
- d1 = sign(p, (x2, y2), (x1, y1))
161
- d2 = sign(p, (x3, y3), (x2, y2))
162
- d3 = sign(p, (x1, y1), (x3, y3))
163
- has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
164
- has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
165
- return not (has_neg and has_pos)
166
- @staticmethod
167
- def draw_line(x1, y1, x2, y2, char='#', width=80, height=25, clear_before_draw=False):
168
- points = Render.get_line_points(x1, y1, x2, y2, char)
169
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
170
- @staticmethod
171
- def draw_circle(cx, cy, r, char='#', width=80, height=25, clear_before_draw=False):
172
- points = Render.get_circle_points(cx, cy, r, char)
173
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
174
- @staticmethod
175
- def draw_filled_circle(cx, cy, r, char='#', width=80, height=25, clear_before_draw=False):
176
- points = Render.get_filled_circle_points(cx, cy, r, char)
177
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
178
- @staticmethod
179
- def draw_rect(x1, y1, x2, y2, char='#', width=80, height=25, clear_before_draw=False):
180
- points = Render.get_rect_points(x1, y1, x2, y2, char)
181
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
182
- @staticmethod
183
- def fill_rect(x1, y1, x2, y2, char='#', width=80, height=25, clear_before_draw=False):
184
- points = Render.get_fill_rect_points(x1, y1, x2, y2, char)
185
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
186
- @staticmethod
187
- def draw_text(x, y, text, width=80, height=25, clear_before_draw=False):
188
- points = Render.get_text_points(x, y, text)
189
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
190
- @staticmethod
191
- def draw_triangle(x1, y1, x2, y2, x3, y3, char='#', width=80, height=25, clear_before_draw=False):
192
- points = Render.get_triangle_points(x1, y1, x2, y2, x3, y3, char)
193
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
194
- @staticmethod
195
- def fill_triangle(x1, y1, x2, y2, x3, y3, char='#', width=80, height=25, clear_before_draw=False):
196
- points = Render.get_filled_triangle_points(x1, y1, x2, y2, x3, y3, char)
197
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
198
- @staticmethod
199
- def draw_heart(cx, cy, size=5, char='#', width=80, height=25, clear_before_draw=False):
200
- points = Render.get_heart_points(cx, cy, size, char)
201
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
202
- @staticmethod
203
- def draw_star(cx, cy, radius=5, points_count=5, char='#', width=80, height=25, clear_before_draw=False):
204
- points = Render.get_star_points(cx, cy, radius, points_count, char)
205
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
206
- @staticmethod
207
- def draw_bezier(x1, y1, x2, y2, x3, y3, steps=20, char='#', width=80, height=25, clear_before_draw=False):
208
- points = Render.get_bezier_points(x1, y1, x2, y2, x3, y3, steps, char)
209
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
210
- @staticmethod
211
- def draw_wave(cx, cy, amplitude=5, length=20, char='~', width=80, height=25, clear_before_draw=False):
212
- points = Render.get_wave_points(cx, cy, amplitude, length, char)
213
- Render.DrawPic(points=points, width=width, height=height, clear_before_draw=clear_before_draw)
214
- class ConsoleInfo:
215
- @staticmethod
216
- def GetConsole():
217
- return sys.stdout
218
- @staticmethod
219
- def GetPipVer():
220
- try:
221
- result = CMD.run(['python', '-m', 'pip', '--version'], capture_output=True, text=True, check=True)
222
- return result.stdout.strip()
223
- except CMD.CalledProcessError as e:
224
- return f"Error: pip not found (code {e.returncode})"
225
- except FileNotFoundError:
226
- return "Error: Python not installed or not in PATH"
File without changes
File without changes