crystalwindow 5.1__tar.gz → 5.3__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.
- {crystalwindow-5.1/crystalwindow.egg-info → crystalwindow-5.3}/PKG-INFO +1 -1
- crystalwindow-5.3/crystalwindow/Fonts.py +30 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/__init__.py +12 -0
- crystalwindow-5.3/crystalwindow/apphelper.py +101 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/camera.py +18 -9
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/draw_helpers.py +3 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/objects.py +11 -3
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/window.py +7 -1
- {crystalwindow-5.1 → crystalwindow-5.3/crystalwindow.egg-info}/PKG-INFO +1 -1
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow.egg-info/SOURCES.txt +2 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/setup.py +1 -1
- {crystalwindow-5.1 → crystalwindow-5.3}/LICENSE +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/MANIFEST.in +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/README.md +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/FileHelper.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/Icons/default_icon.png +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/Icons/file_icons.png +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/ai.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/animation.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/assets.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/chatvpn.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/clock.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/collision.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/color_handler.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/crystal3d.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/docs/getting_started.md +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/docs/index.md +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/draw_rects.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/draw_text_helper.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/draw_tool.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/fun_helpers.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/3dsquare.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/__init__.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/__main__.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/gravitytest.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/guitesting.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/sandbox.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/squaremove.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/testtttagain.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gametests/windowtesting.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gravity.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gui.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/gui_ext.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/math.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/messagebus.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/sprites.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/tilemap.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/ver_warner.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow/websearch.py +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow.egg-info/dependency_links.txt +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow.egg-info/requires.txt +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/crystalwindow.egg-info/top_level.txt +0 -0
- {crystalwindow-5.1 → crystalwindow-5.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (ME)! Easier apps, smoother UI and all-in-one helpers!, Gui, Buttons, FileHelper, Sprites, Animations, Colors, Math, Gravity, Camera, 3D and more!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from PIL import ImageFont
|
|
3
|
+
|
|
4
|
+
class Font:
|
|
5
|
+
def __init__(self, size=16, font_name="Arial", font_path=None):
|
|
6
|
+
self.size = size
|
|
7
|
+
self.font_name = font_name
|
|
8
|
+
self.font_path = font_path
|
|
9
|
+
self.font = self.load_font()
|
|
10
|
+
|
|
11
|
+
def load_font(self):
|
|
12
|
+
try:
|
|
13
|
+
if self.font_path and os.path.isfile(self.font_path):
|
|
14
|
+
return ImageFont.truetype(self.font_path, self.size)
|
|
15
|
+
|
|
16
|
+
return ImageFont.truetype(self.font_name, self.size)
|
|
17
|
+
|
|
18
|
+
except Exception as e:
|
|
19
|
+
print(f"[Font] Fallback used: {e}")
|
|
20
|
+
return ImageFont.load_default()
|
|
21
|
+
|
|
22
|
+
def set_size(self, new_size):
|
|
23
|
+
self.size = new_size
|
|
24
|
+
self.font = self.load_font()
|
|
25
|
+
|
|
26
|
+
def set_font(self, new_font_name=None, new_font_path=None):
|
|
27
|
+
if new_font_name:
|
|
28
|
+
self.font_name = new_font_name
|
|
29
|
+
self.font_path = new_font_path
|
|
30
|
+
self.font = self.load_font()
|
|
@@ -58,6 +58,12 @@ from .chatvpn import ChatVPN, ChatVPNServer
|
|
|
58
58
|
# ==== Message Bus ====
|
|
59
59
|
from .messagebus import send_message, view_message, clear_messages
|
|
60
60
|
|
|
61
|
+
# ==== Fonts =======
|
|
62
|
+
from .Fonts import Font
|
|
63
|
+
|
|
64
|
+
# === App/Window ====
|
|
65
|
+
from .apphelper import GameAppHelper
|
|
66
|
+
|
|
61
67
|
__all__ = [
|
|
62
68
|
# --- Core ---
|
|
63
69
|
"Window", "Sprite", "TileMap", "Player", "Block", "Enemy", "Gravity", "FileHelper", "Mathematics",
|
|
@@ -103,4 +109,10 @@ __all__ = [
|
|
|
103
109
|
|
|
104
110
|
# --- Message Bus ---
|
|
105
111
|
"send_message", "view_message", "clear_messages",
|
|
112
|
+
|
|
113
|
+
# === Fonts ===
|
|
114
|
+
"Font",
|
|
115
|
+
|
|
116
|
+
# --- App/Window ---
|
|
117
|
+
"GameAppHelper",
|
|
106
118
|
]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
class GameAppHelper:
|
|
6
|
+
DEFAULT_APPS = {
|
|
7
|
+
"notepad": "notepad.exe",
|
|
8
|
+
"calculator": "calc.exe",
|
|
9
|
+
"explorer": "explorer.exe",
|
|
10
|
+
"cmd": "cmd.exe",
|
|
11
|
+
"powershell": "powershell.exe",
|
|
12
|
+
"taskmgr": "taskmgr.exe",
|
|
13
|
+
"paint": "mspaint.exe"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
# exe_name -> list of processes
|
|
18
|
+
self.running_apps = {}
|
|
19
|
+
|
|
20
|
+
# -------------------------------
|
|
21
|
+
# OPEN DEFAULT WINDOWS APP
|
|
22
|
+
# -------------------------------
|
|
23
|
+
def open_default_app(self, app_name):
|
|
24
|
+
app = self.DEFAULT_APPS.get(app_name.lower())
|
|
25
|
+
if not app:
|
|
26
|
+
print(f"[AppHelper] Unknown default app: {app_name}")
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
self._launch_process(app)
|
|
30
|
+
|
|
31
|
+
# -------------------------------
|
|
32
|
+
# OPEN ANY APP BY PATH OR EXE
|
|
33
|
+
# -------------------------------
|
|
34
|
+
def open_app(self, app_path):
|
|
35
|
+
exe = os.path.basename(app_path)
|
|
36
|
+
self._launch_process(app_path, exe)
|
|
37
|
+
|
|
38
|
+
# -------------------------------
|
|
39
|
+
# INTERNAL LAUNCH
|
|
40
|
+
# -------------------------------
|
|
41
|
+
def _launch_process(self, command, exe_name=None):
|
|
42
|
+
try:
|
|
43
|
+
proc = subprocess.Popen(command)
|
|
44
|
+
|
|
45
|
+
exe = exe_name or os.path.basename(command)
|
|
46
|
+
exe = exe.lower()
|
|
47
|
+
|
|
48
|
+
self.running_apps.setdefault(exe, []).append(proc)
|
|
49
|
+
|
|
50
|
+
print(f"[AppHelper] Opened {exe}")
|
|
51
|
+
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(f"[AppHelper] Failed to open app: {e}")
|
|
54
|
+
|
|
55
|
+
# -------------------------------
|
|
56
|
+
# CLOSE / KILL BY EXE NAME
|
|
57
|
+
# -------------------------------
|
|
58
|
+
def close_app(self, exe_name):
|
|
59
|
+
exe = exe_name.lower()
|
|
60
|
+
procs = self.running_apps.get(exe)
|
|
61
|
+
|
|
62
|
+
if not procs:
|
|
63
|
+
print(f"[AppHelper] No running app named {exe}")
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
for proc in procs:
|
|
67
|
+
try:
|
|
68
|
+
proc.kill() # HARD kill
|
|
69
|
+
except Exception:
|
|
70
|
+
os.system(f"taskkill /PID {proc.pid} /F")
|
|
71
|
+
|
|
72
|
+
del self.running_apps[exe]
|
|
73
|
+
print(f"[AppHelper] Closed all instances of {exe}")
|
|
74
|
+
|
|
75
|
+
# -------------------------------
|
|
76
|
+
# CLOSE ONLY ONE INSTANCE (OPTIONAL)
|
|
77
|
+
# -------------------------------
|
|
78
|
+
def close_one(self, exe_name):
|
|
79
|
+
exe = exe_name.lower()
|
|
80
|
+
procs = self.running_apps.get(exe)
|
|
81
|
+
|
|
82
|
+
if not procs:
|
|
83
|
+
print(f"[AppHelper] No running app named {exe}")
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
proc = procs.pop()
|
|
87
|
+
try:
|
|
88
|
+
proc.kill()
|
|
89
|
+
except:
|
|
90
|
+
os.system(f"taskkill /PID {proc.pid} /F")
|
|
91
|
+
|
|
92
|
+
if not procs:
|
|
93
|
+
del self.running_apps[exe]
|
|
94
|
+
|
|
95
|
+
print(f"[AppHelper] Closed one instance of {exe}")
|
|
96
|
+
|
|
97
|
+
# -------------------------------
|
|
98
|
+
# CLOSE PYTHON APP
|
|
99
|
+
# -------------------------------
|
|
100
|
+
def close_current_app(self):
|
|
101
|
+
sys.exit()
|
|
@@ -4,23 +4,28 @@ class Camera:
|
|
|
4
4
|
self.offset_x = 0
|
|
5
5
|
self.offset_y = 0
|
|
6
6
|
self.speed = speed # smoothness
|
|
7
|
+
self.shake = None
|
|
7
8
|
|
|
8
9
|
def update(self, win_width, win_height, dt):
|
|
9
|
-
# camera aims for target
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# camera aims for target selected
|
|
11
|
+
if self.target is not None:
|
|
12
|
+
target_x = self.target.x - win_width // 2
|
|
13
|
+
target_y = self.target.y - win_height // 2
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
# smooth lerp follow
|
|
16
|
+
self.offset_x += (target_x - self.offset_x) * self.speed
|
|
17
|
+
self.offset_y += (target_y - self.offset_y) * self.speed
|
|
18
|
+
|
|
19
|
+
if self.shake:
|
|
20
|
+
alive = self.shake.update(dt)
|
|
21
|
+
if not alive:
|
|
22
|
+
self.shake = None # 💥 ACTUALLY STOPS IT
|
|
16
23
|
|
|
17
|
-
if hasattr(self, "shake"):
|
|
18
|
-
self.shake.update(dt)
|
|
19
24
|
|
|
20
25
|
def apply(self, obj):
|
|
21
26
|
# shift object's draw position by camera offset
|
|
22
27
|
sx, sy = (0, 0)
|
|
23
|
-
if
|
|
28
|
+
if self.shake:
|
|
24
29
|
sx, sy = self.shake.offset
|
|
25
30
|
|
|
26
31
|
return (
|
|
@@ -33,6 +38,10 @@ class Camera:
|
|
|
33
38
|
from .draw_helpers import CameraShake
|
|
34
39
|
self.shake = CameraShake(intensity, secs)
|
|
35
40
|
|
|
41
|
+
# Helper if the shake_scrn dosent want to stop
|
|
42
|
+
def stop_shake(self):
|
|
43
|
+
self.shake = None
|
|
44
|
+
|
|
36
45
|
def move_to(self, x, y):
|
|
37
46
|
self.offset_x = x
|
|
38
47
|
self.offset_y = y
|
|
@@ -20,11 +20,14 @@ class CameraShake:
|
|
|
20
20
|
|
|
21
21
|
def update(self, dt):
|
|
22
22
|
import random
|
|
23
|
+
|
|
23
24
|
if self.time_left > 0:
|
|
24
25
|
self.time_left -= dt
|
|
25
26
|
self.offset = (
|
|
26
27
|
random.randint(-self.intensity, self.intensity),
|
|
27
28
|
random.randint(-self.intensity, self.intensity)
|
|
28
29
|
)
|
|
30
|
+
return True
|
|
29
31
|
else:
|
|
30
32
|
self.offset = (0, 0)
|
|
33
|
+
return False
|
|
@@ -128,12 +128,20 @@ class Player(Sprite):
|
|
|
128
128
|
# BLOCK (same)
|
|
129
129
|
# ============================================================
|
|
130
130
|
class Block(Sprite):
|
|
131
|
-
def __init__(self,
|
|
131
|
+
def __init__(self, x, y, w, h, color=None, texture=None):
|
|
132
|
+
self.x = x
|
|
133
|
+
self.y = y
|
|
134
|
+
self.w, self.h = w, h
|
|
135
|
+
self.color = color
|
|
136
|
+
|
|
132
137
|
if texture:
|
|
133
138
|
img = load_image(texture)
|
|
134
|
-
super().__init__(
|
|
139
|
+
super().__init__((x, y), size=(w, h), image=img)
|
|
135
140
|
else:
|
|
136
|
-
super().__init__(
|
|
141
|
+
super().__init__((x, y), size=(w, h), color=color or (150,150,150))
|
|
142
|
+
|
|
143
|
+
def draw(self, win):
|
|
144
|
+
win.draw_rect(self.color, (self.x, self.y, self.w, self.h))
|
|
137
145
|
|
|
138
146
|
def collide_with(self, other):
|
|
139
147
|
return self.colliderect(other)
|
|
@@ -153,7 +153,7 @@ class Window:
|
|
|
153
153
|
self._bg_color = (20, 20, 50)
|
|
154
154
|
self.draw_calls = []
|
|
155
155
|
self._key_last = {} # new dict to store last press time per key
|
|
156
|
-
self._key_cooldown = 0.
|
|
156
|
+
self._key_cooldown = 0.0001 # seconds, tweak for faster/slower input
|
|
157
157
|
|
|
158
158
|
# === Event bindings ===
|
|
159
159
|
self.root.bind("<KeyPress>", self._on_keydown)
|
|
@@ -193,6 +193,7 @@ class Window:
|
|
|
193
193
|
pressed[event.num - 1] = False
|
|
194
194
|
self._mouse_pressed = tuple(pressed)
|
|
195
195
|
|
|
196
|
+
|
|
196
197
|
# === Helpers ===
|
|
197
198
|
def key_pressed(self, key):
|
|
198
199
|
if isinstance(key, str):
|
|
@@ -208,6 +209,11 @@ class Window:
|
|
|
208
209
|
|
|
209
210
|
return False
|
|
210
211
|
|
|
212
|
+
def key_held(self, key):
|
|
213
|
+
if isinstance(key, str):
|
|
214
|
+
key = self.KEY_MAP.get(key, key)
|
|
215
|
+
return self.keys.get(key, False)
|
|
216
|
+
|
|
211
217
|
def mouse_pressed(self, button=1):
|
|
212
218
|
return self._mouse_pressed[button - 1]
|
|
213
219
|
def add_tab(self, title, widget):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (ME)! Easier apps, smoother UI and all-in-one helpers!, Gui, Buttons, FileHelper, Sprites, Animations, Colors, Math, Gravity, Camera, 3D and more!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
@@ -3,9 +3,11 @@ MANIFEST.in
|
|
|
3
3
|
README.md
|
|
4
4
|
setup.py
|
|
5
5
|
crystalwindow/FileHelper.py
|
|
6
|
+
crystalwindow/Fonts.py
|
|
6
7
|
crystalwindow/__init__.py
|
|
7
8
|
crystalwindow/ai.py
|
|
8
9
|
crystalwindow/animation.py
|
|
10
|
+
crystalwindow/apphelper.py
|
|
9
11
|
crystalwindow/assets.py
|
|
10
12
|
crystalwindow/camera.py
|
|
11
13
|
crystalwindow/chatvpn.py
|
|
@@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f:
|
|
|
7
7
|
|
|
8
8
|
setup(
|
|
9
9
|
name="crystalwindow",
|
|
10
|
-
version="5.
|
|
10
|
+
version="5.3", # Force metadata refresh
|
|
11
11
|
packages=find_packages(include=["crystalwindow", "crystalwindow.*"]),
|
|
12
12
|
|
|
13
13
|
include_package_data=True, # include package_data files
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|