crystalwindow 4.5__py3-none-any.whl → 4.6__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.
crystalwindow/__init__.py CHANGED
@@ -32,8 +32,9 @@ from .collision import check_collision, resolve_collision
32
32
  from .gui import Button, Label, GUIManager, hex_to_rgb, Fade
33
33
  from .gui_ext import Toggle, Slider
34
34
 
35
- # === Time ===
36
- from .clock import Clock
35
+ # === Time System ===
36
+ # Includes upgraded Clock + all helper utilities
37
+ from .clock import Clock, Stopwatch, CountdownTimer, Scheduler
37
38
 
38
39
  # === Drawing Helpers ===
39
40
  from .draw_helpers import gradient_rect, CameraShake
@@ -81,14 +82,19 @@ __all__ = [
81
82
  # --- GUI Extensions ---
82
83
  "Toggle", "Slider",
83
84
 
84
- # --- Time ---
85
+ # --- Time System ---
86
+ # FULL time system is now exposed
85
87
  "Clock",
88
+ "Stopwatch",
89
+ "CountdownTimer",
90
+ "Scheduler",
86
91
 
87
92
  # --- Drawing ---
88
93
  "gradient_rect", "CameraShake", "DrawHelper", "DrawTextManager", "CrystalDraw",
89
94
 
90
95
  # --- Misc ---
91
- "random_name", "DebugOverlay", "Camera", "Colors", "Color", "random_palette", "lerp", "WebSearchResult", "WebSearch",
96
+ "random_name", "DebugOverlay", "Camera", "Colors", "Color",
97
+ "random_palette", "lerp", "WebSearchResult", "WebSearch",
92
98
 
93
99
  # --- 3D ---
94
100
  "CW3D",
crystalwindow/clock.py CHANGED
@@ -1,23 +1,189 @@
1
1
  import time
2
+ from datetime import datetime
3
+ from collections import deque
2
4
 
3
- class Clock:
5
+
6
+ # ============================================================
7
+ # Stopwatch Helper
8
+ # ============================================================
9
+ class Stopwatch:
10
+ def __init__(self):
11
+ self.start_time = None
12
+ self.elapsed_time = 0.0
13
+ self.running = False
14
+
15
+ def start(self):
16
+ if not self.running:
17
+ self.start_time = time.perf_counter()
18
+ self.running = True
19
+
20
+ def stop(self):
21
+ if self.running:
22
+ self.elapsed_time += time.perf_counter() - self.start_time
23
+ self.running = False
24
+
25
+ def reset(self):
26
+ self.start_time = None
27
+ self.elapsed_time = 0.0
28
+ self.running = False
29
+
30
+ def elapsed(self):
31
+ if self.running:
32
+ return self.elapsed_time + (time.perf_counter() - self.start_time)
33
+ return self.elapsed_time
34
+
35
+
36
+ # ============================================================
37
+ # Countdown Timer Helper
38
+ # ============================================================
39
+ class CountdownTimer:
4
40
  def __init__(self):
5
- self.last = time.time()
6
- self.delta = 0
7
- self.fps = 60
41
+ self.target_time = None
42
+
43
+ def start(self, seconds: float):
44
+ self.target_time = time.perf_counter() + seconds
45
+
46
+ def remaining(self):
47
+ if not self.target_time:
48
+ return 0
49
+ return max(0, self.target_time - time.perf_counter())
50
+
51
+ def done(self):
52
+ return self.remaining() == 0
53
+
54
+
55
+ # ============================================================
56
+ # Event Scheduler Helper
57
+ # ============================================================
58
+ class Scheduler:
59
+ def __init__(self):
60
+ self.events = [] # list of (interval, last_run, function)
61
+
62
+ def schedule(self, interval: float, func):
63
+ """Run function every `interval` seconds."""
64
+ self.events.append([interval, time.perf_counter(), func])
65
+
66
+ def run_pending(self):
67
+ now = time.perf_counter()
68
+ for event in self.events:
69
+ interval, last_run, func = event
70
+ if now - last_run >= interval:
71
+ func()
72
+ event[1] = now # update last_run
73
+
74
+
75
+ # ============================================================
76
+ # MAIN CLOCK
77
+ # ============================================================
78
+ class Clock:
79
+ def __init__(self, target_fps: int = 60, smooth_fps: int = 30):
80
+ self.last = time.perf_counter()
81
+ self.delta = 0.0
82
+
83
+ # FPS
84
+ self.target_fps = target_fps
85
+ self.min_frame_time = 1 / target_fps if target_fps else 0
86
+ self.frame_times = deque(maxlen=smooth_fps)
87
+
88
+ self.paused = False
89
+
90
+ # Utilities
91
+ self.stopwatch = Stopwatch()
92
+ self.timer = CountdownTimer()
93
+ self.scheduler = Scheduler()
94
+
95
+ # ----------------------------------------------------------
96
+ # TICK + FPS
97
+ # ----------------------------------------------------------
98
+ def tick(self, fps: int | None = None):
99
+ if fps:
100
+ self.target_fps = fps
101
+ self.min_frame_time = 1 / fps
8
102
 
9
- def tick(self, fps=None):
10
- now = time.time()
11
- self.delta = now - self.last
103
+ now = time.perf_counter()
104
+ raw_delta = now - self.last
12
105
  self.last = now
13
106
 
14
- if fps:
15
- self.fps = fps
16
- sleep_for = (1 / fps) - self.delta
17
- if sleep_for > 0:
18
- time.sleep(sleep_for)
107
+ # Paused = no delta
108
+ if self.paused:
109
+ self.delta = 0.0
110
+ return 0.0
111
+
112
+ # FPS limiting
113
+ sleep_time = self.min_frame_time - raw_delta
114
+ if sleep_time > 0:
115
+ time.sleep(sleep_time)
116
+ now2 = time.perf_counter()
117
+ raw_delta = now2 - (self.last - raw_delta)
118
+
119
+ self.delta = raw_delta
120
+ self.frame_times.append(raw_delta)
121
+
122
+ # Scheduler update
123
+ self.scheduler.run_pending()
19
124
 
20
125
  return self.delta
21
126
 
22
127
  def get_fps(self):
23
- return round(1 / self.delta, 2) if self.delta else 0
128
+ if not self.frame_times:
129
+ return 0.0
130
+ avg = sum(self.frame_times) / len(self.frame_times)
131
+ return round(1 / avg, 2) if avg > 0 else 0
132
+
133
+ # ----------------------------------------------------------
134
+ # PAUSE / RESUME
135
+ # ----------------------------------------------------------
136
+ def pause(self):
137
+ self.paused = True
138
+
139
+ def resume(self):
140
+ self.paused = False
141
+ self.last = time.perf_counter()
142
+
143
+ # ----------------------------------------------------------
144
+ # TIME + DATE UTILITIES
145
+ # ----------------------------------------------------------
146
+ def time(self, milliseconds: bool = True, hour_12: bool = False):
147
+ now = datetime.now()
148
+
149
+ if hour_12:
150
+ fmt = "%I:%M:%S" + (" %p" if not milliseconds else ".%f %p")
151
+ else:
152
+ fmt = "%H:%M:%S" + (".%f" if milliseconds else "")
153
+
154
+ text = now.strftime(fmt)
155
+ if milliseconds:
156
+ # Trim microseconds to milliseconds
157
+ if hour_12:
158
+ # Example: "03:20:15.123000 PM" -> "03:20:15.123 PM"
159
+ parts = text.split(".")
160
+ ms = parts[1][:3] + parts[1][6:] # keep .mmm, remove "000 PM"
161
+ text = parts[0] + "." + parts[1][:3] + " " + now.strftime("%p")
162
+ else:
163
+ text = text[:-3] # remove last 3 microseconds digits
164
+
165
+ return text
166
+
167
+ def date(self, format: str = "%m/%d/%Y"):
168
+ return datetime.now().strftime(format)
169
+
170
+ def time_date(self, order: str = "time_first", **kwargs):
171
+ t = self.time(**kwargs)
172
+ d = self.date()
173
+ return f"{t} | {d}" if order == "time_first" else f"{d} | {t}"
174
+
175
+ # ----------------------------------------------------------
176
+ # CUSTOM FORMATTERS
177
+ # ----------------------------------------------------------
178
+ def format_time(self, fmt: str):
179
+ return datetime.now().strftime(fmt)
180
+
181
+ def format_date(self, fmt: str):
182
+ return datetime.now().strftime(fmt)
183
+
184
+ # ----------------------------------------------------------
185
+ # MONOTONIC TIMESTAMP
186
+ # ----------------------------------------------------------
187
+ def timestamp(self):
188
+ """High-precision monotonic timestamp."""
189
+ return time.perf_counter()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 4.5
3
+ Version: 4.6
4
4
  Summary: A Tkinter powered window + GUI toolkit made by Crystal (MEEEEEE)! Easier apps, smoother UI and all-in-one helpers!
5
5
  Home-page: https://pypi.org/project/crystalwindow/
6
6
  Author: CrystalBallyHereXD
@@ -1,10 +1,10 @@
1
1
  crystalwindow/FileHelper.py,sha256=aUnnRG7UwvzJt-idjWjmpwy3RM6nqLlC3-7Bae6Yb94,5471
2
- crystalwindow/__init__.py,sha256=nOEUvoB4OpcYq_le1Kee0Uef3Jq38bYYapOI1u1CN2E,2457
2
+ crystalwindow/__init__.py,sha256=Vr7Zd7Wgsu4id-3KaVuIkorRm80srd4zNR8fXWJZuhY,2662
3
3
  crystalwindow/ai.py,sha256=YIt6dNe1QljSAlNECCVa3DMUSIqQEJRIAAbQpYqFNNo,11525
4
4
  crystalwindow/animation.py,sha256=zHjrdBXQeyNaLAuaGPldJueX05OZ5j31YR8NizmR0uQ,427
5
5
  crystalwindow/assets.py,sha256=2Cj0zdhMWo3mWjdr9KU5n-9_8iKj_fJ9uShMFA-27HU,5193
6
6
  crystalwindow/camera.py,sha256=tbn4X-jxMIszAUg3Iu-89gJN5nij0mjPMEzGotcLbJI,712
7
- crystalwindow/clock.py,sha256=EAcNvxonD7ktkKSIbuVHqzhPhQqtUQtleMSBB_OuUQY,541
7
+ crystalwindow/clock.py,sha256=P7Hzv6-_sHIwJRFcoMLMjQB2BnVjpQWQhRHotp6OPV0,6105
8
8
  crystalwindow/collision.py,sha256=hpkHTp_KparghVK-itp_rxuYdd2GbQMxICHlUBv0rSw,472
9
9
  crystalwindow/color_handler.py,sha256=ZnXnz8552GPiRAnCkW_8wycwRRMAaFRFLlCcsrv0j2E,4071
10
10
  crystalwindow/crystal3d.py,sha256=-Te9IJgbtzl8Mpuc4BPi2bn2apnvBNTI2GwxSLd8sqg,2006
@@ -35,8 +35,8 @@ crystalwindow/gametests/guitesting.py,sha256=SrOssY5peCQEV6TQ1AiOWtjb9phVGdRzW-Q
35
35
  crystalwindow/gametests/sandbox.py,sha256=Oo2tU2N0y3BPVa6T5vs_h9N6islhQrjSrr_78XLut5I,1007
36
36
  crystalwindow/gametests/squaremove.py,sha256=poP2Zjl2oc2HVvIAgIK34H2jVj6otL4jEdvAOR6L9sI,572
37
37
  crystalwindow/gametests/windowtesting.py,sha256=_9X6wnV1-_X_PtNS-0zu-k209NtFIwAc4vpxLPp7V2o,97
38
- crystalwindow-4.5.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
39
- crystalwindow-4.5.dist-info/METADATA,sha256=nWirrrZxkZMaUYGi8BbZQ3fGFCh0d0OZTtLReJHzYls,7338
40
- crystalwindow-4.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
41
- crystalwindow-4.5.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
42
- crystalwindow-4.5.dist-info/RECORD,,
38
+ crystalwindow-4.6.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
39
+ crystalwindow-4.6.dist-info/METADATA,sha256=PSVgwP0RGNqMC7PerNTZkFFH4KzslVZNDBCZ9MHrsww,7338
40
+ crystalwindow-4.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
41
+ crystalwindow-4.6.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
42
+ crystalwindow-4.6.dist-info/RECORD,,