docs(vt): VT1 catalog 08 — VTank UI views from its own view XML and VVS semantics

156 controls across nine tabs plus the three secondary views, each with type,
geometry and bound setting where determinable; VVS control semantics our
markup must offer (multi-column lists with text/check/icon columns, combo,
notebook); window icon and StoredViewInfo facts; MossTank gap. Three cited
claims spot-checked against refs/ by the lead.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-06 19:23:04 +02:00
parent 7ef596581e
commit 68abeffb37

View file

@ -0,0 +1,494 @@
# Campaign VT knowledge base — 08: UI views
Research-only. No code changes. Sources cited by path; `file:line` given for
every code claim. Decompiled VTank/VVS code is **never quoted verbatim**
below — every fact is paraphrased or given as a name/number/attribute list.
Primary sources:
- `refs/vtank/uTank2.ViewXML.mainView.xml` — the main window: 856×210,
9 `<page>` tabs, **156 controls, 38 list columns** (counted directly from
the file; matches the brief's "156 controls").
- `refs/vtank/uTank2.ViewXML.AdvancedOptionsView.xml`,
`SelfBuffChoiceView.xml`, `FriendlyLootEditorView.xml` — secondary popup
views.
- `refs/vtank/uTank2.Resources.defaultsettings.usd` — VTank's serialized
default-settings catalog (setting name / type / default / description /
category-bitmask). This is the authoritative cross-reference for what
each Options/Vitals control actually persists.
- `refs/vvs/decompiled/VirindiViewService.XMLParsers/Decal3XMLParser.cs`
the XML→control mapping table (progid string → concrete `Hud*` class +
constructor arguments). This is the ground truth for "what does this XML
attribute actually do at parse time."
- `refs/vvs/decompiled/VirindiViewService.Controls/*.cs` — control behavior
(`HudList`, `HudCombo`, `HudTabView`, `HudHSlider`/`LinearPositionControl`,
`HudTextBox`, `HudButton`, `HudCheckBox`, `HudPictureBox`, `HudControl`).
- `refs/vvs/decompiled/VirindiViewService/HudView.cs`,
`ViewProperties.cs`, `ACImage.cs` — window chrome, icon-id resolution,
`StoredViewInfo` persistence.
- `refs/vvs/decompiled/VirindiViewService.Themes/Float_Theme.cs` — default
theme pixel constants (`TabHeight`, `SliderNubWidth`, etc.).
- `refs/vtank/decompiled/uTank2/PluginCore.cs` — the class that loads
`mainView.xml`, casts every named control to a typed wrapper interface,
and wires `Click`/`Change`/`Change_Old` handlers. **Heavily obfuscated**
(single/double-letter field and method names) — see §6.
- `refs/vtank/decompiled/MetaViewWrappers.VirindiViewServiceHudControls/List.cs`
— the `IList` wrapper VTank actually programs against (row/cell
accessors, `Click(row,col)`).
- Our side: `src/AcDream.App/UI/MarkupDocument.cs`, `docs/plugin-ui-markup.md`,
`src/AcDream.Plugins.MossTank/mosstank.xml`.
---
## 0. Window-level facts (item 4)
| Fact | Value | Source |
|---|---|---|
| Declared size | `width="856" height="210"` | `mainView.xml:2` |
| `properties.Width`/`Height` | XML value **minus** `HudViewDrawStyle.Theme_OldDecal`'s border `Size` (border chrome is subtracted from the declared size before it becomes the client area) | `Decal3XMLParser.cs:33-37` |
| Icon attribute | `icon="10667"` | `mainView.xml:2` |
| Icon resolution | `ViewProperties.Icon` is typed `ACImage`; the parser assigns it the **int** returned by `a(XmlAttribute)` (the `icon` attribute parsed as a plain integer), which converts via `ACImage`'s `implicit operator ACImage(int p)`. Every `ACImage` int-constructor path ORs the input with `0x6000000` before resolving it as a portal.dat id (`portalfile \| 0x6000000`) | `Decal3XMLParser.cs:32`, `ACImage.cs:618` (`op_Implicit`), `ACImage.cs:282-410` (the `\| 0x6000000` pattern repeated on every constructor) |
| → confirmed formula | icon **10667** (`0x29AB`) resolves to portal.dat id **`0x0600` `29AB`** = `0x060029AB` — i.e. exactly the task's guessed `0x06000000 + 10667` formula, confirmed structurally (VTank's own icon id space is bare portal.dat indices, same convention our `PluginIcons.Normalize` documents for `did` bindings) | `ACImage.cs:618`, cross-ref `docs/plugin-ui-markup.md`'s icon-id grammar section |
| Title | Set at runtime, not in XML: `"Virindi Tank v." + <assembly version>` (` (SIMULATION MODE)` appended when simulating) | `refs/vtank/decompiled/uTank2/PluginCore.cs:1608-1613` |
| Window icon (taskbar/system) | Overridden separately after load via `this.k.SetIcon(101, GetModuleHandle("utank2-i"))` — a **Win32 resource icon** from the plugin DLL itself, unrelated to the `icon="10667"` DAT-portal icon (that one is VVS's own window-manager/hud-bar icon) | `PluginCore.cs:1614` |
| Resizability | `UserResizeable = true`; `MinimumClientArea = new Size(792, <initial height>)`; `MaximumClientArea = new Size(<initial width>, 9999)` — width is effectively pinned near its authored value (a little horizontal shrink to 792 allowed, no growth past the authored width), height can grow unbounded (to 9999) but not shrink below the authored height. This matches a list-heavy layout where the user wants to see more rows, not more columns | `PluginCore.cs:1859-1862` |
| `HudView.UserResizeable` effect on border | Resizeable views use a **different, thicker** themed border (`ViewBorder*_Size_Resizeable` vs `ViewBorder*_Size`) — border thickness is data-driven per resizability state, not a fixed constant | `HudView.cs:561-607` |
| Persistence store | SQLite file at the registry path `HKLM\SOFTWARE\Decal\Services\{DBAC9286-...}\StoredInfoFile`, table **`StoredViewInfo`**: `ViewKey TEXT UNIQUE PK, LocX INT, LocY INT, LocSticky INT, UserW INT, UserH INT, Ghost INT, Theme TEXT, Enabled INT, ClickThrough INT, IsCustomTheme INT, ThemeID INT, ThemeID2 TEXT` | `HudView.cs:1868-1883` (`CREATE TABLE`), `:1916-2018` (`LoadUserSettings`/`ad()` — the `select` matching this schema), `:2020-2072` (`ac()`/the `insert or replace` on save) |
| `ViewKey` (`a9` field) | `"<calling assembly name>:<windowKey>"` — VTank passes no explicit window key to its main `HudView`, so persistence keys off the assembly name + an empty/default key unless a `pWindowKey` constructor overload is used | `HudView.cs:1711-1726` (`a(...)` ctor helper, `ba`/`a9` fields) |
| What's persisted | Location (X/Y), a 4-bit "sticky edge" mask (`LocSticky`, ghost-docking to a screen edge), user-resized W/H, `Ghosted` (hudified/pinned mode), visibility, click-through, and the active theme (by name or numeric index, plus a custom-theme flag) | same range as above |
| Save trigger | Debounced onto the thread pool (`ThreadPool.QueueUserWorkItem`) any time position/size/ghost/click-through/theme changes, not on a timer | `HudView.cs:2020-2040` |
| Right-click / context menu | Exists **only at the window-chrome level** (`HudView.l` = `ContextMenu<a>`), with fixed entries `close`/`alphaup`/`alphadown`/`ghost`/`clickthrough`/`nexttheme`/`resettheme` plus one per user-added titlebar button (`"user~N"`) and one per theme (`"themeset"`). There is **no** per-control or per-list-row right-click anywhere in the base control classes (`HudControl`/`HudList` only ever wire left-button `MouseDown`/`MouseUp`/`MouseMove`/`MouseWheel`) | `HudView.cs:1583-1643` (menu dispatch), confirmed absent by a repo-wide grep for right/second-button handling in `refs/vvs/decompiled` (`RightMouseDown`/`MouseButton.Right`/etc. — zero matches) |
| Double-click | Not implemented anywhere in the base control classes. `HudControl.Hit`/`MouseUp` fires once per press-release pair inside the same control; there is no timestamp-based double-click detector in `HudControl`, `HudList`, or `HudCombo` | same grep + direct read of `HudControl.cs:429-474` |
---
## 1. Per-tab control tables
All geometry, names, and text below is transcribed directly from
`mainView.xml` (100% exact — every `left`/`top`/`width`/`height`/`text` is a
literal attribute value). "Setting/action" columns marked **[confirmed]**
are cross-referenced against `defaultsettings.usd` and/or a direct
`PluginCore.cs` line; those without a bracket are a naming-convention
inference (VTank's own control names are self-describing in most cases) and
are called out as such.
### Tab: Options (37 controls: 36 leaf + 1 `FixedLayout` container, 0 list columns)
| Control | Type | L,T,W,H | Text | Setting / action | Notes |
|---|---|---|---|---|---|
| Label12 | StaticText | 8,8,80,16 | "Monster Range:" | — | label for txtRange |
| txtRange | Edit | 8,24,40,16 | "" | `AttackDistance` **[confirmed]** — `defaultsettings.usd:283-289` (a fractional "distance" unit, default `0.0208333333333333`) | `imageportalsrc="4726"`**dead attribute**, see §2 |
| Label22 | StaticText | 8,40,80,16 | "Ring Range:" | — | |
| txtRingRange | Edit | 8,56,40,16 | "" | `RingDistance` **[confirmed]** — `defaultsettings.usd:307-313` | |
| Label23 | StaticText | 8,72,80,16 | "Approach Range:" | — | |
| txtApproachRange | Edit | 8,88,40,16 | "" | `ApproachDistance` **[confirmed]** — `defaultsettings.usd:299-305` | |
| Label24 | StaticText | 8,104,80,16 | "Follow/Nav Min Distance:" | — | |
| txtWPRange | Edit | 8,120,40,16 | "" | `NavCloseStopRange` (inferred by name/purpose match; not directly grepped to this field) — `defaultsettings.usd:331-337` | |
| bForceBuff | PushButton | 90,8,112,25 | "Force Buff" | action (no persisted setting) | wired `IButton.Click` in `PluginCore.cs:1629,1752` (`this.z`) |
| bCancelForceBuff | PushButton | 90,38,112,25 | "Cancel Force Buff" | action | `PluginCore.cs:1630,1772` (`this.aa`) |
| cEnableBuffing | Checkbox | 90,68,120,20 | "Enable Buffing" | `EnableBuffing` **[confirmed]** — `defaultsettings.usd:163-169` | |
| cEnableCombat | Checkbox | 90,88,120,20 | "Enable Combat" | `EnableCombat` **[confirmed]** — `defaultsettings.usd:171-177` | |
| c1EnableNav | Checkbox | 90,108,120,20 | "Enable Navigation" | `EnableNav` **[confirmed]** — `defaultsettings.usd:155-161` | |
| c1EnableLooting | Checkbox | 90,128,120,20 | "Enable Looting" | `EnableLooting` **[confirmed]** — `defaultsettings.usd:147-153` | |
| c1EnableMeta | Checkbox | 90,148,120,20 | "Enable Meta" | `EnableMeta` **[confirmed]** — `defaultsettings.usd:1027-1033` | |
| cEnableAutoStack | Checkbox | 220,8,160,20 | "Enable Autostack" | `AutoStack` **[confirmed]** — `defaultsettings.usd:419-425` | |
| cEnableAutoCram | Checkbox | 220,28,160,20 | "Enable Autocram" | `AutoCram` **[confirmed]** — `defaultsettings.usd:411-417` | |
| cGems | Checkbox | 220,48,120,20 | "Use Dispel Items" | `UseDispelItems` **[confirmed]** — `defaultsettings.usd:403-409` | XML name ("Gems") doesn't match the text/setting — a VTank-internal inconsistency |
| cDispel | Checkbox | 220,68,120,20 | "Cast Dispel Self" | `CastDispelSelf` **[confirmed]** — `defaultsettings.usd:395-401` | |
| cAutoFellow | Checkbox | 220,128,120,20 | "Auto Fellow Mgmt." | `AutoFellowManagement` **[confirmed]** — `defaultsettings.usd:811-817` | |
| cMChargesWhenOff | Checkbox | 220,148,160,20 | "M. Charges When Off" | `ManaChargesWhenOff` **[confirmed]** — `defaultsettings.usd:803-809` | |
| cNavPriorityBoost | Checkbox | 386,8,160,20 | "Boost Nav. Priority" | `NavPriorityBoost` **[confirmed]** — `defaultsettings.usd:851-857` | |
| cLootPriorityBoost | Checkbox | 386,28,160,20 | "Boost Loot Priority" | `LootPriorityBoost` **[confirmed]** — `defaultsettings.usd:659-665` | |
| cLootOnlyRareCorpses | Checkbox | 386,48,160,20 | "Loot Only Rare Corpses" | `LootOnlyRareCorpses` **[confirmed]** — `defaultsettings.usd:907-913` | |
| cIdlePeace | Checkbox | 386,68,160,20 | "Peace Mode When Idle" | `IdlePeaceMode` **[confirmed]** — `defaultsettings.usd:515-521` | |
| cTopoffBuffs | Checkbox | 386,88,160,20 | "Rebuff When Idle" | `IdleBuffTopoff` **[confirmed]** — `defaultsettings.usd:571-577` | |
| cFastCast | Checkbox | 386,108,160,20 | "Fastcast Buffs" | `FastCastBuffs` **[confirmed]** — `defaultsettings.usd:1139-1145` | |
| cCollisionChecks | Checkbox | 386,128,160,20 | "Don't Shoot at Walls" | `UseProjectileAwareness` **[confirmed]** — `defaultsettings.usd:1155-1161` | inverse-named XML control name vs. the actual boolean sense (checked = awareness ON) |
| cDebuffFallback | Checkbox | 386,148,160,20 | "Fallback Debuffs if Blocked" | `AllowDebuffFallback` **[confirmed]** — `defaultsettings.usd:1227-1233` | |
| cSummonPets | Checkbox | 552,8,160,20 | "Summon Pets" | `SummonPets` **[confirmed]** — `defaultsettings.usd:1075-1081` | |
| cCustomPetRange | Checkbox | 552,28,120,20 | "Custom Pet Range:" | `PetRangeMode` (enum 0=`AttackDistance`,1=`PetCustomRange`, per `SettingsEnumInfo` table) **[confirmed]** — `defaultsettings.usd:1083-1089,2260-2271` | |
| txtCustomPetRange | Edit | 672,28,40,16 | "" | `PetCustomRange` **[confirmed]** — `defaultsettings.usd:1091-1097` | |
| Label1_PetDensity | StaticText | 552,48,125,16 | "Pet Min. Monsters:" | — | |
| txtPetDensity | Edit | 672,48,40,16 | "" | `PetMonsterDensity` **[confirmed]** — `defaultsettings.usd:1123-1129` | |
| cShowAdvanced | Checkbox | 611,128,233,20 | "Advanced Options" | UI-only (not in `defaultsettings.usd`) — opens/closes the `AdvancedOptionsView` popup (`refs/vtank/decompiled/db.cs:79`, icon 9660 "gear" per `AdvancedOptionsView.xml:2`) | not a persisted macro setting, a window-visibility toggle |
| cOn | Checkbox | 611,148,233,20 | "Run Macro" | runtime master enable, not in `defaultsettings.usd` | |
### Tab: Profiles (18 controls, 0 list columns)
Every row follows the same **enable-checkbox + profile-name combo +
CopyTo/New button (+ optional Reset/Show-Editor)** pattern, one per macro
sub-system:
| Control | Type | L,T,W,H | Text | Binds to |
|---|---|---|---|---|
| Label123 | StaticText | 8,8,142,16 | "Macro Settings" | — |
| cmbSettingsSet | Choice | 140,8,140,20 | (populated at runtime) | named macro-settings profile list |
| bSettingsSaveAs | PushButton | 280,8,40,20 | "CopyTo" | copy current profile to a new name |
| cSettingsShowAll | Checkbox | 440,8,80,20 | "Mine only" | filter profile list to the current character |
| bSettingsReset | PushButton | 330,8,100,20 | "Clear profile!" | reset current profile to defaults |
| cNav | Checkbox | 8,32,142,20 | "Enable Auto-Navigation" | `EnableNav` **[confirmed]** (same setting the Options-tab `c1EnableNav` binds — two controls, one setting) |
| cmbNavSet | Choice | 140,32,140,20 | — | named nav-profile list |
| bNavSaveAs | PushButton | 280,32,40,20 | "CopyTo" | |
| bNavReset | PushButton | 330,32,100,20 | "Clear nav profile!" | |
| cLoot | Checkbox | 8,56,142,20 | "Enable Looting" | `EnableLooting` **[confirmed]** (same setting as `c1EnableLooting`) |
| cmbLootSet | Choice | 140,56,140,20 | — | named loot-profile list |
| bLootSaveAs | PushButton | 280,56,40,20 | "New" | (label differs from the Nav/Settings "CopyTo" — loot profiles are created fresh, not copied) |
| cShowLootEditor | Checkbox | 440,56,80,20 | "Show Editor" | opens/closes the `FriendlyLootEditorView` popup **[confirmed]** — `PluginCore.cs:1667,1764,6270-6289` (`bb.Change_Old` handler calls `dz.ah.f()`/`dz.ah.b()` to open/close) |
| cMeta | Checkbox | 8,80,142,20 | "Enable Meta Actions" | `EnableMeta` **[confirmed]** (same setting as `c1EnableMeta`) |
| cmbMetaSet | Choice | 140,80,140,20 | — | named meta-profile list |
| bMetaSaveAs | PushButton | 280,80,40,20 | "CopyTo" | |
| bMetaClearViews | PushButton | 330,80,100,20 | "Del. Meta Windows" | closes any floating meta-debug windows |
### Tab: Vitals (28 controls, 0 list columns)
Three groups of 3 sliders + 3 percent-readout labels, each slider bound to
one of the nine `Recharge-<Stance>-<Vital>` settings — **fully confirmed**
by both the initializer and every change handler:
| Control | Type | L,T,W,H | Label | Setting **[confirmed]** | Evidence |
|---|---|---|---|---|---|
| slMyHP | Slider | 96,0,144,16 | "Heal at:" | `Recharge-Norm-HitP` | `PluginCore.cs:4417-4427` (handler `aj`), `:4566` (init) |
| slMyStam | Slider | 96,16,144,16 | "Restam at:" | `Recharge-Norm-Stam` | `:4404-4415` (`ak`), `:4567` |
| slMyMana | Slider | 96,32,144,16 | "Get Mana at:" | `Recharge-Norm-Mana` | `:4391-4402` (`al`), `:4568` |
| slTopOffHP | Slider | 96,56,144,16 | "Top-off HP:" | `Recharge-NoTarg-HitP` | `:4339-4349` (`ap`), `:4569` |
| slTopOffStam | Slider | 96,72,144,16 | "Top-off Stam:" | `Recharge-NoTarg-Stam` | `:4570` (init; handler by symmetry with `ap`) |
| slTopOffMana | Slider | 96,88,144,16 | "Top-off Mana:" | `Recharge-NoTarg-Mana` | `:4571` |
| slOtherHP | Slider | 96,112,144,16 | "Heal others at:" | `Recharge-Helper-HitP` | `:4378-4389` (`am`), `:4572` |
| slOtherStam | Slider | 96,128,144,16 | "Restam others at:" | `Recharge-Helper-Stam` | `:4573` |
| slOtherMana | Slider | 96,144,144,16 | "Infuse others at:" | `Recharge-Helper-Mana` | `:4574` |
Each slider has a matching `min="0" max="100"` (`mainView.xml:81-83` etc.)
percent readout label (`lblVitals_H_Self`, `_S_Self`, `_M_Self`, `_H_Idle`,
`_S_Idle`, `_M_Idle`, `_H_Help`, `_S_Help`, `_M_Help` — 9 `StaticText`
controls at 248,0 / 248,16 / … / 248,144, each `80×16`, default text `"0%"`)
updated from the slider's `.Position` on every `Change` (e.g.
`cx.Text = co.Position + "%";``PluginCore.cs:4560-4561`). Plus the 9
"Heal at:"/"Restam at:"/… `Label1`/`Label2`/`Label3`/`Label11`/`Label21`/
`Label31`/`Label111`/`Label211`/`Label311` captions (8×16 each).
### Tab: Monsters (26 controls: 25 leaf + 1 container, **23 list columns**)
The single `lstMonsters` list (0,16,856,116) has **23 declared columns**,
14 checkbox + 7 text + 2 icon — matching (with two anomalies) the
**21-field `MyMonsters` settings table** (`defaultsettings.usd:48-91`:
`MonsterName, AttackPriority, DamageType, WeaponToUse, Imperil, Vuln,
Yield, GravityW, Attack, Ring, Broadside, Fester, WeakeningCurse,
FesteringCurse, Corruption, DestructiveCurse, Corrosion, Streak,
SecondaryVuln, SecondaryEquip, PetDamageType`):
| # | Column `name` | VVS type | fixedwidth | Data-field match | Header (separate StaticText above the list) |
|---|---|---|---|---|---|
| 1 | clFester | CheckColumn | 16 | `Fester` | "F" (`Label_Mon_F`) |
| 2 | clBroadside | CheckColumn | 16 | `Broadside` | "B" |
| 3 | clGravity | CheckColumn | 16 | `GravityW` | "G" |
| 4 | clImp | CheckColumn | 16 | `Imperil` | "I" |
| 5 | clYield | CheckColumn | 16 | `Yield` | "Y" |
| 6 | clVuln | CheckColumn | 16 | `Vuln` | "V" |
| 7 | clWar | CheckColumn | 16 | `Attack` | "A" |
| 8 | clRings | CheckColumn | 16 | `Ring` | "R" |
| 9 | clRings *(duplicate name — bug in VTank's own XML, see §6)* | CheckColumn | 16 | `Streak`? (unclear — see §6) | "S" |
| 10 | clWeakeningCurse | CheckColumn | 16 | `WeakeningCurse` | "WC" |
| 11 | clFesteringCurse | CheckColumn | 16 | `FesteringCurse` | "FC" |
| 12 | clCorruption | CheckColumn | 16 | `Corruption` | "Cp" |
| 13 | clDestructiveCurse | CheckColumn | 16 | `DestructiveCurse` | "DC" |
| 14 | clCorrosion | CheckColumn | 16 | `Corrosion` | "Cs" |
| 15 | clMonName | TextColumn | 120 | `MonsterName` | "Name" |
| 16 | clPriority | TextColumn | 20 | `AttackPriority` | "P" |
| 17 | clDamageType | TextColumn | 56 | `DamageType` | "Dmg type" |
| 18 | clExVulnType | TextColumn | 56 | `SecondaryVuln` (inferred) | "Ex. Vuln" |
| 19 | clWeaponToUse | TextColumn | 80 | `WeaponToUse` | "Weapon" |
| 20 | clOffHand | TextColumn | 80 | `SecondaryEquip` (inferred) | "Offhand" |
| 21 | clPetDamageType | TextColumn | 56 | `PetDamageType` | "PetDmg" |
| 22 | clMoveUp | IconColumn | 16 | (UI-only reorder arrow, no data field) | — |
| 23 | clMoveDown | IconColumn | 16 | (UI-only reorder arrow, no data field) | — |
Below the list: `txtNewMonster` (Edit, 8,136,388,16), `cmdNewMonster`
(PushButton "Add", 404,136,50,16), `cmdNewMonsterFromCur` (PushButton
"Add Sel", 462,136,50,16). Nine tooltip strings are assigned to the header
labels at runtime (`bm.TooltipText = "Fester"` … `b0.TooltipText =
"Priority"`, `PluginCore.cs:1693-1707`) — the single-letter header glyphs
are deliberately terse and rely on a hover tooltip to spell out the full
curse/spell-family name.
### Tab: Items (6 controls, 2 list columns)
| Control | Type | L,T,W,H | Text | Columns |
|---|---|---|---|---|
| Label4a | StaticText | 0,0,320,16 | "Weapons / Wands / Shields / Pets" | — |
| Label4b | StaticText | 320,0,80,16 | "Hands" | — |
| lstBuffItems | List | 0,16,420,116 | — | `clWeaponName` (TextColumn, 320), `clHandedness` (TextColumn, 80) |
| cmdNewWeapon | PushButton | 10,136,140,16 | "Add" | — |
| cmdNewWeapon_NoBuffs | PushButton | 170,136,140,16 | "Add (no buffs)" | — |
Underlying data table (inferred by column-name match): `BuffedItems`
(`Object`, `Spell` fields — `defaultsettings.usd:14-20`) for the weapon
list; handedness likely a derived/wrapper property, not itself a
`defaultsettings.usd` field.
### Tab: Consumables (8 controls, 3 list columns)
| Control | Type | L,T,W,H | Text | Columns |
|---|---|---|---|---|
| Label7a | StaticText | 0,0,400,16 | "Gems / Food / Kits / Potions / Charges / Grenades / Lockpicks" | — |
| lstExtraBuffItems | List | 0,16,344,116 | — | `clExtraBuffItemsC1` (TextColumn, 320) |
| cmdNewBuffItem | PushButton | 0,136,260,16 | "Add" | — |
| cmdAddAllPeas | PushButton | 264,136,80,16 | "Add All Peas" | — |
| Label7b | StaticText | 448,0,344,16 | "Excluded Scarab Types:" | — |
| lstExcludedComponents | List | 448,16,344,116 | — | `1` (IconColumn, 16 — unnamed/numeric column name, another minor authoring wart), `2` (TextColumn, no fixedwidth → auto-sized) |
| cmdNewExcludedComponent | PushButton | 448,136,344,16 | "Add Selected" | — |
Underlying data (inferred): `GemFoodItems` (`Name`, `Spell`
`defaultsettings.usd:26-31`) for the left list; `BlacklistedSpellComps`
(a bare string-list setting — `defaultsettings.usd:1035-1041`) for the
right list.
### Tab: Buffs (7 controls, 2 list columns)
| Control | Type | L,T,W,H | Text | Columns |
|---|---|---|---|---|
| LabelBPa | StaticText | 0,0,320,16 | "Extra Buff Spells (best similar will be used)" | — |
| lstBuffSpells | List | 0,16,320,116 | — | `clBuff` (TextColumn, 320) |
| cmdNewBuffSpell | PushButton | 10,136,140,16 | "Add..." | — |
| LabelBPb | StaticText | 472,0,320,16 | "Blacklisted Buff Families" | — |
| lstAntiBuffSpells | List | 472,16,320,116 | — | `clBuff` (TextColumn, 320 — **same column name as the left list**, harmless since each `HudList` instance owns its own column namespace) |
| cmdNewAntiBuffSpell | PushButton | 472,136,140,16 | "Add..." | — |
Data tables (confirmed by name): `ExtraBuffSpells` and
`AntiExtraBuffSpells`, both single-field `ExemplarId` tables
(`defaultsettings.usd:1-6,21-25`).
### Tab: Route (20 controls, 2 list columns)
| Control | Type | L,T,W,H | Text | Notes |
|---|---|---|---|---|
| Label5 | StaticText | 0,0,370,16 | "Navigation Waypoints" | |
| lstWaypoints | List | 0,16,370,116 | — | columns `clWP` (TextColumn, 330), `clWPc` (TextColumn, 30) |
| layoutRouteBottomControls | FixedLayout | 0,136,370,16 | — | nested layout, XML comment: "A layout containing stuff below the points list to make resizing easier" |
| cmbNavType | Choice | 0,0,80,16 (nested) | selected=0 | options: Circular / Linear / Follow / Once |
| cmbNavInsertMode | Choice | 198,0,120,16 (nested) | selected=0 | options: Add to End / Insert Above / Insert Below |
| btnNavDown | Button (image) | 322,0,16,16 (nested) | — | image button, `Background=100673789` **[confirmed]** — `PluginCore.cs:1820`; tooltip "Advance Current Point" |
| btnNavUp | Button (image) | 338,0,16,16 (nested) | — | `Background=100673788` **[confirmed]** — `PluginCore.cs:1822`; tooltip "Regress Current Point" |
| btnNavResetPoint | Button (image) | 354,0,16,16 (nested) | — | `Background=100667895` **[confirmed]** — `PluginCore.cs:1824`; tooltip "Select Nearest Point" |
| cmdNewWaypoint | PushButton | 376,16,88,16 | "Add" | |
| cmdNavOpenVendor | PushButton | 470,16,88,16 | "Open Vendor" | |
| cmdNewWaypointPortal | PushButton | 376,38,88,16 | "Add Portal/NPC" | |
| cmdNavUseNPC | PushButton | 470,38,88,16 | "Add NPC Talk" | |
| cmdNewRecall | PushButton | 376,60,88,16 | "Add Recall" | |
| cmbRecallType | Choice | 470,60,120,16 | selected=0 | 27 options: Primary/Secondary/LS/LS Sending/Portal/Aphus/Sanctuary/Caul/GW/Aerlinthe/Mt. Lethe/Ulgrim's/Bur/PtOIA/Graveyard/Colosseum/Fac. Hub/Gear K. Camp/Neftet/Candeth/FacHub/Rynthid/VR Rocks/VR Tree/Soc. CH/Soc. RB/Soc. EW (note: "Fac. Hub" and "FacHub" both present — another authoring duplicate) |
| cmdNewWaypointPause | PushButton | 376,82,88,16 | "Add Pause" | |
| txtPauseWaypointTime | Edit | 470,82,68,16 | "5" | only Edit control in the whole file with a non-empty default `text` |
| Label52 | StaticText | 543,82,50,16 | "seconds" | |
| cmdNewWaypointChat | PushButton | 376,104,88,16 | "Add Chat" | |
| txtChatWaypoint | Edit | 470,104,120,16 | "/ls" | |
The `100673789`/`100673788`/`100667895` background image ids assigned to
the three nav image-buttons decode (subtracting VVS's `0x6000000` DAT
block prefix) to portal.dat indices `0x0A47FD`, `0x0A47FC`,
`0x0A2BF7` — retail DAT icon glyphs, not synthesized art.
### Tab: Meta (5 controls, 6 list columns)
| Control | Type | L,T,W,H | Text | Columns |
|---|---|---|---|---|
| lstMetaRules | List | 0,16,856,116 | — | `clDelete` (IconColumn,16), `clMoveUp` (IconColumn,16), `clMoveDown` (IconColumn,16), `clState` (TextColumn,150), `clCondition` (TextColumn, no fixedwidth → auto-sized), `clAction` (TextColumn, no fixedwidth → auto-sized) |
| cmdMetaCreate | PushButton | 462,136,50,16 | "Create" | |
| lblmetacurrentstate | StaticText | 4,136,136,16 | "Current State:" | bold, left-justified |
| cmbMetaCurrentState | Choice | 140,136,120,16 | selected=0 | one placeholder option `"---"` — populated at runtime from the profile's actual state list |
### Secondary view: AdvancedOptionsView (392×300, icon 9660)
| Control | Type | L,T,W,H | Columns |
|---|---|---|---|
| lOptionList | List | 4,4,260,160 | `clOpt` (TextColumn,180), `clVal` (TextColumn,62) |
| txtInfo | StaticText | 4,188,384,80 | — (description readout for the selected option) |
| txtEditbox | Edit | 4,168,260,16 | — |
| lFilterList | List | 268,4,120,180 | `clEn` (CheckColumn, no fixedwidth), `clSetting` (TextColumn, no fixedwidth) |
This is the raw editor over the full `Settings` table
(`defaultsettings.usd:135-144`: `Setting, Value, Description,
SettingType`) — **137 rows** per the file's own row count
(`defaultsettings.usd:145`), matching MossTank's `mosstank.xml:107`
tooltip text "Select one of Virindi Tank's 137 advanced options."
`lFilterList` is a checklist of `SettingsCategories` bitmask groups
(`defaultsettings.usd:1513-1518`) used to filter `lOptionList`.
### Secondary view: SelfBuffChoiceView (268×236, icon 8241)
| Control | Type | L,T,W,H | Text | Columns |
|---|---|---|---|---|
| lExemplarList | List | 4,4,260,160 | — | `clVal` (TextColumn, no fixedwidth) |
| lblSearch | StaticText | 4,168,384,16 | "Search:" | — |
| txtSearch | Edit | 4,188,260,16 | "" | — |
A simple filtered single-column exemplar picker, opened from the Buffs
tab's "Add..." buttons (`cmdNewBuffSpell`/`cmdNewAntiBuffSpell`) — the
`txtSearch` live-filters `lExemplarList` (loaded twice under two different
obfuscated class names, `e7.cs:108` and `hz.cs:108`, once per "Add..."
button, each with its own filter predicate).
### Secondary view: FriendlyLootEditorView (268×300, icon 8241)
Two-tab `Notebook1`:
| Page | Control | Type | L,T,W,H | Text | Columns |
|---|---|---|---|---|---|
| Rules | LabelA1 | StaticText | 4,2,80,16 | "Loot Rule:" | — |
| Rules | cmbRuleList | Choice | 4,18,240,20 | — | — |
| Rules | LabelA2 | StaticText | 100,140,150,16 | "This page not yet completed." | — |
| Names | LabelB1 | StaticText | 4,2,80,16 | "Name match:" | — |
| Names | LabelB2 | StaticText | 230,2,30,16 | "Exact" | — |
| Names | lNames | List | 4,18,260,180 | — | `clName` (TextColumn,228), `clExact` (CheckColumn,32) |
| Names | LabelB3 | StaticText | 4,200,80,16 | "New name:" | — |
| Names | txtNewName | Edit | 4,212,196,16 | "" | — |
| Names | cExact | Checkbox | 204,212,40,16 | "Ex." checked=true | — |
| Names | bAddName | PushButton | 234,212,30,16 | "Add" | — |
**The "Rules" page is a stub in retail VTank itself** — its own XML
literally reads "This page not yet completed." (`FriendlyLootEditorView.xml:10`).
Only the "Names" (name-match) editor is functional. This is the one place
where our `mosstank.xml`'s loot editor (§5) is **more complete than VTank's
own shipped UI**, since it implements a full rule list with action/priority
editing that VTank never finished.
---
## 2. VVS control semantics to reproduce for parity
| VVS control | Key semantics | Source |
|---|---|---|
| `HudList` | Vertically scrolling grid; every row has the same ordered column set (`cColInfo`: `ControlType`/`Width`/`Name`), each cell is a live child control (`HudStaticText`/`HudCheckBox`/`HudPictureBox`/`HudButton`/`HudTextBox`/nested `HudList`/`HudFixedLayout`/`HudTabView`). **No built-in header row** — the header glyphs seen in `mainView.xml` (F/B/G/I/…) are ordinary `StaticText` controls placed manually above the list at `top=0`, with the list itself starting at `top=16`. Row height defaults to `ControlHeight=16px`; `Padding=1px` (vertical), `WPadding=7px` (horizontal gap between columns), `WPaddingOuter=3px` (left/right list margin). A `0`-width text/button/edit/list/fixedlayout/notebook column auto-sizes: all such columns in one list share the remaining width equally after fixed-width and icon (fixed at declared width) and check (fixed 13px) columns are subtracted. Selection is not built in as a highlighted-row concept — `Click` is a **per-cell** event `delClickedControl(sender, row, col)`, fired from `MouseUp` when the press and release land in the same cell; callers implement "selected row" state themselves. Scrolling is a `HudVScrollBar` child, width from the theme's `VScrollBarButtonSize` (16px in `Float_Theme`), driven by mouse-wheel or drag. | `HudList.cs:14-609` (whole file); `Float_Theme.cs:58` |
| `HudList` column mapping (from progid) | `IconColumn``HudPictureBox` (default 16px), `TextColumn``HudStaticText`, `CheckColumn``HudCheckBox` (fixed 13px regardless of declared width), plus (less commonly used) `FixedLayout``HudFixedLayout`, `Notebook``HudTabView`, `PushButton``HudButton`, `Checkbox``HudCheckBox`, `Edit``HudTextBox`, `StaticText``HudStaticText`, `List``HudList` (nested) | `Decal3XMLParser.cs:257-424` |
| `HudCombo` (`Choice`) | A dropdown: closed state shows the selected item's control (usually a `HudStaticText`) in a `ComboBackground_Unselected` box with a themed up/down arrow (16px square, `arrowrect`). Opening spawns a **separate top-level popup surface** (`DxHud`, its own device/texture, `+1` z-priority above the owning view) sized to `min(item count, 10) * 16px` rows (`m_j=10` fixed max-visible, `dropdownamt`), with its own `HudVScrollBar` if the item count exceeds 10. Selecting an item raises `Change`; closing happens on any click outside the drop rect, or via `FireLostFocus`. `AddItem`/`InsertItem` accept either a raw string (wrapped in a `HudStaticText`) or an arbitrary `HudControl` + opaque tag object — so combo items are not restricted to plain text. | `HudCombo.cs:15-744` |
| `HudTabView` (`Notebook`) | Tab strip height is themed (`TabHeight=16px` in `Float_Theme`). Each tab's width auto-sizes to its caption's rendered text width (capped at 280px) plus themed left/right border sizes (`TabLeftBorder_Size`/`TabRightBorder_Size`, both `0` in `Float_Theme`) plus a themed horizontal padding (`TabTextHPadding=6px`). Selected vs. deselected tabs use **separate font options** (`TabTextFontName/Size/Weight/Color/Shadow*_Selected` vs `_Deselected`). Mouse wheel over the tab strip cycles tabs; over the body it's forwarded to the active child. Only one tab's content control is ever `CanDraw=true` at a time — switching tabs disposes no state, it just flips visibility/draw flags on the existing child controls (so per-tab state survives switching, which matters for MossTank/acdream parity: switching tabs must not reset in-progress edits). | `HudTabView.cs:12-455`; `Float_Theme.cs:91-93` |
| `HudHSlider` (`Slider`) | Backed by `LinearPositionControl` (`Min`/`Max`/`Position`, `Changed(min,max,pos)` event, `Percentage` helper = `100*Position/(Max-Min)`). Draws as a 3px-tall two-tone bar (`SliderBarOuter`/`SliderBarInner`) plus a themed nub (`SliderNubWidth=7px`, `SliderNubHeight=12px` in `Float_Theme`) whose X position is `GetPositionProportionalPixels`. Drag-to-set, click-to-jump-to-position, and mouse-wheel (±1 unit per notch, accumulator-smoothed via `v.a`) are all supported; `UserChangeable=false` disables all three without hiding the control. | `HudHSlider.cs:9-131`, `LinearPositionControl.cs:6-186`, `Float_Theme.cs:54-55` |
| `HudTextBox` (`Edit`) | Single-line text input with a blinking caret (500ms toggle via an internal timer `r`), left/right/Home/End/Backspace/Delete/Ctrl+V (paste from the Windows clipboard) key handling, and an optional numeric-only input mode (`eTextBoxInputType.Int_Numeric`/`Float_Numeric`) that rejects any edit that doesn't `TryParse`. Background is themed (`TextBoxBackground`/`_MouseOver`) with a 1px `ButtonHighlight`/`ButtonShadow` bevel. **The `imageportalsrc="4726"` attribute present on every `Edit` control in `mainView.xml` is never read by `Decal3XMLParser.cs`'s `"decalcontrols.edit"` case** — only `text` is consumed; the parser never sets `HudPictureBox.Image` for an Edit control, and a repo-wide grep of VTank's own source found no other code path assigning it either. This is a **dead/vestigial XML attribute**, likely copy-pasted from an older Decal 3.0 view-XML dialect; acdream's markup does not need to reproduce it. | `HudTextBox.cs:11-417` (esp. `RawKeyAction`/`KeyDown` `260-350`, `DrawNow` `371-416`); parser evidence `Decal3XMLParser.cs:205-212`; dead-attribute confirmed by grep across `refs/vtank/decompiled/` (only hits are the literal XML strings and one string-builder-generated XML fragment in `h8.cs:104`) |
| `HudButton` (`PushButton`) vs. `HudImageButton` (`Button`) | **These are two different progids mapping to two different classes.** `PushButton``HudButton`: text-only push button, themed `ButtonBackground`/`_MouseOver`/`_Down`/`_Down_MouseOver` fills with a 1px bevel, optional `ImagePressed`/`OverlayImage` override. `Button``HudImageButton`: an image-only button taking `iconlibrary` (a portal-dat "icon library" grouping id), `background`/`icon`/`pressedicon` (each resolved via `ACImage.FromIconLibrary` unless the numeric value already looks like a raw image id, per `global::b.d`), and `matte` (a background color override, with `Color.Cyan` specifically mapped to fully transparent). Neither VTank's `mainView.xml` uses `Button` directly (only the three Route-tab nav arrows use it, via VTank's own C# code assigning `.Background` post-construction rather than XML `icon=`/`background=` attributes — see the Route-tab table above) nor does `AdvancedOptionsView.xml`/`FriendlyLootEditorView.xml`. | `HudButton.cs:9-226`; parser `Decal3XMLParser.cs:157-195` (`PushButton`), `:165-195` (`Button`) |
| `HudCheckBox` (`Checkbox`) | Fixed **13×13px** glyph box regardless of the declared control width/height (only the optional trailing label text uses the extra width). Three visual states: unchecked/checked (each with a `_MouseOver` variant) plus a transient "partial" press-feedback state while the mouse is down inside the box. `UserChangeable=false` disables toggling without hiding it. Label text (when present) starts at a fixed `+17px` offset from the left edge. | `HudCheckBox.cs:10-267` |
| `HudControl` (base) | Only left-button `MouseDown`/`MouseUp`/`MouseMove`/`MouseWheel` are wired; there is no right-click or double-click concept anywhere in the base class or in any of the concrete controls surveyed. A `Hit` event fires once per press-then-release-inside-the-same-control. Focus is a single static `HudView.FocusControl` — only one control across the *entire* VVS runtime (all views, all plugins) can have keyboard focus at a time. | `HudControl.cs:13-712` |
---
## 3. Mapping to acdream markup
### 1:1 today
| VVS control | acdream element | Notes |
|---|---|---|
| `PushButton`/`Button` (text) | `<button>` | text + `onclick`; acdream's `<button icon=... iconkind=...>` already covers VVS's image-button case more generally (any of did/spell/item, not just a bare portal-dat icon-library lookup) |
| `Checkbox` | `<toggle>` | `checked`/`onclick`; acdream's is a bound bool with no separate `UserChangeable`-style disable — use the common `enabled` attribute instead |
| `Slider` | `<slider>` | `value`/`onchange`; VVS's `Min`/`Max` are not directly exposed in acdream's `<slider>` today — see gap below |
| `StaticText` | `<label>` | acdream's `color` attribute already generalizes VVS's `textcolor`/`justify`/font options (acdream fixes font via the DAT bitmap font, so per-label font-face/size isn't a parity concern) |
| `Edit` | `<field>` | `text`/`onchange`/`onsubmit`; VVS's numeric-only input mode (`eTextBoxInputType`) has no acdream equivalent yet — not currently exercised by `mainView.xml` (every `Edit` there is `Any`-typed) so not urgent |
| `Notebook` (page tabs) | acdream's existing `<tab>` + one `<group visible=...>` per page (the pattern `mosstank.xml` already uses) | Functionally equivalent to `HudTabView`, but acdream implements it as N independent buttons + N groups rather than one owning control — fine for parity since VVS tab state (selected index) has no behavior beyond visibility toggling anyway |
| `Choice` (dropdown) | `<menu>` | `items`/`selected`/`onchange`; acdream's `rows`/`openupward` attributes already cover VVS's max-10-visible-plus-scrollbar and (implicitly) always-downward-opening behavior — acdream's `openupward` is actually a **superset** of VVS (VVS's `HudCombo` always opens downward from `DropRect`, computed as `base.n.Top` downward with no upward flip) |
### Needs a markup extension
| Gap | What VVS has | What acdream's `<list>` has today | Proposed extension |
|---|---|---|---|
| **Multi-column lists with typed columns** | `HudList`: N columns per row, each independently typed (`TextColumn`/`CheckColumn`/`IconColumn`/nested controls), per-cell `Click(row,col)` | Exactly one text column + one optional icon column (`docs/plugin-ui-markup.md`'s explicit LIMITATION note) | Add a `<column>` child element under `<list>`, e.g.:<br>`<list x= y= w= h= rowheight=17 selected="{Idx}" onchange="{Select}">`<br>` <column type="text" width="120" header="Name" items="{NameCol}"/>`<br>` <column type="check" width="16" header="F" values="{FesterCol}" onchange="{ToggleFesterCol}"/>`<br>` <column type="icon" width="16" iconkind="did" values="{MoveUpIcons}" onclick="{MoveUpCol}"/>`<br>`</list>`<br>Each `<column>` binds its own `IEnumerable<T>` parallel to the row count (mirroring VVS's per-column `cColInfo`), keeping the existing single-column `<list items=...>` form as sugar for a one-`text`-column list (backward compatible with every current markup file). `type="check"`/`type="icon"` columns need their own per-row `onchange`/`onclick` binding returning the row index (VVS's `Click(row,col)` folded into a per-column callback, since acdream's binding model is per-attribute rather than per-cell) |
| **Header row** | Not built into `HudList` at all (VTank places separate `<label>`s above the list, exactly as acdream would today with `<label>` + `<list>`) | N/A — acdream already matches VVS here for free | No extension needed; document the pattern (static `<label>` row above a `<list>`) as the recommended idiom, matching `mainView.xml`'s Monsters-tab header |
| **Dropdown-from-a-list-of-arbitrary-controls** | `HudCombo.AddItem(HudControl, tag)` — combo items aren't restricted to text | acdream's `<menu items="{Strings}">` is text-only | Not worth adding — no VTank tab actually uses a non-text combo item; flagged only for completeness |
| **Slider `Min`/`Max`** | `HudHSlider`/`LinearPositionControl` expose `Min`/`Max` independent of a fixed 0-100 (every VTank slider in `mainView.xml` happens to use `minimum="0" maximum="100"`, but the control supports arbitrary ranges) | acdream's `<slider value=...>` implies an assumed `0.0-1.0` or similar fixed range (needs verification against `MarkupDocument.cs`) | If acdream's slider isn't already range-flexible, add optional `min`/`max` literal attributes (defaulting to today's implicit range) so a 1:1 VTank slider port doesn't need a value-rescaling shim in the plugin's ViewModel layer |
| **Edit-box background image** (`imageportalsrc`) | Present in every VTank `Edit` control's XML, but confirmed dead in VVS itself (see §2) | acdream's `<field background=...>` already exists (a real, live attribute, unlike VVS's dead one) | No extension needed — acdream's `<field background>` is strictly more useful than what VVS actually does with this attribute |
None of the three secondary popup views (`AdvancedOptionsView`,
`SelfBuffChoiceView`, `FriendlyLootEditorView`) need anything beyond the
gaps above — they're smaller compositions of the same List/Edit/Choice/
Checkbox/StaticText primitives.
---
## 4. Window-level facts
Covered in §0 above (kept together with the other numbered items per the
task's own ordering; repeated here only as a pointer since §0 precedes §1
in this document for readability).
---
## 5. The MossTank gap
Comparing `src/AcDream.Plugins.MossTank/mosstank.xml` (586 lines) against
the `mainView.xml` transcription above:
| Area | VTank (`mainView.xml`) | MossTank (`mosstank.xml`) | Assessment |
|---|---|---|---|
| Window size | 856×210 (9-tab strip fits in 210px tall because every tab's content scrolls/paginates within a fixed 116-134px list) | 800×244 (`mosstank.xml:7`) | Deliberately reshaped, not a bug — a few px narrower, ~34px taller; matches acdream's own control metrics (16px checkbox rows read slightly differently in acdream's DAT font vs. VVS's) rather than being a literal port |
| Tab strip | `HudTabView`, one owning control, auto-sized tab widths | 9 independent `<tab>` buttons with hand-picked `x`/`w` per tab (`mosstank.xml:10-27`) | Correct idiom given the gap noted in §3; hand-tuned widths look reasonable against each tab's caption length (spot check: "Consumables" gets `w="86"`, the widest, correctly) |
| Options tab | 4-column layout, single flat page, 37 controls | 4-visual-column layout preserved (`mosstank.xml:29-99`), but **folds VTank's separate `AdvancedOptionsView` popup into an in-panel group** (`AdvancedOptionsVisible`, `mosstank.xml:101-118`) reachable via the same "Advanced Options" button | Deliberate redesign (single-window UX vs. VVS's popup-window pattern), consistent with acdream's plugin panels not each spawning independent OS-level windows. Not a defect — a documented architectural choice |
| Missing controls | — | `cShowLootEditor`'s VTank behavior (open a *separate* `FriendlyLootEditorView` popup) is instead an in-panel `LootEditorVisible` group (`mosstank.xml:519-585`), same pattern as Advanced Options | Consistent design choice, not an omission — and per §1's Loot-Editor table, MossTank's rules editor is functionally **more complete** than VTank's own (VTank's Rules page is a literal stub) |
| Monsters tab — **the real gap** | 14 checkbox columns + 7 text columns, all inline per row in one scrolling grid (23 columns total) | A single-column `<list>` (`mosstank.xml:232-234`) showing pre-formatted text rows, with the 14 boolean flags exposed as **14 separate `<toggle>` controls below the list** (`mosstank.xml:269-282`) that edit only the *currently selected* row | This is the direct consequence of the multi-column-list gap in §3. It's a legitimate current workaround (edit-the-selected-row, rather than edit-any-cell-inline) but loses VTank's at-a-glance grid view (seeing every monster's full flag row without selecting it first). Closing the §3 `<column>` gap would let this tab go back to VTank's original one-row-per-monster grid layout |
| Items/Consumables/Buffs tabs | 2-column (Items), 1-column ×2 (Consumables), 1-column ×2 (Buffs) lists | Single-column lists with padded text rows (comment in `docs/plugin-ui-markup.md:116`: `$"{name,-16}{value,6}"`) | Same root cause as Monsters, smaller blast radius since these VTank lists are only 1-2 columns to begin with — a `<column>` extension would let Items regain its true 2-column (name/handedness) layout, but the workaround here is much less lossy than Monsters' 14-checkbox grid |
| Route/Meta tabs | `lstWaypoints` (2 cols), `lstMetaRules` (2 icon + 4 text = 6 cols, including inline per-row Delete/Up/Down icon buttons) | Single-column padded-text lists (`mosstank.xml:367-369`, `461-463`) with the row-reorder/delete actions pulled out to buttons below the list (`↑`/`↓`/`Remove`, `mosstank.xml:410-415`, `509-512`) | Same selected-row-editor pattern as Monsters — reasonable given the gap, loses VTank's inline per-row icon buttons (click the up-arrow *in that row* vs. select-then-click-a-shared-up-arrow-button) |
| Oversized/undersized controls | n/a (authored, VTank's own values) | Nothing found materially oversized against its own 800×244 canvas; every group is sized to `w="784" h="194"` (leaving room for the 8px margin + tab strip), consistent across all 9 tabs (`mosstank.xml:30,101,122,180,229,291,313,331,365,442,519`) | No sizing defects found |
| Extra controls VTank doesn't have | — | `AdvancedOptionsVisible` and `LootEditorVisible` groups (discussed above) are additions, by design, not accidental scope creep | — |
**Bottom line:** the single architectural gap driving every "lossy"
difference above is the one already flagged in
`docs/plugin-ui-markup.md`'s explicit LIMITATION note — acdream's `<list>`
has no multi-column support. MossTank's current "select a row, edit it with
separate controls below" pattern is a reasonable adaptation to that gap,
not an authoring mistake, and the §3 extension spec would let a future pass
restore VTank's true inline-grid layout for Monsters/Items/Route/Meta
without any other markup change.
---
## 6. Could not determine
- **The exact handler bodies for the majority of the 156 controls.**
`PluginCore.cs` (the class wiring `mainView.xml`) uses single/double-letter
field and method names throughout (an obfuscator artifact, consistent
with `feedback_bn_decomp_field_names.md`'s "heuristic field names, name ≠
semantics" caution, extended here to a *different* decompiler/obfuscator
than the Ghidra/Binary Ninja one that note originally warns about). I
traced specific handlers only where a distinguishing string literal
(a settings-key string, or a numeric `.Background=` assignment) let me
disambiguate one letter-named method from the thousands of others in the
same class (the Vitals-tab sliders, the Route-tab nav-arrow icon ids, the
loot-editor checkbox). For the remaining controls (all of Profiles,
Items, Consumables, Buffs, Route's recall/pause/chat buttons, all of
Meta), the "binds to" column above is a naming-convention inference
against `defaultsettings.usd`/the XML's own control names, not a
traced `file:line` proof.
- **The `clRings`/`clRings` duplicate column's real data field.** The
Monsters-tab list declares two `CheckColumn`s both named `clRings`
(`mainView.xml:121-122`) under a header row that has 9 single-letter
captions (F/B/G/I/Y/V/A/R/S) for what should be 9 *distinct* boolean
columns. Since the 9th column has no unique `name`, I could not determine
from the XML alone whether it silently shadows column 8 (both write the
same `MyMonsters.Ring` field) or is genuinely wired to the 18th
`MyMonsters` field (`Streak`, matching the "S" header) through some
other lookup path VTank's C# code uses instead of the XML `name`. This
reads as a real (if harmless — `HudList.AddColumn` doesn't enforce unique
column names) authoring bug in VTank's own shipped `mainView.xml`.
- **The exact call site that loads `FriendlyLootEditorView.xml`.** Unlike
`AdvancedOptionsView.xml` (`db.cs:79`) and `SelfBuffChoiceView.xml`
(`e7.cs:108`, `hz.cs:108`), a repo-wide string grep for
`FriendlyLootEditorView` across `refs/vtank/decompiled/` returns only the
`.csproj`'s embedded-resource declaration — no `.cs` file references the
resource name as a literal string. It is loaded somewhere (the checkbox
behavior at `PluginCore.cs:6270-6289` proves a loot-editor view object
exists and opens/closes), just not through a call I could locate by
string search; likely a dynamically-built resource-name string or a
differently-obfuscated loader class not distinguishable from its
siblings.
- **VTank's exact on-disk schema for per-character nav/loot/meta/settings
*profile* documents** (as opposed to the global `defaultsettings.usd`
default-value catalog, which I did read in full). `cmbSettingsSet`/
`cmbNavSet`/`cmbLootSet`/`cmbMetaSet` clearly select among named,
persisted profiles, and `lstWaypoints`/`lstMetaRules`/loot rules are
per-profile row data, but none of that per-profile storage format is
present under `refs/vtank/` — only the default/template values are.
- **Whether VVS's numeric-input `HudTextBox` mode
(`eTextBoxInputType.Int_Numeric`/`Float_Numeric`) is used anywhere in
`mainView.xml`.** The XML attribute space has no field for input-type
(it's set programmatically post-construction, if at all), and I did not
find a `PluginCore.cs` line setting `.InputType`/equivalent on any of the
wrapped `ITextBox` instances within the effort budget for this pass —
flagged as low-priority since every `Edit` control observed accepts
free-form text either way (VTank does its own string→number parsing on
submit rather than relying on VVS to reject bad input at the keystroke
level, going by the numeric fields' plain-`Edit` progid with no visible
extra attribute).