PlayPy 0.4.0__tar.gz → 0.5.0.dev202606202327__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.
- playpy-0.5.0.dev202606202327/PKG-INFO +715 -0
- playpy-0.5.0.dev202606202327/README.md +703 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/pyproject.toml +1 -1
- playpy-0.5.0.dev202606202327/src/PlayPy.egg-info/PKG-INFO +715 -0
- playpy-0.5.0.dev202606202327/src/PlayPy.egg-info/SOURCES.txt +32 -0
- playpy-0.5.0.dev202606202327/src/playpy/__init__.py +816 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/builtin/__init__.py +25 -8
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/builtin/effects.py +28 -23
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/builtin/elements.py +94 -70
- playpy-0.5.0.dev202606202327/src/playpy/builtin/events.py +283 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/core/__init__.py +7 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/core/elements.py +40 -37
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/core/resources.py +15 -14
- playpy-0.5.0.dev202606202327/src/playpy/core/state/__init__.py +36 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/state/asset.py +230 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/state/input.py +395 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/state/rect.py +399 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/state/tween.py +214 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/__init__.py +6 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/display.py +220 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/element_hierarchy.py +153 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/element_input.py +134 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/input.py +300 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/rendering.py +56 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/scenes.py +156 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/tween.py +61 -0
- playpy-0.5.0.dev202606202327/src/playpy/core/workspace/workspace.py +286 -0
- playpy-0.4.0/PKG-INFO +0 -530
- playpy-0.4.0/README.md +0 -518
- playpy-0.4.0/src/PlayPy.egg-info/PKG-INFO +0 -530
- playpy-0.4.0/src/PlayPy.egg-info/SOURCES.txt +0 -20
- playpy-0.4.0/src/playpy/__init__.py +0 -607
- playpy-0.4.0/src/playpy/builtin/events.py +0 -153
- playpy-0.4.0/src/playpy/core/state.py +0 -931
- playpy-0.4.0/src/playpy/core/workspace.py +0 -624
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/LICENSE.txt +0 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/setup.cfg +0 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/PlayPy.egg-info/dependency_links.txt +0 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/PlayPy.egg-info/requires.txt +0 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/PlayPy.egg-info/top_level.txt +0 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/builtin/components.py +0 -0
- {playpy-0.4.0 → playpy-0.5.0.dev202606202327}/src/playpy/data/default_icon.ppm +0 -0
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PlayPy
|
|
3
|
+
Version: 0.5.0.dev202606202327
|
|
4
|
+
Summary: PlayPy is a lightweight Python library for creating games, tools, and interactive applications using a retained-mode UI and scene system built on top of pygame. It focuses on rapid prototyping, composable rendering, and simple but powerful layout primitives.
|
|
5
|
+
Author-email: angel <angyv2861@gmail.com>
|
|
6
|
+
Requires-Python: >=3.14
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE.txt
|
|
9
|
+
Requires-Dist: pygame-ce>=2.5.6
|
|
10
|
+
Requires-Dist: colorama>=0.4.6
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# PlayPy (0.5.0.dev202606202327)
|
|
14
|
+
|
|
15
|
+
PlayPy is a lightweight Python library for creating games, tools, and interactive applications using a retained-mode UI and scene system built on top of pygame. It focuses on rapid prototyping, composable rendering, and simple but powerful layout primitives.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Python `>=3.11`
|
|
20
|
+
- `pygame(-ce) >=2.6.1`
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install playpy
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If that does not work:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m pip install playpy
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# Core Concepts
|
|
37
|
+
|
|
38
|
+
## Module State
|
|
39
|
+
|
|
40
|
+
Use the following methods to control the state of the module:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
plp.init()
|
|
44
|
+
plp.quit()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Workspace
|
|
50
|
+
|
|
51
|
+
`Workspace` owns:
|
|
52
|
+
- the window
|
|
53
|
+
- render loop
|
|
54
|
+
- input state
|
|
55
|
+
- scene stack
|
|
56
|
+
- coroutine scheduler
|
|
57
|
+
|
|
58
|
+
Key methods:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
ws.run()
|
|
62
|
+
ws.quit() # keep in mind that this method does not call plp.quit()
|
|
63
|
+
ws.wait(seconds)
|
|
64
|
+
|
|
65
|
+
ws.queue_scene_change(scene)
|
|
66
|
+
ws.queue_scene_push(scene)
|
|
67
|
+
ws.queue_scene_pop(scene=None)
|
|
68
|
+
|
|
69
|
+
ws.step()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Scene Scope
|
|
73
|
+
|
|
74
|
+
Temporarily push a scene using a context manager:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
with ws.scene_scope(scene) as (scn, handle):
|
|
78
|
+
...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Call:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
handle.disconnect()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
to remotely pop the scoped scene.
|
|
88
|
+
|
|
89
|
+
The scoped scene will automatically be disconnected if not disconnected manually.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### Screen State
|
|
94
|
+
Use `ws.resizable`, `ws.maximized`, and `ws.fullscreen` to check and change current state.
|
|
95
|
+
The screen must be resizable to be maximized or fullscreen, and cannot be maximized and fullscreen at the same time.
|
|
96
|
+
Use `ws.resized`, `ws.maxed`, and `ws.restored` to check status on current frame.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Layout Values
|
|
101
|
+
|
|
102
|
+
PlayPy uses two rectangle value types:
|
|
103
|
+
|
|
104
|
+
### `FRect`:
|
|
105
|
+
Relative scale values.
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
plp.FRect(x, y, w, h)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `Rect`:
|
|
112
|
+
Absolute pixel offsets.
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
plp.Rect(x, y, w, h)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
Final element rectangle:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
(scale * parent_size) + offset
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Helpers:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
plp.empty_rect() -> Rect(0, 0, 0, 0)
|
|
130
|
+
plp.empty_frect() -> FRect(0, 0, 0, 0)
|
|
131
|
+
plp.full_screen_rect() -> (FRect(0, 0, 1, 1), Rect(0, 0, 0, 0))
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Rect types are iterable and support multiple constructor overloads.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Assets
|
|
139
|
+
|
|
140
|
+
Assets are reusable wrappers around external files such as images, animations, and sounds.
|
|
141
|
+
|
|
142
|
+
PlayPy assets load lazily: they store the path when created, then load the underlying pygame resource when needed. You can also call `load()` ahead of time to preload an asset and reduce latency during gameplay.
|
|
143
|
+
|
|
144
|
+
### Sprites and Animations
|
|
145
|
+
|
|
146
|
+
`Sprite`s load and store images. Initialize them by passing in a path. (`Path` or `str` object)
|
|
147
|
+
|
|
148
|
+
`Animation`s store multiple `Sprite`s and allow for changing of animation settings (FPS, loop, etc.)
|
|
149
|
+
Pass in either sprite paths (`Path` or `str` object), or `Sprite`s themselves.
|
|
150
|
+
|
|
151
|
+
### Sounds
|
|
152
|
+
|
|
153
|
+
`Sound`s load and store user-imported sounds from sound files. Initialize them by passing in a path. (`Path` or `str` object)
|
|
154
|
+
|
|
155
|
+
Useful methods:
|
|
156
|
+
```python
|
|
157
|
+
sound = plp.Sound("my_awesome_sound.wav")
|
|
158
|
+
|
|
159
|
+
sound.load()
|
|
160
|
+
sound.play(loop_amt=3, maxtime=10, fade_ms=500)
|
|
161
|
+
sound.stop()
|
|
162
|
+
sound.set_volume(.5)
|
|
163
|
+
volume = sound.get_volume()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Tweening
|
|
167
|
+
|
|
168
|
+
`Tween`ing is a way to smoothly change values. (like element positions/colors)
|
|
169
|
+
|
|
170
|
+
`Tween` constructor:
|
|
171
|
+
```python
|
|
172
|
+
tween = plp.Tween(
|
|
173
|
+
tweened: list[TweenedValue],
|
|
174
|
+
target: list[Any],
|
|
175
|
+
easing_function: TweenEasingFunction | Callable[[float], float] = "cubic",
|
|
176
|
+
easing_style: TweenEasingStyle | None = None,
|
|
177
|
+
length: float = 1,
|
|
178
|
+
looped: bool = False,
|
|
179
|
+
clear_on_finish: bool = True,
|
|
180
|
+
)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Useful methods/properties include...
|
|
184
|
+
```python
|
|
185
|
+
tween.looped # whether or not the tween loops
|
|
186
|
+
tween.length # the length of the tween
|
|
187
|
+
tween.elapsed # the current elapsed time in the tween
|
|
188
|
+
tween.finished # whether or not the tween has finished (always false on looped tweens)
|
|
189
|
+
|
|
190
|
+
tween.edit_easing(function, style) # changes the easing function and style of the tween
|
|
191
|
+
tween.play() # plays the tween at the current elapsed time
|
|
192
|
+
tween.pause() # stops the tween at the current elapsed time
|
|
193
|
+
tween.start() # plays the tween from the start, remapping the start points of the tween to the current values
|
|
194
|
+
tween.restart() # plays the tween from the start, reverting the current values of the tween to the start point
|
|
195
|
+
tween.stop() # instantly ends the tween; start() must be used to restart a stopped tween.
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Handling Tweened Values
|
|
199
|
+
|
|
200
|
+
`TweenedValue` handles all tweenable values.
|
|
201
|
+
```python
|
|
202
|
+
val = plp.TweenedValue(
|
|
203
|
+
base_object: object | None,
|
|
204
|
+
key: Any
|
|
205
|
+
)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`TweenedValue`s support:
|
|
209
|
+
- attributes of a class/instance: `TweenedValue(x, "y") = x.y`
|
|
210
|
+
- indices/keys of a `list`/`dict`: `TweenedValue(x, y) = x[y]`
|
|
211
|
+
- standalone values: `TweenedValue(None, x) = x`.
|
|
212
|
+
|
|
213
|
+
Useful methods/properties include...
|
|
214
|
+
```python
|
|
215
|
+
tweened_value.hierarchy_type # returns the hierarchy type (see above) of the TweenedValue ("standalone" / "attribute" / "key" / "index")
|
|
216
|
+
|
|
217
|
+
tweened_value.get() # gets the current value of the TweenedValue
|
|
218
|
+
tweened_value.set(value) # sets the current value of the TweenedValue
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Integration Into Workspace
|
|
222
|
+
|
|
223
|
+
For the tween to update each frame, you must attach it to the workspace.
|
|
224
|
+
|
|
225
|
+
Active tween helper methods/properties:
|
|
226
|
+
```python
|
|
227
|
+
ws.active_tweens # returns all active tweens (cannot be overwritten)
|
|
228
|
+
|
|
229
|
+
index = ws.add_tween(tween) # adds a new tween to the workspace and returns it
|
|
230
|
+
|
|
231
|
+
tween = ws.remove_tween(index) # removes a tween based on its index and returns it
|
|
232
|
+
tween = ws.remove_tween(tween) # removes a tween and returns it
|
|
233
|
+
|
|
234
|
+
tween = ws.get_tween(index) # gets a tween from its index
|
|
235
|
+
|
|
236
|
+
cleared_tweens = ws.clear_tweens() # clears all active tweens and returns them
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
# Parenting
|
|
242
|
+
|
|
243
|
+
Any `Element` can contain children.
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
child.parent = parent
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
or:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
parent.add_child(child)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Relationship helpers:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
is_parent_of()
|
|
259
|
+
is_child_of()
|
|
260
|
+
|
|
261
|
+
is_ancestor_of()
|
|
262
|
+
is_descendant_of()
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Properties:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
parent
|
|
269
|
+
children
|
|
270
|
+
ancestors
|
|
271
|
+
descendants
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
# Rendering System
|
|
277
|
+
|
|
278
|
+
PlayPy uses a compositing pipeline.
|
|
279
|
+
|
|
280
|
+
`Element.draw()` returns a `SurfaceHandler` instead of drawing directly to the workspace.
|
|
281
|
+
|
|
282
|
+
This enables:
|
|
283
|
+
- outlines for arbitrary shapes
|
|
284
|
+
- gradients inheriting shape alpha
|
|
285
|
+
- subtree compositing
|
|
286
|
+
- layered visual effects
|
|
287
|
+
- future post-processing support
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
# Elements
|
|
292
|
+
|
|
293
|
+
## Core Elements
|
|
294
|
+
|
|
295
|
+
- `Panel`
|
|
296
|
+
- `Text`
|
|
297
|
+
- `Button`
|
|
298
|
+
- `Textbox`
|
|
299
|
+
- `Tooltip`
|
|
300
|
+
- `Line`
|
|
301
|
+
- `Scene`
|
|
302
|
+
|
|
303
|
+
All elements have the following attributes:
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
Element(
|
|
307
|
+
scale: FRectValue, # position/size relative to the parent of the element
|
|
308
|
+
offset: RectValue, # absolute position/size of the element
|
|
309
|
+
visible: bool = True, # whether or not this element is visible (processed while drawing) (Tooltip does not have this as it automates visibility)
|
|
310
|
+
enabled: bool = True, # whether or not this element is enabled (processed when input handling)
|
|
311
|
+
block_input_when_occluded: bool = False, # whether or not to block the input of this element when it is hovered and another element is hovered above this one
|
|
312
|
+
z: int = 0, # the z layer of the object
|
|
313
|
+
ignores_environment: bool = False, # whether or not this element ignores its environment. If an object ignores its environment, it will not obide by its parent's components or child clipping.
|
|
314
|
+
)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Unless `ignores_environment` is set, elements natively cut off children that are outside of their bounds.
|
|
318
|
+
|
|
319
|
+
## Effects
|
|
320
|
+
|
|
321
|
+
`Effect` is a subclass of `Element` that visually modifies its parent subtree.
|
|
322
|
+
|
|
323
|
+
Built-in effects:
|
|
324
|
+
|
|
325
|
+
- `Gradient`
|
|
326
|
+
- `ButtonGradient`
|
|
327
|
+
- `Outline`
|
|
328
|
+
- `BorderRadius`
|
|
329
|
+
- `VisualLayer`
|
|
330
|
+
|
|
331
|
+
Effects are ordered using `z`.
|
|
332
|
+
|
|
333
|
+
Typical layering:
|
|
334
|
+
|
|
335
|
+
```text
|
|
336
|
+
Negative z:
|
|
337
|
+
backgrounds/gradients
|
|
338
|
+
|
|
339
|
+
Normal z:
|
|
340
|
+
content
|
|
341
|
+
|
|
342
|
+
Positive z:
|
|
343
|
+
outlines/glows/overlays
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Components
|
|
347
|
+
|
|
348
|
+
`Component`s modify behavior/layout but do not draw.
|
|
349
|
+
|
|
350
|
+
Built-in components:
|
|
351
|
+
|
|
352
|
+
- `Padding`
|
|
353
|
+
- `Font`
|
|
354
|
+
- `Camera`
|
|
355
|
+
- `Scrollable`
|
|
356
|
+
- `GlobalElement`
|
|
357
|
+
|
|
358
|
+
Attach/get/remove:
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
element.set_component(component)
|
|
362
|
+
|
|
363
|
+
element.get_component(ComponentType)
|
|
364
|
+
|
|
365
|
+
element.remove_component(ComponentType)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
or:
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
component.parent = element
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
# Input State
|
|
377
|
+
|
|
378
|
+
Access input using:
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
ws.input
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Controller profile changes are tracked on the workspace for the current frame:
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
ws.profile_changes
|
|
388
|
+
ws.profiles_added
|
|
389
|
+
ws.profiles_removed
|
|
390
|
+
ws.bad_joystick_indices
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Other miscellaneous controller properties / methods:
|
|
394
|
+
|
|
395
|
+
```python
|
|
396
|
+
ws.get_controller_name(profile)
|
|
397
|
+
|
|
398
|
+
ws.rumble_controller(profile, strength, duration_ms)
|
|
399
|
+
ws.stop_rumble_controller(profile)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Properties:
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
ws.input.keys_pressed
|
|
406
|
+
ws.input.key_downs
|
|
407
|
+
ws.input.key_ups
|
|
408
|
+
|
|
409
|
+
ws.input.mouse_buttons_pressed
|
|
410
|
+
ws.input.mouse_downs
|
|
411
|
+
ws.input.mouse_ups
|
|
412
|
+
|
|
413
|
+
ws.input.mouse_pos
|
|
414
|
+
ws.input.mouse_delta
|
|
415
|
+
ws.input.mouse_wheel
|
|
416
|
+
|
|
417
|
+
ws.input.controller_buttons_pressed
|
|
418
|
+
ws.input.controller_ups
|
|
419
|
+
ws.input.controller_downs
|
|
420
|
+
|
|
421
|
+
ws.input.controller_left_sticks
|
|
422
|
+
ws.input.controller_right_sticks
|
|
423
|
+
ws.input.controller_left_sticks_deltas
|
|
424
|
+
ws.input.controller_right_stick_deltas
|
|
425
|
+
|
|
426
|
+
ws.input.text_input
|
|
427
|
+
|
|
428
|
+
ws.input.dt
|
|
429
|
+
ws.input.running_fps
|
|
430
|
+
ws.input.runtime
|
|
431
|
+
ws.input.quit
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Helper methods:
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
ws.input.key_held()
|
|
438
|
+
ws.input.key_down()
|
|
439
|
+
ws.input.key_up()
|
|
440
|
+
|
|
441
|
+
ws.input.mousebutton_held()
|
|
442
|
+
ws.input.mousebutton_down()
|
|
443
|
+
ws.input.mousebutton_up()
|
|
444
|
+
|
|
445
|
+
ws.input.controllerbutton_held()
|
|
446
|
+
ws.input.controllerbutton_down()
|
|
447
|
+
ws.input.controllerbutton_up()
|
|
448
|
+
|
|
449
|
+
ws.input.left_stick(profile)
|
|
450
|
+
ws.input.right_stick(profile)
|
|
451
|
+
ws.input.left_stick_delta(profile)
|
|
452
|
+
ws.input.right_stick_delta(profile)
|
|
453
|
+
|
|
454
|
+
ws.input.input_action_held()
|
|
455
|
+
ws.input.input_action_down()
|
|
456
|
+
ws.input.input_action_up()
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Use `InputAction`s for easier keybind compatibility. Any matching key, mouse button, or controller button can trigger the action.
|
|
460
|
+
|
|
461
|
+
```python
|
|
462
|
+
keybind = plp.InputAction(
|
|
463
|
+
keys = [plp.Key.SPACE, plp.Key.RETURN],
|
|
464
|
+
mouse_buttons = [plp.MouseButton.LEFT],
|
|
465
|
+
controller_buttons = [plp.ControllerButton.A, plp.ControllerButton.B],
|
|
466
|
+
profiles = [plp.InputProfile.KEYBOARD_MOUSE, plp.InputProfile.CONTROLLER_0]
|
|
467
|
+
)
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
InputAction event helpers can run handlers directly from those keybinds:
|
|
471
|
+
|
|
472
|
+
```python
|
|
473
|
+
@plp.on_input_action_down(ws, keybind)
|
|
474
|
+
def activate(w: plp.Workspace):
|
|
475
|
+
...
|
|
476
|
+
|
|
477
|
+
@plp.while_input_action(ws, keybind)
|
|
478
|
+
def charge(w: plp.Workspace):
|
|
479
|
+
...
|
|
480
|
+
|
|
481
|
+
@plp.on_input_action_up(ws, keybind)
|
|
482
|
+
def release(w: plp.Workspace):
|
|
483
|
+
...
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Raw input event helpers are available for direct key, mouse button, and controller button checks:
|
|
487
|
+
|
|
488
|
+
```python
|
|
489
|
+
@plp.on_key_down(ws, plp.Key.ESCAPE)
|
|
490
|
+
def quit_game(w: plp.Workspace):
|
|
491
|
+
w.quit()
|
|
492
|
+
|
|
493
|
+
@plp.on_mousebutton_down(ws, plp.MouseButton.LEFT)
|
|
494
|
+
def click(w: plp.Workspace):
|
|
495
|
+
...
|
|
496
|
+
|
|
497
|
+
@plp.on_controllerbutton_down(ws, plp.ControllerButton.A, plp.InputProfile.CONTROLLER_0)
|
|
498
|
+
def confirm(w: plp.Workspace):
|
|
499
|
+
...
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
# Hover State
|
|
505
|
+
|
|
506
|
+
Workspace hover helpers:
|
|
507
|
+
|
|
508
|
+
```python
|
|
509
|
+
ws.is_mouse_top(element)
|
|
510
|
+
ws.is_mouse_over(element)
|
|
511
|
+
|
|
512
|
+
ws.just_hovered(element)
|
|
513
|
+
ws.just_unhovered(element)
|
|
514
|
+
|
|
515
|
+
ws.just_hovered_inclusive(element)
|
|
516
|
+
ws.just_unhovered_inclusive(element)
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
# Events
|
|
522
|
+
|
|
523
|
+
Decorator helpers create `Event` elements.
|
|
524
|
+
|
|
525
|
+
```python
|
|
526
|
+
@plp.on_start(target)
|
|
527
|
+
@plp.on_update(target)
|
|
528
|
+
@plp.on_quit(target)
|
|
529
|
+
|
|
530
|
+
@plp.on_resize(target)
|
|
531
|
+
@plp.on_maximize(target)
|
|
532
|
+
@plp.on_restore(target)
|
|
533
|
+
|
|
534
|
+
@plp.on_scene_change(target)
|
|
535
|
+
|
|
536
|
+
@plp.on_profile_changed(target)
|
|
537
|
+
@plp.on_profile_added(target)
|
|
538
|
+
@plp.on_profile_removed(target)
|
|
539
|
+
@plp.on_controller_not_connected(target)
|
|
540
|
+
|
|
541
|
+
@plp.on_input_action_down(target, action)
|
|
542
|
+
@plp.on_input_action_up(target, action)
|
|
543
|
+
@plp.while_input_action(target, action)
|
|
544
|
+
|
|
545
|
+
@plp.on_key_down(target, key, profile=None)
|
|
546
|
+
@plp.on_key_up(target, key, profile=None)
|
|
547
|
+
@plp.while_key_held(target, key, profile=None)
|
|
548
|
+
|
|
549
|
+
@plp.on_mousebutton_down(target, mousebutton, profile=None)
|
|
550
|
+
@plp.on_mousebutton_up(target, mousebutton, profile=None)
|
|
551
|
+
@plp.while_mousebutton_held(target, mousebutton, profile=None)
|
|
552
|
+
|
|
553
|
+
@plp.on_controllerbutton_down(target, controllerbutton, profile=None)
|
|
554
|
+
@plp.on_controllerbutton_up(target, controllerbutton, profile=None)
|
|
555
|
+
@plp.while_controllerbutton_held(target, controllerbutton, profile=None)
|
|
556
|
+
|
|
557
|
+
@on_hover(...)
|
|
558
|
+
@on_unhover(...)
|
|
559
|
+
@while_hovered(...)
|
|
560
|
+
|
|
561
|
+
@on_hover_inclusive(...)
|
|
562
|
+
@on_unhover_inclusive(...)
|
|
563
|
+
@while_hovered_inclusive(...)
|
|
564
|
+
|
|
565
|
+
@plp.create_event(target, condition)
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
Events attached to the main workspace are global by default.
|
|
569
|
+
|
|
570
|
+
Example:
|
|
571
|
+
|
|
572
|
+
```python
|
|
573
|
+
@plp.on_update(ws)
|
|
574
|
+
def tick(w: plp.Workspace):
|
|
575
|
+
if w.input.key_down(plp.Key.ESCAPE):
|
|
576
|
+
w.quit()
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
# Coroutines
|
|
582
|
+
|
|
583
|
+
Event-like functions can yield.
|
|
584
|
+
|
|
585
|
+
If a handler returns a generator, PlayPy resumes it on future frames.
|
|
586
|
+
|
|
587
|
+
Example:
|
|
588
|
+
|
|
589
|
+
```python
|
|
590
|
+
def flash(_: plp.Workspace):
|
|
591
|
+
for _ in range(60):
|
|
592
|
+
print("frame")
|
|
593
|
+
yield
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
Supported in:
|
|
597
|
+
- event callbacks
|
|
598
|
+
- button callbacks
|
|
599
|
+
- textbox callbacks
|
|
600
|
+
- other event-like handlers
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
# Textbox Features
|
|
605
|
+
|
|
606
|
+
`Textbox` supports:
|
|
607
|
+
- placeholders
|
|
608
|
+
- caret blinking
|
|
609
|
+
- text confirmation/reverting
|
|
610
|
+
- character filtering
|
|
611
|
+
- maximum length
|
|
612
|
+
- coroutine callbacks
|
|
613
|
+
|
|
614
|
+
Useful arguments:
|
|
615
|
+
|
|
616
|
+
```python
|
|
617
|
+
is_char_accepted: Callable[[str], bool] | None,
|
|
618
|
+
on_text_updated: Callable[[workspace.Workspace], Generator[None, None, None] | None] | None,
|
|
619
|
+
confirm_on_click_off: bool,
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
Special keys:
|
|
623
|
+
|
|
624
|
+
```text
|
|
625
|
+
Backspace -> remove character
|
|
626
|
+
Delete -> clear text
|
|
627
|
+
Return -> confirm text
|
|
628
|
+
Escape -> revert text
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
# Scenes
|
|
634
|
+
|
|
635
|
+
`Scene`s act as "sub-workspaces": when they are alive, only descendants of them (and global elements) are processed and drawn.
|
|
636
|
+
|
|
637
|
+
Use previously mentioned workspace scene lifecycle methods (`ws.queue_scene_change`, etc.) to manage alive scene.
|
|
638
|
+
|
|
639
|
+
`Scene`s support lifecycle hooks:
|
|
640
|
+
|
|
641
|
+
```python
|
|
642
|
+
on_enter()
|
|
643
|
+
on_exit()
|
|
644
|
+
on_pause()
|
|
645
|
+
on_resume()
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Scene changes are queued internally.
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
# Cameras and Scrolling
|
|
653
|
+
|
|
654
|
+
`Camera` offsets descendant elements.
|
|
655
|
+
|
|
656
|
+
`Scrollable` extends camera functionality with built-in scrolling support.
|
|
657
|
+
|
|
658
|
+
Example:
|
|
659
|
+
|
|
660
|
+
```python
|
|
661
|
+
scrollable = plp.Scrollable()
|
|
662
|
+
scrollable.parent = panel
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
### VisualLayer
|
|
668
|
+
|
|
669
|
+
`VisualLayer`s render `Sprite`s, `Animation`s, colors, and shader-like effects.
|
|
670
|
+
|
|
671
|
+
`VisualLayer` constructor:
|
|
672
|
+
```python
|
|
673
|
+
VisualLayer(
|
|
674
|
+
visual: plp.Sprite | plp.Animation | plp.ColorValue,
|
|
675
|
+
blend_mode: plp.BlendMode | None = None,
|
|
676
|
+
scale: plp.FRectValue = (0, 0, 1, 1),
|
|
677
|
+
offset: plp.RectValue = (0, 0, 0, 0),
|
|
678
|
+
z: int = -1_000_000,
|
|
679
|
+
visible: bool = True,
|
|
680
|
+
ignores_environment: bool = True
|
|
681
|
+
)
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
Use the previously mentioned `ignores_environment` for different types of `VisualLayer`s.
|
|
685
|
+
|
|
686
|
+
```python
|
|
687
|
+
# Overlay-style usage:
|
|
688
|
+
plp.VisualLayer(sprite, ignores_environment=True)
|
|
689
|
+
|
|
690
|
+
# Embedded panel/sprite usage:
|
|
691
|
+
plp.VisualLayer(sprite, plp.empty_frect(), (20, 20, 50, 50), ignores_environment=False)
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
# Logging
|
|
697
|
+
|
|
698
|
+
PlayPy replaces standard exceptions/logging with a categorized logging system.
|
|
699
|
+
|
|
700
|
+
```python
|
|
701
|
+
plp.log(severity, category, message)
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
Severities:
|
|
705
|
+
|
|
706
|
+
```python
|
|
707
|
+
plp.Severity.INFO
|
|
708
|
+
plp.Severity.WARNING
|
|
709
|
+
plp.Severity.ERROR
|
|
710
|
+
plp.Severity.CRITICAL
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
`ERROR` and `CRITICAL` are treated as `NoReturn`.
|
|
714
|
+
|
|
715
|
+
Use `plp.enter_debug_mode()` to prevent logs from halting the program.
|