feat(ui-markup): slice 7 step 1 — <slider min max> and <menu scroll>

Campaign VT slice 7 needs to transcribe VTank's own Vitals sliders
(minimum=0/maximum=100) and its long Profiles/Route named-item combos
control-for-control (docs/research/vtank-kb/08-ui-views.md §3's two
markup gaps). acdream's <slider> was hardwired to a 0.0-1.0 scalar and
<menu> always wrapped overflow into extra columns instead of VVS's
single scrolling column.

<slider min max>: optional literal attributes declaring the range the
bound value/onchange speak in (e.g. min="0" max="100" for a percent),
while UiScrollbar itself keeps its existing 0.0-1.0 internal math
untouched — MarkupDocument rescales at the binding boundary. Omitting
both (every pre-existing <slider>) keeps the exact historical identity
range.

<menu scroll="true">: wires UiMenu.Scrollable plus the same
track/thumb/up/down chrome sprites ConfigOptionsPageController and
VendorUiController already apply to their own Scrollable menus,
previously only reachable from C#. Omitting scroll keeps the
historical column-wrapping default.

Both are additive — no existing <slider>/<menu> markup changes
behavior. New pins in MarkupDocumentTests.cs shown to fail against the
prior MarkupDocument.cs (5 failures: Build_SliderWithNoMinMax_*,
Build_SliderWithMinMax_*, Slider_MinMax_Draws*,
Build_MenuWithScrollAttribute_*, Menu_Scroll_Draws*) before this
change, all green after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-07 07:07:42 +02:00
parent fbdbbc7f90
commit e72a64a311
3 changed files with 283 additions and 6 deletions

View file

@ -106,9 +106,9 @@ vanishing from the built tree.
| `meter` | Retail-style nine-slice bar | `x y w h fill cur max color anchor backleft/backtile/backright frontleft/fronttile/frontright` |
| `tab` | Selectable tab button | `x y w h text selected onclick` |
| `toggle` | Lamp-style checkbox | `x y w h text checked onclick color` |
| `slider` | Horizontal scalar | `x y w h value onchange` |
| `slider` | Horizontal scalar | `x y w h value onchange min max` |
| `field` | Single-line editable text | `x y w h text maxlength clearonsubmit onchange onsubmit color background` |
| `menu` | Dropdown selector | `x y w h items selected onchange rows rowheight openupward` |
| `menu` | Dropdown selector | `x y w h items selected onchange rows rowheight openupward scroll` |
| `list` | Scrollable row list (+ Slice B icon column, + Campaign VT slice 1 multi-column) | `x y w h selected onchange rowheight` + either the single-column `items colors icons iconkind`, or one-to-many `<column>` children (see "Columns" below) — never both |
Common to every element via `ApplyCommon`: `name`/`id` (a stable control
@ -466,6 +466,55 @@ single-text-column widget — every existing panel (including every current
MossTank tab) keeps working unchanged; `<column>` is additive, not a
migration.
## Slider range and scrollable menus (Campaign VT slice 7)
Two small `<slider>`/`<menu>` attributes, both closing gaps identified in
`docs/research/vtank-kb/08-ui-views.md` §3 while porting VTank's own Vitals
and Profiles tabs.
### `<slider min max>`
VVS's `HudHSlider`/`LinearPositionControl` expose an arbitrary `Min`/`Max`
range (VTank's own nine Vitals sliders are `minimum="0" maximum="100"`).
acdream's `<slider>` always bound a fixed 0.01.0 scalar; `min`/`max` are
now optional literal attributes that declare the range the BOUND `value`/
`onchange` speak in, while the widget itself keeps working internally in
0.01.0 (drag math, click-to-jump, mouse-wheel are all unchanged):
```xml
<slider x="96" y="0" w="144" h="16" min="0" max="100"
value="{HealPercent}" onchange="{SetHealPercent}"/>
```
`HealPercent`/`SetHealPercent` read and write a plain `0..100` value — no
`/100f` scaling shim in the plugin's own ViewModel. Omitting both attributes
(every `<slider>` written before this slice) keeps the exact historical
0.01.0 identity range — `min`/`max` default to `0`/`1`, so `(value-0)/(1-0)`
and `0+t*(1-0)` are both no-ops. A declared `min == max` falls back to a
range of `1` rather than dividing by zero.
### `<menu scroll="true">`
VVS's `HudCombo` popup is always exactly one scrolling column, at most 10
rows visible before a scrollbar appears (`HudCombo.cs:35,102-146`).
acdream's `<menu>` instead wraps overflow into extra columns unless the
markup opts into `UiMenu.Scrollable` — previously only reachable from C#
(`ConfigOptionsPageController`, `VendorUiController`). `scroll="true"` wires
`Scrollable` plus the same track/thumb/up/down chrome sprites those two
controllers already apply, so a VTank `Choice` with many entries (the
27-option recall menu, a long named-profile list) keeps VVS's one-column
look instead of fanning out sideways:
```xml
<menu x="188" y="64" w="120" h="22" items="{RouteProfileNames}"
selected="{SelectedRouteProfile}" onchange="{SelectRouteProfile}"
rows="7" scroll="true"/>
```
Omitting `scroll` (every `<menu>` written before this slice) keeps
`Scrollable` at its historical `false` default — the column-wrapping
behavior is unchanged.
## The plugin shelf (Slice A)
The shelf (`AcDream.App.UI.PluginSidePanel`) is the right-edge strip of