crystalwindow 4.6__tar.gz → 4.8__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.
Files changed (59) hide show
  1. {crystalwindow-4.6/crystalwindow.egg-info → crystalwindow-4.8}/PKG-INFO +6 -2
  2. crystalwindow-4.8/crystalwindow/FileHelper.py +263 -0
  3. crystalwindow-4.8/crystalwindow/Icons/file_icons.png +0 -0
  4. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/__init__.py +16 -27
  5. crystalwindow-4.8/crystalwindow/assets.py +382 -0
  6. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/clock.py +21 -63
  7. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/color_handler.py +3 -21
  8. crystalwindow-4.8/crystalwindow/crystal3d.py +140 -0
  9. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/fun_helpers.py +4 -0
  10. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/3dsquare.py +2 -2
  11. crystalwindow-4.8/crystalwindow/gametests/gravitytest.py +120 -0
  12. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/guitesting.py +4 -2
  13. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/squaremove.py +4 -1
  14. crystalwindow-4.8/crystalwindow/gametests/testtttagain.py +17 -0
  15. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gui.py +87 -17
  16. crystalwindow-4.8/crystalwindow/gui_ext.py +110 -0
  17. crystalwindow-4.8/crystalwindow/objects.py +171 -0
  18. crystalwindow-4.8/crystalwindow/sprites.py +257 -0
  19. crystalwindow-4.8/crystalwindow/tilemap.py +103 -0
  20. crystalwindow-4.8/crystalwindow/websearch.py +160 -0
  21. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/window.py +430 -12
  22. {crystalwindow-4.6 → crystalwindow-4.8/crystalwindow.egg-info}/PKG-INFO +6 -2
  23. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow.egg-info/SOURCES.txt +4 -2
  24. crystalwindow-4.8/crystalwindow.egg-info/requires.txt +3 -0
  25. {crystalwindow-4.6 → crystalwindow-4.8}/setup.py +9 -2
  26. crystalwindow-4.6/crystalwindow/FileHelper.py +0 -142
  27. crystalwindow-4.6/crystalwindow/assets.py +0 -191
  28. crystalwindow-4.6/crystalwindow/crystal3d.py +0 -61
  29. crystalwindow-4.6/crystalwindow/cw_client.py +0 -95
  30. crystalwindow-4.6/crystalwindow/gametests/gravitytest.py +0 -47
  31. crystalwindow-4.6/crystalwindow/gui_ext.py +0 -98
  32. crystalwindow-4.6/crystalwindow/player.py +0 -106
  33. crystalwindow-4.6/crystalwindow/sprites.py +0 -108
  34. crystalwindow-4.6/crystalwindow/tilemap.py +0 -13
  35. crystalwindow-4.6/crystalwindow/websearch.py +0 -233
  36. {crystalwindow-4.6 → crystalwindow-4.8}/LICENSE +0 -0
  37. {crystalwindow-4.6 → crystalwindow-4.8}/MANIFEST.in +0 -0
  38. {crystalwindow-4.6 → crystalwindow-4.8}/README.md +0 -0
  39. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/Icons/default_icon.png +0 -0
  40. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/ai.py +0 -0
  41. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/animation.py +0 -0
  42. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/camera.py +0 -0
  43. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/collision.py +0 -0
  44. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/docs/getting_started.md +0 -0
  45. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/docs/index.md +0 -0
  46. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/draw_helpers.py +0 -0
  47. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/draw_rects.py +0 -0
  48. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/draw_text_helper.py +0 -0
  49. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/draw_tool.py +0 -0
  50. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/__init__.py +0 -0
  51. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/__main__.py +0 -0
  52. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/sandbox.py +0 -0
  53. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gametests/windowtesting.py +0 -0
  54. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/gravity.py +0 -0
  55. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/math.py +0 -0
  56. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow/ver_warner.py +0 -0
  57. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow.egg-info/dependency_links.txt +0 -0
  58. {crystalwindow-4.6 → crystalwindow-4.8}/crystalwindow.egg-info/top_level.txt +0 -0
  59. {crystalwindow-4.6 → crystalwindow-4.8}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 4.6
4
- Summary: A Tkinter powered window + GUI toolkit made by Crystal (MEEEEEE)! Easier apps, smoother UI and all-in-one helpers!
3
+ Version: 4.8
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
7
7
  Author-email: mavilla.519@gmail.com
@@ -16,6 +16,9 @@ Classifier: License :: OSI Approved :: MIT License
16
16
  Requires-Python: >=3.6
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
+ Requires-Dist: requests
20
+ Requires-Dist: packaging
21
+ Requires-Dist: pillow
19
22
  Dynamic: author
20
23
  Dynamic: author-email
21
24
  Dynamic: classifier
@@ -25,6 +28,7 @@ Dynamic: home-page
25
28
  Dynamic: keywords
26
29
  Dynamic: license-file
27
30
  Dynamic: project-url
31
+ Dynamic: requires-dist
28
32
  Dynamic: requires-python
29
33
  Dynamic: summary
30
34
 
@@ -0,0 +1,263 @@
1
+ """
2
+ CrystalWindow FileHelper
3
+ ------------------------
4
+ Handles saving/loading text, JSON, and pickle files.
5
+ Uses Tk file dialogs, auto-creates 'saves/' folder,
6
+ and supports image fallback + resizing.
7
+ """
8
+
9
+ import os
10
+ import json
11
+ import pickle
12
+ import tkinter as tk
13
+ from tkinter import filedialog
14
+ from PIL import Image, ImageTk
15
+ from .assets import load_image
16
+
17
+
18
+ class FileHelper:
19
+ """CrystalWindow integrated file helper."""
20
+
21
+ def __init__(self, default_save_folder="saves"):
22
+ self.default_save_folder = default_save_folder
23
+ self.last_dir = "."
24
+ os.makedirs(self.default_save_folder, exist_ok=True)
25
+
26
+ # ======================================================================
27
+ # INTERNAL TK ROOT
28
+ # ======================================================================
29
+ def _make_root(self):
30
+ """Create hidden Tk root without any custom icon."""
31
+ root = tk.Tk()
32
+ root.withdraw()
33
+ return root
34
+
35
+ # ======================================================================
36
+ # SAFE RESIZE HANDLER
37
+ # ======================================================================
38
+ def _resize_any(self, img, size):
39
+ """Resize PIL image safely and return Tk PhotoImage."""
40
+ if size is None:
41
+ # If already a PhotoImage, keep as is
42
+ if isinstance(img, Image.Image):
43
+ return ImageTk.PhotoImage(img)
44
+ return img
45
+
46
+ if isinstance(img, Image.Image):
47
+ pil = img.resize(size, Image.Resampling.LANCZOS)
48
+ return ImageTk.PhotoImage(pil)
49
+
50
+ print("[WARN] Unknown image type, cannot resize.")
51
+ return img
52
+
53
+ # ======================================================================
54
+ # IMAGE OPENING WITH RETRY + FALLBACK + RESIZE
55
+ # ======================================================================
56
+ def open_img(
57
+ self,
58
+ start_in=None,
59
+ retry=False,
60
+ fallback_size=(64, 64),
61
+ fallback_color=(255, 0, 255),
62
+ resize=None,
63
+ return_pil=False
64
+ ):
65
+ """
66
+ Open an image using a dialog.
67
+
68
+ Params:
69
+ retry=True → reopen dialog until image selected
70
+ fallback_size → fallback square size when cancelled
71
+ fallback_color → fallback color
72
+ resize=(w, h) → resize final image
73
+
74
+ Returns dict:
75
+ - Always returns `image` as a Tk-compatible image (ImageTk.PhotoImage or PhotoImage)
76
+ - If `return_pil=True` and Pillow is available, also returns `pil` with the PIL Image
77
+ { "path": str|None, "image": PhotoImage, "pil": PIL.Image.Image|None, "cancelled": bool }
78
+ """
79
+
80
+ while True:
81
+ root = self._make_root()
82
+ folder = start_in if start_in else self.last_dir
83
+
84
+ path = filedialog.askopenfilename(
85
+ title="Select image",
86
+ initialdir=folder,
87
+ filetypes=[
88
+ ("Image files", "*.png;*.jpg;*.jpeg;*.gif;*.bmp"),
89
+ ("All files", "*.*")
90
+ ]
91
+ )
92
+ root.destroy()
93
+
94
+ # ------------------------ CANCELLED ------------------------
95
+ if not path:
96
+ if retry:
97
+ print("⚠️ No image selected. Trying again...")
98
+ continue
99
+
100
+ print("⚠️ No image selected. Using fallback.")
101
+ # Create a PIL fallback if Pillow available, then make a Tk image
102
+ if Image is not None:
103
+ w, h = fallback_size if fallback_size else (64, 64)
104
+ pil_fb = Image.new("RGB", (w, h), fallback_color)
105
+ if resize:
106
+ pil_fb = pil_fb.resize(resize, Image.Resampling.LANCZOS)
107
+ tk_fb = ImageTk.PhotoImage(pil_fb)
108
+ if return_pil:
109
+ return {"path": None, "image": tk_fb, "pil": pil_fb, "cancelled": True}
110
+ return {"path": None, "image": tk_fb, "pil": None, "cancelled": True}
111
+
112
+ # Fallback to existing asset loader (returns PhotoImage)
113
+ fb = load_image(None, size=fallback_size, color=fallback_color)
114
+ if resize:
115
+ fb = self._resize_any(fb, resize)
116
+ return {"path": None, "image": fb, "pil": None, "cancelled": True}
117
+
118
+ # ------------------------ LOAD IMAGE -----------------------
119
+ self.last_dir = os.path.dirname(path)
120
+
121
+ try:
122
+ # If Pillow is available, open with PIL and create a Tk PhotoImage for compatibility
123
+ if Image is not None:
124
+ pil_img = Image.open(path).convert("RGBA")
125
+ if resize:
126
+ pil_img = pil_img.resize(resize, Image.Resampling.LANCZOS)
127
+ tk_img = ImageTk.PhotoImage(pil_img)
128
+ if return_pil:
129
+ return {"path": path, "image": tk_img, "pil": pil_img, "cancelled": False}
130
+ return {"path": path, "image": tk_img, "pil": None, "cancelled": False}
131
+
132
+ # Otherwise fall back to the asset loader which returns a Tk image
133
+ img = load_image(path)
134
+ if resize:
135
+ img = self._resize_any(img, resize)
136
+ return {"path": path, "image": img, "pil": None, "cancelled": False}
137
+
138
+ except Exception as e:
139
+ print(f"[ERROR] Failed to load image '{path}': {e}")
140
+
141
+ if retry:
142
+ print("Trying again...")
143
+ continue
144
+
145
+ # On error, provide a fallback (PIL if available)
146
+ if Image is not None:
147
+ w, h = fallback_size if fallback_size else (64, 64)
148
+ pil_fb = Image.new("RGB", (w, h), fallback_color)
149
+ if resize:
150
+ pil_fb = pil_fb.resize(resize, Image.Resampling.LANCZOS)
151
+ tk_fb = ImageTk.PhotoImage(pil_fb)
152
+ if return_pil:
153
+ return {"path": None, "image": tk_fb, "pil": pil_fb, "cancelled": True}
154
+ return {"path": None, "image": tk_fb, "pil": None, "cancelled": True}
155
+
156
+ fb = load_image(None, size=fallback_size, color=fallback_color)
157
+ if resize:
158
+ fb = self._resize_any(fb, resize)
159
+ return {"path": None, "image": fb, "pil": None, "cancelled": True}
160
+
161
+ # ======================================================================
162
+ # FILE DIALOGS
163
+ # ======================================================================
164
+ def ask_save_file(self, default_name="save.json",
165
+ filetypes=[("JSON files", "*.json"), ("All files", "*.*")]):
166
+ root = self._make_root()
167
+
168
+ path = filedialog.asksaveasfilename(
169
+ title="Save As",
170
+ initialdir=self.default_save_folder,
171
+ initialfile=default_name,
172
+ filetypes=filetypes,
173
+ defaultextension=filetypes[0][1]
174
+ )
175
+ root.destroy()
176
+ return path if path else None
177
+
178
+ def ask_open_file(self, filetypes=[("JSON files", "*.json"), ("All files", "*.*")]):
179
+ root = self._make_root()
180
+
181
+ path = filedialog.askopenfilename(
182
+ title="Open File",
183
+ initialdir=self.default_save_folder,
184
+ filetypes=filetypes
185
+ )
186
+ root.destroy()
187
+ return path if path else None
188
+
189
+ # ======================================================================
190
+ # PATH HANDLING
191
+ # ======================================================================
192
+ def _resolve_path(self, filename):
193
+ if not filename:
194
+ return None
195
+ if os.path.isabs(filename):
196
+ return filename
197
+ return os.path.join(self.default_save_folder, filename)
198
+
199
+ # ======================================================================
200
+ # TEXT FILES
201
+ # ======================================================================
202
+ def save_text(self, filename, content):
203
+ path = self._resolve_path(filename)
204
+ if not path:
205
+ print("[CANCELLED] No save path provided.")
206
+ return None
207
+ os.makedirs(os.path.dirname(path), exist_ok=True)
208
+ with open(path, "w", encoding="utf-8") as f:
209
+ f.write(content)
210
+ print(f"[INFO] Text saved to: {path}")
211
+ return path
212
+
213
+ def load_text(self, filename):
214
+ path = self._resolve_path(filename)
215
+ if path and os.path.exists(path):
216
+ with open(path, "r", encoding="utf-8") as f:
217
+ return f.read()
218
+ print(f"[WARN] Text file not found: {path}")
219
+ return None
220
+
221
+ # ======================================================================
222
+ # JSON FILES
223
+ # ======================================================================
224
+ def save_json(self, filename, data):
225
+ path = self._resolve_path(filename)
226
+ if not path:
227
+ print("[CANCELLED] No save path provided.")
228
+ return None
229
+ os.makedirs(os.path.dirname(path), exist_ok=True)
230
+ with open(path, "w", encoding="utf-8") as f:
231
+ json.dump(data, f, indent=4)
232
+ print(f"[INFO] JSON saved to: {path}")
233
+ return path
234
+
235
+ def load_json(self, filename):
236
+ path = self._resolve_path(filename)
237
+ if path and os.path.exists(path):
238
+ with open(path, "r", encoding="utf-8") as f:
239
+ return json.load(f)
240
+ print(f"[WARN] JSON file not found: {path}")
241
+ return None
242
+
243
+ # ======================================================================
244
+ # PICKLE FILES
245
+ # ======================================================================
246
+ def save_pickle(self, filename, obj):
247
+ path = self._resolve_path(filename)
248
+ if not path:
249
+ print("[CANCELLED] No save path provided.")
250
+ return None
251
+ os.makedirs(os.path.dirname(path), exist_ok=True)
252
+ with open(path, "wb") as f:
253
+ pickle.dump(obj, f)
254
+ print(f"[INFO] Pickle saved to: {path}")
255
+ return path
256
+
257
+ def load_pickle(self, filename):
258
+ path = self._resolve_path(filename)
259
+ if path and os.path.exists(path):
260
+ with open(path, "rb") as f:
261
+ return pickle.load(f)
262
+ print(f"[WARN] Pickle file not found: {path}")
263
+ return None
@@ -4,9 +4,9 @@ check_for_update("crystalwindow")
4
4
 
5
5
  # === Core Systems ===
6
6
  from .window import Window
7
- from .sprites import Sprite
7
+ from .sprites import Sprite, CollisionHandler
8
8
  from .tilemap import TileMap
9
- from .player import Player
9
+ from .objects import Player, Block, Enemy
10
10
  from .gravity import Gravity
11
11
  from .FileHelper import FileHelper
12
12
  from .math import Mathematics
@@ -22,6 +22,8 @@ from .assets import (
22
22
  flip_vertical,
23
23
  LoopAnim,
24
24
  loop_image,
25
+ load_file,
26
+ Sound,
25
27
  )
26
28
  from .animation import Animation
27
29
 
@@ -33,8 +35,7 @@ from .gui import Button, Label, GUIManager, hex_to_rgb, Fade
33
35
  from .gui_ext import Toggle, Slider
34
36
 
35
37
  # === Time System ===
36
- # Includes upgraded Clock + all helper utilities
37
- from .clock import Clock, Stopwatch, CountdownTimer, Scheduler
38
+ from .clock import Clock, CountdownTimer
38
39
 
39
40
  # === Drawing Helpers ===
40
41
  from .draw_helpers import gradient_rect, CameraShake
@@ -43,23 +44,18 @@ from .draw_text_helper import DrawTextManager
43
44
  from .draw_tool import CrystalDraw
44
45
 
45
46
  # === Misc Helpers ===
46
- from .fun_helpers import random_name, DebugOverlay, random_color, random_palette, lerp
47
+ from .fun_helpers import random_name, DebugOverlay, random_color, random_palette, lerp, random_number
47
48
  from .camera import Camera
48
49
  from .color_handler import Colors, Color
49
- from .websearch import WebSearchResult, WebSearch
50
+ from .websearch import SearchResult, WebBrowse
50
51
 
51
52
  # === 3D Engine ===
52
- from .crystal3d import CW3D
53
+ from .crystal3d import CW3DShape, CW3D
53
54
 
54
- # === AI Engine ===
55
- from .ai import AI
56
-
57
- # === Server Manager ===
58
- from .cw_client import CWClient
59
55
 
60
56
  __all__ = [
61
57
  # --- Core ---
62
- "Window", "Sprite", "TileMap", "Player", "Gravity", "FileHelper", "Mathematics",
58
+ "Window", "Sprite", "TileMap", "Player", "Block", "Enemy", "Gravity", "FileHelper", "Mathematics",
63
59
 
64
60
  # --- Assets & Animation ---
65
61
  "load_image",
@@ -72,9 +68,11 @@ __all__ = [
72
68
  "Animation",
73
69
  "LoopAnim",
74
70
  "loop_image",
71
+ "load_file",
72
+ "Sound",
75
73
 
76
74
  # --- Collision ---
77
- "check_collision", "resolve_collision",
75
+ "check_collision", "resolve_collision", "CollisionHandler",
78
76
 
79
77
  # --- GUI ---
80
78
  "Button", "Label", "GUIManager", "random_color", "hex_to_rgb", "Fade",
@@ -83,25 +81,16 @@ __all__ = [
83
81
  "Toggle", "Slider",
84
82
 
85
83
  # --- Time System ---
86
- # FULL time system is now exposed
87
- "Clock",
88
- "Stopwatch",
89
- "CountdownTimer",
90
- "Scheduler",
84
+ "Clock", "CountdownTimer",
91
85
 
92
86
  # --- Drawing ---
93
87
  "gradient_rect", "CameraShake", "DrawHelper", "DrawTextManager", "CrystalDraw",
94
88
 
95
89
  # --- Misc ---
96
90
  "random_name", "DebugOverlay", "Camera", "Colors", "Color",
97
- "random_palette", "lerp", "WebSearchResult", "WebSearch",
91
+ "random_palette", "lerp", "SearchResult", "WebBrowse", "random_number",
98
92
 
99
93
  # --- 3D ---
100
- "CW3D",
101
-
102
- # --- AI ---
103
- "AI",
94
+ "CW3DShape", "CW3D",
104
95
 
105
- # --- Server Client ---
106
- "CWClient",
107
- ]
96
+ ]