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 +10 -4
- crystalwindow/clock.py +179 -13
- {crystalwindow-4.5.dist-info → crystalwindow-4.6.dist-info}/METADATA +1 -1
- {crystalwindow-4.5.dist-info → crystalwindow-4.6.dist-info}/RECORD +7 -7
- {crystalwindow-4.5.dist-info → crystalwindow-4.6.dist-info}/WHEEL +0 -0
- {crystalwindow-4.5.dist-info → crystalwindow-4.6.dist-info}/licenses/LICENSE +0 -0
- {crystalwindow-4.5.dist-info → crystalwindow-4.6.dist-info}/top_level.txt +0 -0
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
|
-
|
|
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",
|
|
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
|
-
|
|
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.
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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.
|
|
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=
|
|
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=
|
|
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.
|
|
39
|
-
crystalwindow-4.
|
|
40
|
-
crystalwindow-4.
|
|
41
|
-
crystalwindow-4.
|
|
42
|
-
crystalwindow-4.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|