crystalwindow 4.7__py3-none-any.whl → 4.9__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
@@ -52,6 +52,11 @@ from .websearch import SearchResult, WebBrowse
52
52
  # === 3D Engine ===
53
53
  from .crystal3d import CW3DShape, CW3D
54
54
 
55
+ # === Chatting/VPN Engine =====
56
+ from .chatvpn import ChatVPN, ChatVPNServer
57
+
58
+ # ==== Message Bus ====
59
+ from .messagebus import send_message, view_message, clear_messages
55
60
 
56
61
  __all__ = [
57
62
  # --- Core ---
@@ -93,4 +98,9 @@ __all__ = [
93
98
  # --- 3D ---
94
99
  "CW3DShape", "CW3D",
95
100
 
101
+ # --- ChatVPN ---
102
+ "ChatVPN", "ChatVPNServer",
103
+
104
+ # --- Message Bus ---
105
+ "send_message", "view_message", "clear_messages",
96
106
  ]
@@ -0,0 +1,82 @@
1
+ import socket
2
+ import threading
3
+ import json
4
+
5
+
6
+ # ====================================================
7
+ # ChatVPN SERVER (built into this file)
8
+ # ====================================================
9
+ class ChatVPNServer:
10
+ def __init__(self, host="0.0.0.0", port=9001):
11
+ self.host = host
12
+ self.port = port
13
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
14
+ self.sock.bind((self.host, self.port))
15
+ self.clients = set()
16
+ self.running = False
17
+
18
+ def start(self):
19
+ if self.running:
20
+ return
21
+ self.running = True
22
+ print(f"[ChatVPN-Server] running on {self.host}:{self.port}")
23
+ threading.Thread(target=self._loop, daemon=True).start()
24
+
25
+ def _loop(self):
26
+ while self.running:
27
+ data, addr = self.sock.recvfrom(4096)
28
+
29
+ if addr not in self.clients:
30
+ self.clients.add(addr)
31
+ print(f"[ChatVPN-Server] new client: {addr}")
32
+
33
+ for c in self.clients:
34
+ if c != addr:
35
+ self.sock.sendto(data, c)
36
+
37
+ def stop(self):
38
+ self.running = False
39
+ self.sock.close()
40
+ print("[ChatVPN-Server] stopped.")
41
+
42
+
43
+ # ====================================================
44
+ # ChatVPN CLIENT
45
+ # ====================================================
46
+ class ChatVPN:
47
+ def __init__(self, server_ip: str, port: int = 9001):
48
+ self.server = (server_ip, port)
49
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
50
+ self.running = False
51
+ self._on_msg = None
52
+
53
+ def start(self):
54
+ if self.running:
55
+ return
56
+ self.running = True
57
+ threading.Thread(target=self._recv_loop, daemon=True).start()
58
+ print(f"[ChatVPN-Client] connected to {self.server}")
59
+
60
+ def send(self, text: str):
61
+ packet = json.dumps({"type": "text", "data": text}).encode()
62
+ self.sock.sendto(packet, self.server)
63
+
64
+ def on_msg(self, func):
65
+ self._on_msg = func
66
+
67
+ def _recv_loop(self):
68
+ while self.running:
69
+ try:
70
+ data, _ = self.sock.recvfrom(4096)
71
+ except OSError:
72
+ break
73
+
74
+ try:
75
+ obj = json.loads(data.decode())
76
+ msg = obj.get("data", "")
77
+ except:
78
+ msg = data.decode()
79
+
80
+ if self._on_msg:
81
+ self._on_msg(msg)
82
+
crystalwindow/clock.py CHANGED
@@ -45,6 +45,7 @@ class Clock:
45
45
 
46
46
  # FPS
47
47
  self.target_fps = target_fps
48
+ self.timer = CountdownTimer()
48
49
  self.min_frame_time = 1 / target_fps if target_fps else 0
49
50
  self.frame_times = deque(maxlen=smooth_fps)
50
51
 
@@ -145,3 +146,13 @@ class Clock:
145
146
  def timestamp(self):
146
147
  """High-precision monotonic timestamp."""
147
148
  return time.perf_counter()
149
+
150
+ #TIMER
151
+ def start_timer(self, seconds: float):
152
+ self.timer.start(seconds)
153
+
154
+ def timer_ended(self):
155
+ return self.timer.is_finished()
156
+
157
+ def timer_remaining(self):
158
+ return self.timer.get_remaining()
crystalwindow/gui.py CHANGED
@@ -45,7 +45,7 @@ class Button:
45
45
  # ======================================
46
46
  def update(self, win):
47
47
  mx, my = win.mouse_pos
48
- x, y, w, h = self.rect
48
+ x, y, w, h = self.rect
49
49
 
50
50
  # Reset transient states
51
51
  self._clicked = False
@@ -0,0 +1,33 @@
1
+ # crystalwindow/messagebus.py
2
+
3
+ class MessageBus:
4
+ def __init__(self):
5
+ self._queue = []
6
+
7
+ def send(self, name: str, data=None):
8
+ self._queue.append({
9
+ "name": name,
10
+ "data": data
11
+ })
12
+
13
+ def poll(self, name: str):
14
+ for msg in self._queue:
15
+ if msg["name"] == name:
16
+ self._queue.remove(msg)
17
+ return msg["data"]
18
+ return None
19
+
20
+ def clear(self):
21
+ self._queue.clear()
22
+
23
+
24
+ _bus = MessageBus()
25
+
26
+ def send_message(name: str, data=None):
27
+ _bus.send(name, data)
28
+
29
+ def view_message(name: str):
30
+ return _bus.poll(name)
31
+
32
+ def clear_messages():
33
+ _bus.clear()
crystalwindow/tilemap.py CHANGED
@@ -1,13 +1,103 @@
1
1
  from .sprites import Sprite
2
2
 
3
3
  class TileMap:
4
- def __init__(self, tile_size):
4
+ def __init__(self, tile_size=32):
5
5
  self.tile_size = tile_size
6
- self.tiles = []
6
+ self.tiles = [] # list of Sprite
7
7
 
8
8
  def add_tile(self, image, x, y):
9
- self.tiles.append(Sprite.image(image, x, y))
9
+ """Add a tile snapped to grid."""
10
+ gx = x // self.tile_size * self.tile_size
11
+ gy = y // self.tile_size * self.tile_size
12
+ tile = Sprite((gx, gy), (self.tile_size, self.tile_size), image=image)
13
+ self.tiles.append(tile)
14
+ return tile
15
+
16
+ def remove_tile_at(self, x, y):
17
+ """Remove a tile that sits on this grid cell."""
18
+ gx = x // self.tile_size * self.tile_size
19
+ gy = y // self.tile_size * self.tile_size
20
+ for t in self.tiles:
21
+ if t.pos[0] == gx and t.pos[1] == gy:
22
+ self.tiles.remove(t)
23
+ return True
24
+ return False
25
+
26
+ def get_tile_at(self, x, y):
27
+ """Return tile located at the grid coords."""
28
+ gx = x // self.tile_size * self.tile_size
29
+ gy = y // self.tile_size * self.tile_size
30
+ for t in self.tiles:
31
+ if t.pos[0] == gx and t.pos[1] == gy:
32
+ return t
33
+ return None
34
+
35
+ def to_data(self):
36
+ """Convert to serializable list for saving."""
37
+ return [
38
+ {
39
+ "x": t.pos[0],
40
+ "y": t.pos[1],
41
+ "image_id": t.image_id if hasattr(t, "image_id") else None
42
+ }
43
+ for t in self.tiles
44
+ ]
45
+
46
+ def load_data(self, data, image_loader):
47
+ """
48
+ Load tiles from list.
49
+ image_loader(id) → returns the image object used by Sprite.
50
+ """
51
+ self.tiles = []
52
+ for d in data:
53
+ img = image_loader(d["image_id"])
54
+ tile = Sprite((d["x"], d["y"]),
55
+ (self.tile_size, self.tile_size),
56
+ image=img)
57
+ if img is not None:
58
+ tile.image_id = d["image_id"]
59
+ self.tiles.append(tile)
10
60
 
11
61
  def draw(self, win):
62
+ """Draw all tiles."""
12
63
  for t in self.tiles:
13
64
  win.draw_sprite(t)
65
+ class Grid:
66
+ def __init__(self, win, cell_size=(16, 16)):
67
+ self.win = win
68
+ self.cell_w, self.cell_h = cell_size
69
+ self.update_size()
70
+
71
+ def update_size(self):
72
+ self.w, self.h = self.win.size
73
+
74
+ self.cols = self.w // self.cell_w
75
+ self.rows = self.h // self.cell_h
76
+ self.cells = [(cx, cy) for cy in range(self.rows) for cx in range(self.cols)]
77
+
78
+ # MAKES GRID WORK LIKE gameg(x, y)
79
+ def __call__(self, x, y):
80
+ """Return cell index for given pixel pos."""
81
+ return x // self.cell_w, y // self.cell_h
82
+
83
+ def snap(self, x, y):
84
+ gx = x // self.cell_w * self.cell_w
85
+ gy = y // self.cell_h * self.cell_h
86
+ return gx, gy
87
+
88
+ def get_cell(self, x, y):
89
+ return x // self.cell_w, y // self.cell_h
90
+
91
+ def cell_to_px(self, cx, cy):
92
+ return cx * self.cell_w, cy * self.cell_h
93
+
94
+ def draw(self, color=(200, 200, 200)):
95
+ self.update_size()
96
+
97
+ # vertical
98
+ for x in range(0, self.w, self.cell_w):
99
+ self.win.draw_line((x, 0), (x, self.h), color)
100
+
101
+ # horizontal
102
+ for y in range(0, self.h, self.cell_h):
103
+ self.win.draw_line((0, y), (self.w, y), color)
@@ -10,6 +10,7 @@ from dataclasses import dataclass
10
10
  from typing import List, Tuple, Optional, Any
11
11
 
12
12
 
13
+
13
14
  # ================================
14
15
  # Dataclass: Unified Search Result
15
16
  # ================================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crystalwindow
3
- Version: 4.7
3
+ Version: 4.9
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
@@ -1,10 +1,11 @@
1
1
  crystalwindow/FileHelper.py,sha256=U20iwND4jX1y91TOK46e8MPH8xyw7GOrZ697nPEnOPk,10706
2
- crystalwindow/__init__.py,sha256=GQxj4yLpnp53i3rc7X_DY_KbYTQFr1Op8qX4-_R_RrA,2510
2
+ crystalwindow/__init__.py,sha256=3YBPnMJuc-jatE__Ts-cs5s2J1OWeDE7HzgCv95ykdA,2823
3
3
  crystalwindow/ai.py,sha256=YIt6dNe1QljSAlNECCVa3DMUSIqQEJRIAAbQpYqFNNo,11525
4
4
  crystalwindow/animation.py,sha256=zHjrdBXQeyNaLAuaGPldJueX05OZ5j31YR8NizmR0uQ,427
5
5
  crystalwindow/assets.py,sha256=8MxPSk7W5YcBnKDh6KcLdg34uxmACf_m6feSYFCWHqA,11405
6
6
  crystalwindow/camera.py,sha256=tbn4X-jxMIszAUg3Iu-89gJN5nij0mjPMEzGotcLbJI,712
7
- crystalwindow/clock.py,sha256=JjpLOWaZlVtLd1KfvaMn5Gx5iOqyuy6oLnHaM22axKY,4827
7
+ crystalwindow/chatvpn.py,sha256=Ij3wRNrMbPINO-SX9vx8xlrKRLvG7zJgzAN2T0jzSz8,2477
8
+ crystalwindow/clock.py,sha256=LZUm4WoAnJuGA-efRKkLHRE9cxCs3pRhwcZZF14fIKA,5109
8
9
  crystalwindow/collision.py,sha256=hpkHTp_KparghVK-itp_rxuYdd2GbQMxICHlUBv0rSw,472
9
10
  crystalwindow/color_handler.py,sha256=K3LipCPOjYt1NemeT-hNWf886LL59QgRN8ifHOi7-0M,3255
10
11
  crystalwindow/crystal3d.py,sha256=8n42S71NZWgBgYwP8ZWfobXFeWvNrhJY80YGK-PzI8s,5375
@@ -14,14 +15,15 @@ crystalwindow/draw_text_helper.py,sha256=qv5fFCuTCKWeGDk9Z_ZpOzrTFP8YYwlgQrrorwr
14
15
  crystalwindow/draw_tool.py,sha256=1YYEqjmgt4HpV3S15sTjCSmcqgHup4fD8gskTkxU0t4,1638
15
16
  crystalwindow/fun_helpers.py,sha256=x-OF5dlMlHgvXjtT7Om8RvzKWgizSwnzeaM0_W3-SKQ,870
16
17
  crystalwindow/gravity.py,sha256=pZJykZzO-mKVBPsZRP55nnlvUoYQfR29wPgJcI4IbBs,2904
17
- crystalwindow/gui.py,sha256=Ipu3BKA6euwQJ75oq7L9V7jbbZHGawwTQjv-KEH_owE,5286
18
+ crystalwindow/gui.py,sha256=_T4diMardg50gk0_OBpFHfJo5Coo-D3aZt3Vl6PJjxQ,5287
18
19
  crystalwindow/gui_ext.py,sha256=JctpNPr7gtGdro3csyUo9ft3FFArj3JhkVlgKF0lyME,3407
19
20
  crystalwindow/math.py,sha256=slOY3KQZ99VDMUMxsSJabMyRtJcwVzEyxR2RoXspHho,963
21
+ crystalwindow/messagebus.py,sha256=9K2P_TkdQ1rt-oouIkRg_XHwMTwykttBt-9gFYaItyI,696
20
22
  crystalwindow/objects.py,sha256=VCEvRrzPv-bWCiVw63rMF67KYluP6FKySgDOvOiN8QU,5413
21
23
  crystalwindow/sprites.py,sha256=IADCQetFDQoat3qGpKkH93TdtqqgldfHl4N0HKX1Ajc,7480
22
- crystalwindow/tilemap.py,sha256=J6u3K3n-tEFyAqVc6eBGxnG0qVeGQeE0aMc-WLapydQ,328
24
+ crystalwindow/tilemap.py,sha256=endJ8KcbP9EjPvL9qWsOpV4jc_Re1yH080aUyDkwufA,3378
23
25
  crystalwindow/ver_warner.py,sha256=qEN3ulc1NixBy15FFx2R3Zu0DhyJTVJwiESGAPwpynM,3373
24
- crystalwindow/websearch.py,sha256=ZaG4rO2TRxJVv1QRYv8vcSKx1fCf5OqqhEGNns99-KU,5159
26
+ crystalwindow/websearch.py,sha256=IgsoKt27yCBHeq8yFVfSq_8sEj5KP6mqn2yNRTsRw1A,5161
25
27
  crystalwindow/window.py,sha256=qfz0e8dhLH0ZfoqjswFu20NJqh3Ln6rhaZ3v626Uewk,31849
26
28
  crystalwindow/Icons/default_icon.png,sha256=Loq27Pxb8Wb3Sz-XwtNF1RmlLNxR4TcfOWfK-1lWcII,7724
27
29
  crystalwindow/Icons/file_icons.png,sha256=kqjvz3gMaIbepW4XGrLZOjDYu-yhFbVxjvylS-0RO4U,5659
@@ -36,8 +38,8 @@ crystalwindow/gametests/sandbox.py,sha256=Oo2tU2N0y3BPVa6T5vs_h9N6islhQrjSrr_78X
36
38
  crystalwindow/gametests/squaremove.py,sha256=ei6DMnvcgpOhmxbGv-Yqmx5EqiZjKbVlZhI7YbT2hY8,643
37
39
  crystalwindow/gametests/testtttagain.py,sha256=oIhK9MGgMVly_W2lRwD9Hn9WyPdd8JnX2HGrLTGZdxY,373
38
40
  crystalwindow/gametests/windowtesting.py,sha256=_9X6wnV1-_X_PtNS-0zu-k209NtFIwAc4vpxLPp7V2o,97
39
- crystalwindow-4.7.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
40
- crystalwindow-4.7.dist-info/METADATA,sha256=T0kgPlByhRHl1pND0oNPapnesZKSvu9B4Urvb4tkEvo,7523
41
- crystalwindow-4.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
- crystalwindow-4.7.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
43
- crystalwindow-4.7.dist-info/RECORD,,
41
+ crystalwindow-4.9.dist-info/licenses/LICENSE,sha256=Gt5cJRchdNt0guxyQMHKsATN5PM5mjuDhdO6Gzs9qQc,1096
42
+ crystalwindow-4.9.dist-info/METADATA,sha256=9CY3r5w-s8NAWe5ynIBOWOehMyRDro-zXnhhPw1yL2Q,7523
43
+ crystalwindow-4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
+ crystalwindow-4.9.dist-info/top_level.txt,sha256=PeQSld4b19XWT-zvbYkvE2Xg8sakIMbDzSzSdOSRN8o,14
45
+ crystalwindow-4.9.dist-info/RECORD,,