plexi-sdk 0.4.0__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.
- plexi_sdk-0.4.0/.gitignore +61 -0
- plexi_sdk-0.4.0/PKG-INFO +127 -0
- plexi_sdk-0.4.0/README.md +105 -0
- plexi_sdk-0.4.0/plexi_sdk/__init__.py +477 -0
- plexi_sdk-0.4.0/plexi_sdk/_app.py +1077 -0
- plexi_sdk-0.4.0/plexi_sdk/_constants.py +52 -0
- plexi_sdk-0.4.0/plexi_sdk/_emitter.py +1466 -0
- plexi_sdk-0.4.0/plexi_sdk/_pipe.py +92 -0
- plexi_sdk-0.4.0/plexi_sdk/_protocol.py +48 -0
- plexi_sdk-0.4.0/plexi_sdk/_render_context.py +976 -0
- plexi_sdk-0.4.0/plexi_sdk/_types.py +139 -0
- plexi_sdk-0.4.0/plexi_sdk/midi.py +222 -0
- plexi_sdk-0.4.0/plexi_sdk/py.typed +1 -0
- plexi_sdk-0.4.0/plexi_sdk/templates/__init__.py +0 -0
- plexi_sdk-0.4.0/plexi_sdk/templates/app_init.py +72 -0
- plexi_sdk-0.4.0/plexi_sdk/testing.py +451 -0
- plexi_sdk-0.4.0/plexi_sdk/ui.py +1535 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/__init__.py +27 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/button.py +60 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/keymap.py +51 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/list_view.py +159 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/scroll.py +100 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/text_area.py +218 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/text_buffer.py +337 -0
- plexi_sdk-0.4.0/plexi_sdk/widgets/text_input.py +70 -0
- plexi_sdk-0.4.0/pyproject.toml +47 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Build
|
|
2
|
+
/target/
|
|
3
|
+
deps/egui_term/target/
|
|
4
|
+
|
|
5
|
+
# Scratch docs
|
|
6
|
+
docs/scratch/
|
|
7
|
+
|
|
8
|
+
# IDE
|
|
9
|
+
.idea/
|
|
10
|
+
.vscode/
|
|
11
|
+
|
|
12
|
+
# AI tool configs (local only)
|
|
13
|
+
.agents/
|
|
14
|
+
.claude/settings.local.json
|
|
15
|
+
.claude/*.lock
|
|
16
|
+
.kiro/
|
|
17
|
+
/skills-lock.json
|
|
18
|
+
|
|
19
|
+
# OS
|
|
20
|
+
.DS_Store
|
|
21
|
+
Thumbs.db
|
|
22
|
+
|
|
23
|
+
# Environment
|
|
24
|
+
.env
|
|
25
|
+
.env.local
|
|
26
|
+
|
|
27
|
+
# Generated bundle assets (cargo bundle generates its own from Cargo.toml)
|
|
28
|
+
assets/Info.plist
|
|
29
|
+
|
|
30
|
+
# Bundled Python runtime (fetched by `just fetch-python-runtime` at build time)
|
|
31
|
+
assets/python/
|
|
32
|
+
|
|
33
|
+
# Channel (per-worktree, not shared)
|
|
34
|
+
.channel
|
|
35
|
+
|
|
36
|
+
# Misc
|
|
37
|
+
*.log
|
|
38
|
+
*.swp
|
|
39
|
+
*.swo
|
|
40
|
+
here.md
|
|
41
|
+
NEXT.md
|
|
42
|
+
examples/*/target/
|
|
43
|
+
sdk/*/target/
|
|
44
|
+
worktrees/
|
|
45
|
+
|
|
46
|
+
# Python
|
|
47
|
+
__pycache__/
|
|
48
|
+
*.pyc
|
|
49
|
+
*.pyo
|
|
50
|
+
sdk/python/**/__pycache__/
|
|
51
|
+
sdk/python/*.egg-info/
|
|
52
|
+
|
|
53
|
+
# Local config
|
|
54
|
+
.plexi/
|
|
55
|
+
.plexi-alpha/
|
|
56
|
+
.plexi-beta/
|
|
57
|
+
.plexi-pr-*/
|
|
58
|
+
.superpowers/
|
|
59
|
+
|
|
60
|
+
# Claude agent memory (local, not shared)
|
|
61
|
+
.claude/agent-memory/
|
plexi_sdk-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plexi-sdk
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Python SDK for building Plexi apps via the PGAP v3 protocol
|
|
5
|
+
Project-URL: Homepage, https://github.com/ianjamesburke/PLEXI
|
|
6
|
+
Project-URL: Repository, https://github.com/ianjamesburke/PLEXI
|
|
7
|
+
Project-URL: Documentation, https://github.com/ianjamesburke/PLEXI/tree/main/sdk/python
|
|
8
|
+
Author-email: Ian Burke <ianjamesburke@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: apps,pgap,plexi,sdk,tiling,window-manager
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# plexi-sdk
|
|
24
|
+
|
|
25
|
+
Python SDK for building Plexi apps via the PGAP v3 protocol.
|
|
26
|
+
|
|
27
|
+
Full API reference: `plexi_sdk/__init__.py` docstring.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Keyboard Conventions
|
|
32
|
+
|
|
33
|
+
Apps should follow these standard navigation bindings so users get consistent behavior across all Plexi apps.
|
|
34
|
+
|
|
35
|
+
### Key name strings
|
|
36
|
+
|
|
37
|
+
Keys arrive in `on_key(ctx, key, mods)` as **lowercase canonical strings**:
|
|
38
|
+
|
|
39
|
+
| Physical key | `key` string |
|
|
40
|
+
|---|---|
|
|
41
|
+
| Enter / Return | `"return"` |
|
|
42
|
+
| Escape | `"escape"` |
|
|
43
|
+
| Backspace | `"backspace"` |
|
|
44
|
+
| Tab | `"tab"` |
|
|
45
|
+
| Space | `"space"` |
|
|
46
|
+
| Arrow keys | `"up"` / `"down"` / `"left"` / `"right"` |
|
|
47
|
+
|
|
48
|
+
The SDK normalizes egui's internal key names automatically. Always match against
|
|
49
|
+
the lowercase canonical strings — `key == "return"`, not `key == "Enter"`.
|
|
50
|
+
|
|
51
|
+
### Focus / modal conventions
|
|
52
|
+
|
|
53
|
+
| Action | Key |
|
|
54
|
+
|---|---|
|
|
55
|
+
| Open item / confirm / select | `"return"` |
|
|
56
|
+
| Exit focused view / go back | `"escape"` |
|
|
57
|
+
| Exit focused view (fallback) | `"backspace"` (optional second binding) |
|
|
58
|
+
|
|
59
|
+
Any view that opens a focused sub-view (detail panel, modal, inline editor) must
|
|
60
|
+
let the user exit with `"escape"`. No view should be a dead end.
|
|
61
|
+
|
|
62
|
+
**TextInput exception:** `"return"` fires `on_text_submitted`, so the TextInput
|
|
63
|
+
widget owns that key while focused. `"escape"` should still dismiss the
|
|
64
|
+
surrounding view or cancel the input mode.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
def on_key(self, ctx, key, mods):
|
|
68
|
+
if self.detail_open:
|
|
69
|
+
if key in ("escape", "backspace"):
|
|
70
|
+
self.detail_open = False
|
|
71
|
+
return
|
|
72
|
+
if key == "return":
|
|
73
|
+
self._confirm()
|
|
74
|
+
return
|
|
75
|
+
# list navigation below
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### List navigation
|
|
79
|
+
|
|
80
|
+
Standard bindings for any scrollable list:
|
|
81
|
+
|
|
82
|
+
| Key | Action |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `j` / `"down"` | Move selection down |
|
|
85
|
+
| `k` / `"up"` | Move selection up |
|
|
86
|
+
| `"return"` | Open selected item |
|
|
87
|
+
| `"escape"` | Exit list / go back |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## List + Detail Views
|
|
92
|
+
|
|
93
|
+
For any app with a list-and-detail pattern, prefer `SelectList` from
|
|
94
|
+
`plexi_sdk.ui` over managing selection state manually. It handles j/k/arrow
|
|
95
|
+
navigation, scroll-to-keep-selected-visible, and click hit-testing.
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from plexi_sdk import App
|
|
99
|
+
from plexi_sdk.ui import SelectList, Column
|
|
100
|
+
|
|
101
|
+
class MyApp(App):
|
|
102
|
+
async def on_init(self, ctx):
|
|
103
|
+
self.items = [{"name": "Alpha"}, {"name": "Beta"}, {"name": "Gamma"}]
|
|
104
|
+
self.list = SelectList(self.items) # stateful — create once, not per frame
|
|
105
|
+
self.detail_open = False
|
|
106
|
+
|
|
107
|
+
def on_key(self, ctx, key, mods):
|
|
108
|
+
if self.detail_open:
|
|
109
|
+
if key in ("escape", "backspace"):
|
|
110
|
+
self.detail_open = False
|
|
111
|
+
return
|
|
112
|
+
if key == "return":
|
|
113
|
+
self.detail_open = True
|
|
114
|
+
return
|
|
115
|
+
self.list.handle_key(key) # handles j/k/up/down
|
|
116
|
+
|
|
117
|
+
def on_render(self, ctx):
|
|
118
|
+
if self.detail_open:
|
|
119
|
+
ctx.text(20, 40, self.items[self.list.selected_idx]["name"])
|
|
120
|
+
else:
|
|
121
|
+
ctx.draw(Column([self.list.render(self.items)]))
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`SelectList` is stateful — create it in `on_init`, not `on_render`.
|
|
125
|
+
|
|
126
|
+
For the lower-level `ctx.list_view()` primitive (draw only, no state) see the
|
|
127
|
+
`ListItem` shape in the API reference.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# plexi-sdk
|
|
2
|
+
|
|
3
|
+
Python SDK for building Plexi apps via the PGAP v3 protocol.
|
|
4
|
+
|
|
5
|
+
Full API reference: `plexi_sdk/__init__.py` docstring.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Keyboard Conventions
|
|
10
|
+
|
|
11
|
+
Apps should follow these standard navigation bindings so users get consistent behavior across all Plexi apps.
|
|
12
|
+
|
|
13
|
+
### Key name strings
|
|
14
|
+
|
|
15
|
+
Keys arrive in `on_key(ctx, key, mods)` as **lowercase canonical strings**:
|
|
16
|
+
|
|
17
|
+
| Physical key | `key` string |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Enter / Return | `"return"` |
|
|
20
|
+
| Escape | `"escape"` |
|
|
21
|
+
| Backspace | `"backspace"` |
|
|
22
|
+
| Tab | `"tab"` |
|
|
23
|
+
| Space | `"space"` |
|
|
24
|
+
| Arrow keys | `"up"` / `"down"` / `"left"` / `"right"` |
|
|
25
|
+
|
|
26
|
+
The SDK normalizes egui's internal key names automatically. Always match against
|
|
27
|
+
the lowercase canonical strings — `key == "return"`, not `key == "Enter"`.
|
|
28
|
+
|
|
29
|
+
### Focus / modal conventions
|
|
30
|
+
|
|
31
|
+
| Action | Key |
|
|
32
|
+
|---|---|
|
|
33
|
+
| Open item / confirm / select | `"return"` |
|
|
34
|
+
| Exit focused view / go back | `"escape"` |
|
|
35
|
+
| Exit focused view (fallback) | `"backspace"` (optional second binding) |
|
|
36
|
+
|
|
37
|
+
Any view that opens a focused sub-view (detail panel, modal, inline editor) must
|
|
38
|
+
let the user exit with `"escape"`. No view should be a dead end.
|
|
39
|
+
|
|
40
|
+
**TextInput exception:** `"return"` fires `on_text_submitted`, so the TextInput
|
|
41
|
+
widget owns that key while focused. `"escape"` should still dismiss the
|
|
42
|
+
surrounding view or cancel the input mode.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
def on_key(self, ctx, key, mods):
|
|
46
|
+
if self.detail_open:
|
|
47
|
+
if key in ("escape", "backspace"):
|
|
48
|
+
self.detail_open = False
|
|
49
|
+
return
|
|
50
|
+
if key == "return":
|
|
51
|
+
self._confirm()
|
|
52
|
+
return
|
|
53
|
+
# list navigation below
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### List navigation
|
|
57
|
+
|
|
58
|
+
Standard bindings for any scrollable list:
|
|
59
|
+
|
|
60
|
+
| Key | Action |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `j` / `"down"` | Move selection down |
|
|
63
|
+
| `k` / `"up"` | Move selection up |
|
|
64
|
+
| `"return"` | Open selected item |
|
|
65
|
+
| `"escape"` | Exit list / go back |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## List + Detail Views
|
|
70
|
+
|
|
71
|
+
For any app with a list-and-detail pattern, prefer `SelectList` from
|
|
72
|
+
`plexi_sdk.ui` over managing selection state manually. It handles j/k/arrow
|
|
73
|
+
navigation, scroll-to-keep-selected-visible, and click hit-testing.
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from plexi_sdk import App
|
|
77
|
+
from plexi_sdk.ui import SelectList, Column
|
|
78
|
+
|
|
79
|
+
class MyApp(App):
|
|
80
|
+
async def on_init(self, ctx):
|
|
81
|
+
self.items = [{"name": "Alpha"}, {"name": "Beta"}, {"name": "Gamma"}]
|
|
82
|
+
self.list = SelectList(self.items) # stateful — create once, not per frame
|
|
83
|
+
self.detail_open = False
|
|
84
|
+
|
|
85
|
+
def on_key(self, ctx, key, mods):
|
|
86
|
+
if self.detail_open:
|
|
87
|
+
if key in ("escape", "backspace"):
|
|
88
|
+
self.detail_open = False
|
|
89
|
+
return
|
|
90
|
+
if key == "return":
|
|
91
|
+
self.detail_open = True
|
|
92
|
+
return
|
|
93
|
+
self.list.handle_key(key) # handles j/k/up/down
|
|
94
|
+
|
|
95
|
+
def on_render(self, ctx):
|
|
96
|
+
if self.detail_open:
|
|
97
|
+
ctx.text(20, 40, self.items[self.list.selected_idx]["name"])
|
|
98
|
+
else:
|
|
99
|
+
ctx.draw(Column([self.list.render(self.items)]))
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`SelectList` is stateful — create it in `on_init`, not `on_render`.
|
|
103
|
+
|
|
104
|
+
For the lower-level `ctx.list_view()` primitive (draw only, no state) see the
|
|
105
|
+
`ListItem` shape in the API reference.
|