docs(vt): slice-1 contract — per-column list bindings per KB 08 §3; .af is the only meta/nav store

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-06 19:58:47 +02:00
parent 986bd9668a
commit 59f247664a

View file

@ -51,10 +51,13 @@ lists in each `C*`/`A*`/`N*` class's `ImportFromMetAF`/`ExportToMetAF` pair
(py:6727-11821); nav node lines `<flw|pnt|prt|rcl|pau|cht|vnd|ptl|tlk|chk|jmp> x y z args`
(py:10728-11821); nested `All`/`Any`/`Not`/`DoAll` by indentation exactly as
metaf emits and accepts them; embedded navs inside `EmbedNav`. Load into the
existing `Meta`/`Navigation` models (replacing `VtankMetaProfileSerializer`
and `VtankNavRouteSerializer` as the profile-store format; keep the binary
readers only if a test still needs them — delete otherwise, with their
tests), save back as `.af` that metaf itself accepts. Proof: (1) every
existing `Meta`/`Navigation` models. `.af` becomes the ONLY storage and
authoring format of the meta and route profile stores. The existing binary
`VtankMetaProfileSerializer`/`VtankNavRouteSerializer` are demoted to a
one-shot import (`.met`/`.nav` → model → saved as `.af`); their `Save`
writers and writer tests are deleted (lead's call under the owner's "do not
implement .met" direction — flagged in the closeout for the owner). Save
back as `.af` that metaf itself accepts. Proof: (1) every
`.af` under `metas/af/` parses; (2) parse → write → parse is identical;
(3) for the `met/` and `nav/` samples, our model loaded from metaf's own
`.af` conversion equals our model loaded from the matching `.af` in `af/`
@ -74,17 +77,21 @@ to fail first.
Oracle: `docs/research/vtank-kb/08-ui-views.md` §2-3 (VVS `HudList`
semantics and the proposed extension), `docs/plugin-ui-markup.md`.
B1. Markup: `<list>` accepts child `<column type="text|check|icon"
header="…" width="…" [name] />` elements. Without columns the element is
unchanged (single text column, existing bindings). With columns: `rows`
binds an `IEnumerable<PluginListRow>`-shaped contract in
`AcDream.Plugin.Abstractions` (BCL-only: a row = ordered cells; cell = text
string, bool check, or uint icon id with `iconkind` per column), `selected`
/`onchange` as today, plus `oncell="{Action<int,int>}"` (row, column) fired
on a click inside a cell, and check columns toggling through
`oncheck="{Action<int,int,bool>}"`. Header row optional (`headers="true"`),
per-column widths in px with the last column absorbing the remainder,
horizontal clipping per cell, scrolling as today.
B1. Markup, exactly doc 08 §3's proposal: `<list>` accepts child
`<column type="text|check|icon" width="…" [iconkind] [colors]/>` elements,
each binding its own per-row source parallel to the row count (per-attribute
binding like every other element; no new `Plugin.Abstractions` type):
`items="{IReadOnlyList<string>}"` for text, `values="{IReadOnlyList<bool>}"`
+ `onchange="{Action<int>}"` (row index; the plugin flips its own bool) for
check, `values="{IReadOnlyList<uint>}"` + `iconkind` + `onclick="{Action<int>}"`
for icon. Row count = the longest bound column; short columns draw empty
cells. The list's own `selected`/`onchange` stay as today; a click in a
check/icon column fires that column's callback and does NOT change
selection; a click in a text column selects. No header row (VTank's idiom
is `<label>`s above the list; document it). Per-column widths in px, the
last column absorbs the remainder, per-cell horizontal clipping, scrolling
as today. Without `<column>` children the element is byte-for-byte the old
single-column list (existing `items`/`icons`/`colors` attributes unchanged).
B2. Widget: extend `UiMarkupList` (or a sibling) — draw header, per-cell
text/check/icon, hit-test to (row, column), keyboard-free. Icons through the
existing `IMarkupIconResolver` with the column's `iconkind`.