fix(vtank): slice 7 round E item D-3 — Advanced Options popup actually resizable
mosstank.xml's own top-of-file comment already claimed the Advanced Options popup "gets its own resizable=\"true\" + anchored lists" — the popup file itself still carried the dead resize="none" attribute (MarkupDocument.cs: "resize" only ever means anything once resizable="true" already arms the master switch), so the claim was false and the popup was permanently fixed-size. resizable="true" now floors minw/minh at the pre-fix authored size (392x450 — never shrink below the tested layout, matching the main panel's own rule). lOptionList grows WIDTH ONLY: the value-edit field, description, and notice all sit directly below it with zero vertical slack and none of them anchor to shift down in lockstep, so any height growth here would walk the list straight into the field below — the same "grow only in the direction with nothing in the way" principle the main panel already applies to Items/Consumables/Buffs/Route's lists. lFilterList (the category checklist beside it) tracks the growing right edge via its own anchor="right" so the widening option list never walks into it, matching the main panel's own right-pinned-sibling pattern. AdvancedOptionDescription is declared anchor="left top right" for markup consistency, but documented as a real no-op: UiLabel.OnDraw (UiPanel.cs) always overwrites Width/Height to the current measured text extent on every draw, right after the anchor pass runs in the same frame, so nothing a label's anchor computes is ever visible — a genuinely working vertical anchor was deliberately avoided since the notice label directly below isn't anchored either and a large resize would walk description into it; fully anchoring the rest of the vertical stack is a larger redesign left for a future round. Mutation shown to fail first: reverting the markup (git checkout, patch saved and reapplied) failed at Assert.True(built.Resizable) — the popup was still fixed-size. App markup/plugin filter 243 -> 244; MossTank suite holds 721/721 (this item touches App-side markup only). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
3fe3043599
commit
64b62fea33
2 changed files with 115 additions and 5 deletions
|
|
@ -97,10 +97,51 @@
|
|||
+/- stepper (a real duplicate of Options' own editable
|
||||
FollowNavMinimumValueText field). Bold text isn't representable in the
|
||||
plain retail UI font (0x40000000 has no bold face) — the section
|
||||
header uses the same bright caption color other headers use instead. -->
|
||||
header uses the same bright caption color other headers use instead.
|
||||
|
||||
D-3 (round E architecture re-check): mosstank.xml's own top-of-file
|
||||
comment already claimed this popup "gets its own resizable=\"true\" +
|
||||
anchored lists" — this file never actually carried that; "resize" is a
|
||||
vestigial axis-lock attribute that only means anything once
|
||||
resizable="true" already arms the master switch (MarkupDocument.cs),
|
||||
so resize="none" alone left the popup permanently fixed-size. Now
|
||||
resizable="true" with minw/minh floored at the pre-fix authored size
|
||||
(392x450, the same "never shrink below the tested layout" rule the
|
||||
main panel's own minw/minh follow).
|
||||
|
||||
lOptionList grows WIDTH ONLY (anchor="left top right"), NOT height:
|
||||
the value-edit field/description/notice/"MossTank Extras" section all
|
||||
sit directly below it with no vertical slack (field starts at y=168,
|
||||
4px under the list's own y=4+h=164) and none of them are anchored to
|
||||
shift down in lockstep, so any HEIGHT growth here would walk the list
|
||||
straight into the field below it — the main panel's own
|
||||
Items/Consumables/Buffs/Route lists avoid exactly this by growing
|
||||
height-only where nothing sits below, and by growing WIDTH-only here
|
||||
instead, this popup gets the same "the growth direction with nothing
|
||||
in its path" safety. lFilterList (the category checklist, sitting
|
||||
immediately to the option list's right) is repositioned to track the
|
||||
right edge via its own anchor="right" so the widening option list
|
||||
never grows into it — the same "right-pinned sibling repositions"
|
||||
pattern the main panel's Consumables/Buffs lists already use.
|
||||
|
||||
AdvancedOptionDescription is declared anchor="left top right" too, for
|
||||
markup consistency with the option list above it, but this is a
|
||||
documented NO-OP for a <label>: UiLabel.OnDraw (UiPanel.cs) always
|
||||
overwrites Width/Height to the CURRENT measured text extent on every
|
||||
single draw, immediately after the parent's own anchor pass runs (both
|
||||
happen inside the same DrawSelfAndChildren frame) — so whatever a
|
||||
label's anchor computes is discarded before it is ever visible. A
|
||||
genuinely working vertical anchor (e.g. "bottom", tracking the growing
|
||||
window edge) was deliberately NOT used here either: with the notice
|
||||
label directly below it also unanchored, a large enough resize would
|
||||
walk description right into notice — the same class of risk this
|
||||
round avoided for the option list. Anchoring the rest of the vertical
|
||||
stack in lockstep is a real, larger redesign left for a future round;
|
||||
this one stays inside "make it actually resizable without introducing
|
||||
a new overlap," per the round's own stated scope. -->
|
||||
<panel x="253" y="405" w="392" h="450" title="MossTank Advanced Options"
|
||||
visible="{AdvancedOptionsVisible}" resize="none">
|
||||
<list x="4" y="4" w="256" h="160" rowheight="17"
|
||||
visible="{AdvancedOptionsVisible}" resizable="true" minw="392" minh="450">
|
||||
<list x="4" y="4" w="256" h="160" rowheight="17" anchor="left top right"
|
||||
selected="{SelectedAdvancedOptionIndex}" onchange="{SelectAdvancedOption}"
|
||||
tooltip="Select one of Virindi Tank's 137 advanced options.">
|
||||
<column type="text" width="187" items="{AdvancedOptionNames}" onclick="{SelectAdvancedOption}" />
|
||||
|
|
@ -110,7 +151,7 @@
|
|||
bug here: <list> markup requires a "selected" int binding even for a
|
||||
pure checklist with no real selection concept — see
|
||||
SelectedAdvancedOptionCategoryIndex's own doc comment. -->
|
||||
<list x="268" y="4" w="120" h="180" rowheight="18"
|
||||
<list x="268" y="4" w="120" h="180" rowheight="18" anchor="right"
|
||||
selected="{SelectedAdvancedOptionCategoryIndex}"
|
||||
tooltip="Uncheck a category to hide its settings from the list on the left.">
|
||||
<column type="check" width="20" values="{AdvancedOptionCategoryEnabled}" onchange="{ToggleAdvancedOptionCategoryAt}" />
|
||||
|
|
@ -120,7 +161,8 @@
|
|||
onchange="{SetAdvancedOptionValueDraft}" onsubmit="{SubmitAdvancedOption}"
|
||||
maxlength="160" clearonsubmit="false" background="#E6000000"
|
||||
tooltip="Edit the selected advanced-option value and press Enter to apply." />
|
||||
<label x="4" y="188" w="384" h="80" text="{AdvancedOptionDescription}" color="#FFE8DEC3" />
|
||||
<label x="4" y="188" w="384" h="80" text="{AdvancedOptionDescription}" color="#FFE8DEC3"
|
||||
anchor="left top right" />
|
||||
<label x="4" y="272" w="384" h="16" text="{AdvancedOptionNotice}" color="#FFC7B98F" />
|
||||
|
||||
<label x="4" y="294" w="200" h="16" text="MossTank Extras" color="#FFE8DEC3" />
|
||||
|
|
|
|||
|
|
@ -113,6 +113,74 @@ public sealed class MossTankMarkupBuildOverRealFilesTests
|
|||
$"Monsters list width did not grow: {widthAtAuthoredDefault} -> {monstersList.Width}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// D-3 (round E architecture re-check): mosstank.xml's own top-of-file
|
||||
/// comment already claimed the Advanced Options popup "gets its own
|
||||
/// resizable=\"true\" + anchored lists" — the popup file itself still
|
||||
/// carried the dead <c>resize="none"</c> attribute (only meaningful
|
||||
/// once <c>resizable="true"</c> already arms the master switch,
|
||||
/// MarkupDocument.cs), so the popup was permanently fixed-size. This
|
||||
/// proves the fix through the real anchor machinery (the same
|
||||
/// mechanism <see cref="WideningTheRealMainPanelWidensTheRealMonstersList"/>
|
||||
/// proves for the main panel): lOptionList grows in WIDTH ONLY
|
||||
/// (mosstank-advanced.xml's own comment explains why height growth is
|
||||
/// unsafe here — the value field sits directly below with no slack),
|
||||
/// and lFilterList tracks the growing right edge in lockstep so the
|
||||
/// widening option list never walks into it (the same "right-pinned
|
||||
/// sibling repositions" pattern the main panel already uses).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void WideningTheRealAdvancedOptionsPopupGrowsTheOptionListWithoutOverlappingItsSibling()
|
||||
{
|
||||
string xml = File.ReadAllText(
|
||||
Path.Combine(MossTankMarkupDirectory, "mosstank-advanced.xml"));
|
||||
var panel = new MossTankPanel(new StubHost());
|
||||
|
||||
UiNineSlicePanel built = MarkupDocument.Build(xml, panel, static id => (id, 32, 32));
|
||||
|
||||
Assert.True(built.Resizable);
|
||||
Assert.Equal(392f, built.MinWidth);
|
||||
Assert.Equal(450f, built.MinHeight);
|
||||
|
||||
// Bypass the VisibleSource binding (bound to AdvancedOptionsVisible,
|
||||
// false on the stub automation) the same way the Monsters test
|
||||
// bypasses tab visibility — DrawSelfAndChildren's own anchor pass
|
||||
// never runs for an invisible element.
|
||||
built.Visible = true;
|
||||
|
||||
UiMarkupList optionList = Assert.Single(
|
||||
built.Children.OfType<UiMarkupList>(), static list => list.Width == 256f);
|
||||
UiMarkupList categoryList = Assert.Single(
|
||||
built.Children.OfType<UiMarkupList>(), static list => list.Width == 120f);
|
||||
|
||||
var device = new RecordingGpuDevice();
|
||||
var renderer = new TextRenderer(device, new NullGpuFrameSource(), "unused");
|
||||
renderer.Begin(new Vector2(1400f, 900f));
|
||||
var ctx = new UiRenderContext(renderer, new Vector2(1400f, 900f));
|
||||
|
||||
built.DrawSelfAndChildren(ctx);
|
||||
float optionListWidthBefore = optionList.Width;
|
||||
float optionListHeightBefore = optionList.Height;
|
||||
float categoryListLeftBefore = categoryList.Left;
|
||||
float categoryListWidthBefore = categoryList.Width;
|
||||
|
||||
built.Width += 100f;
|
||||
built.DrawSelfAndChildren(ctx);
|
||||
|
||||
Assert.True(
|
||||
optionList.Width > optionListWidthBefore,
|
||||
$"Option list width did not grow: {optionListWidthBefore} -> {optionList.Width}");
|
||||
Assert.Equal(optionListHeightBefore, optionList.Height); // height fixed
|
||||
Assert.True(
|
||||
categoryList.Left > categoryListLeftBefore,
|
||||
$"Category list did not track the growing right edge: {categoryListLeftBefore} -> {categoryList.Left}");
|
||||
Assert.Equal(categoryListWidthBefore, categoryList.Width); // width fixed, only repositions
|
||||
Assert.True(
|
||||
optionList.Left + optionList.Width <= categoryList.Left,
|
||||
$"Widened option list (right edge {optionList.Left + optionList.Width}) overlaps "
|
||||
+ $"the repositioned category list (left edge {categoryList.Left}).");
|
||||
}
|
||||
|
||||
private sealed class NullGpuFrameSource : ICurrentGpuFrameSource
|
||||
{
|
||||
public IGpuFrame? CurrentFrame => null;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue