fix(vtank): slice 7 round F item 6 — Buffs gap, Loot Editor Back, Route count column
Three small resemblance-re-check nits. Buffs: the extras strip (toggles/Difficulty/Rebuff/Buff button, no VTank counterpart) stayed at its pre-Round-D x=332 while Round D item 4's own +128 right-anchor shift moved the Blacklisted Buff Families list from x=524 to x=652 — an 8px left margin against a 138px right margin. Discovered a hard geometric ceiling while fixing this: Extra Buff Spells never moves (anchor="left top bottom", pinned x=4..324) but Blacklisted Buff Families tracks the growing right edge, sitting at x=524 at the panel's own tested FLOOR (856x236) and x=652 at the 984-wide enlarged default — a 128px swing. A single fixed-position strip can only be centered against ONE of those widths; centering against the 984 default (tried x=397 first) put the strip's right edge 55px inside where the list sits at the floor — a real overlap the existing ResolvedMainPanelHasNoOverlapOrOutOfBoundsChildAtThisSize pin (856x236 case) caught immediately. x=333 is the widest safe position (9px margins against the floor's 324..524 gap) — 1px from where fix round B item 2 already had it. The residual 984-default asymmetry (~9/137, barely changed from ~8/138) is an accepted, unavoidable- without-a-redesign limitation, the same "dead margin, polish later" trade already accepted for six other tabs at this size. Coverage moved from y=213 (anchored to the group's bottom edge, a real 55px empty hole once the panel grew past its original 194-tall size) to sit directly under the Buff button row (y=176, no anchor). Loot Editor: dropped the leftover standalone "Back" button — the window's own OS-level title bar already closes it, matching every other plugin popup (Advanced Options included) since round D. CloseLootEditor stays real, still called by ToggleLootEditorVisible. Route: the waypoint grid's count column (declared width="30") was the grid's LAST column, so docs/plugin-ui-markup.md's own "Width semantics" rule made that declared width never validated/used — it silently absorbed whatever remainder was left (33px normally, but only 17px once the scrollbar's 16px reservation ate into the list's own 370px width, since 337+30 already exceeded 370-16=354). A trailing filler column alone wasn't sufficient — proved by a targeted mutation below — since even non-last, a truly fixed 30px column still gets clamped by the same 354px ceiling. The real text column narrows 337->324 (324+30=354, exactly matching the scrollbar-reduced width) so the count column gets its full 30px whether or not the scrollbar shows. Every new/changed pin shown to fail against a targeted mutation first: LootEditorHasNoLeftoverBackButton failed with the button re-inserted, then passed once removed. RouteShapedGrid_CountColumnStaysThirtyPxWhen TheListScrolls (a synthetic list matching Route's real 370/324/30/* shape, 9 rows forcing the scrollbar, reflecting into UiMarkupList's own _cachedLayout) failed both against the original 2-column 337/30 shape (17px, reproducing the reported squeeze) AND against filler-only-no- narrowing (also 17px, proving the filler alone isn't the fix), then passed at exactly 30px once both changes landed together. BuffsExtrasStripIsCenteredAtThePanelsFloorAndCoverageSitsUnderTheButtonRow and its App-side resolved-tree counterpart BuffsExtrasStripStaysCenteredAndNonOverlappingAtTheFloor pin the floor-centered position and the Coverage gap. MossTank suite 725 -> 726 (one new pin); App markup/plugin filter 260 -> 262 (two new pins). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
bae34aaa8b
commit
8376105936
6 changed files with 312 additions and 32 deletions
|
|
@ -1040,6 +1040,18 @@ internal sealed partial class MossTankPanel
|
|||
// PluginCore.cs:3576-3599 — any cell click deletes the waypoint).
|
||||
public IReadOnlyList<string> RouteWaypointTextColumn => _routeRows;
|
||||
public IReadOnlyList<string> RouteWaypointCountColumn => _routeWaypointCounts;
|
||||
// Round F item 6 (resemblance re-check: "Route's count column
|
||||
// squeezes to 17 when the list scrolls"): RouteWaypointCountColumn
|
||||
// was the grid's LAST column, so docs/plugin-ui-markup.md's own
|
||||
// "Width semantics" rule made its declared width="30" NEVER validated
|
||||
// or used — it silently absorbed whatever remainder was left instead
|
||||
// (33px normally, but only 17px once the scrollbar's own 16px
|
||||
// reservation ate into that remainder). A trailing filler column
|
||||
// (empty items) now sits after it so the count column is no longer
|
||||
// last and keeps its own real, always-honored 30px width — the same
|
||||
// fix as the Monsters grid's MonsterFillerColumn.
|
||||
public IReadOnlyList<string> RouteWaypointFillerColumn => Array.Empty<string>();
|
||||
public Action<int> RouteWaypointFillerClick => static _ => { };
|
||||
public Action<int> DeleteRouteWaypointAt => DeleteRouteWaypointAtCore;
|
||||
public Action SelectNearestRouteWaypoint => SelectNearestRouteWaypointCore;
|
||||
// VTank's own cmbNavType captions read Circular/Linear/Follow/Once
|
||||
|
|
|
|||
|
|
@ -13,11 +13,20 @@
|
|||
panel, registered as a THIRD AddPanel call from MossTankPlugin.cs with
|
||||
ShowInSidePanel=false (VTank's popup has no independent shelf entry). This
|
||||
panel's own visible="{LootEditorVisible}" binding is the SAME flag the
|
||||
checkbox flips and this popup's own "Back" button clears
|
||||
checkbox flips and CloseLootEditor clears
|
||||
(CloseLootEditor => _lootEditorVisible = false) — closing the popup
|
||||
unchecks the box for free (see mosstank-advanced.xml's comment for why no
|
||||
new host show/hide API was needed).
|
||||
|
||||
Round F item 6 (resemblance re-check: "Loot Editor: drop the leftover
|
||||
'Back' button — the window closes from its title bar like the
|
||||
others"): the standalone "Back" button bound directly to
|
||||
CloseLootEditor is gone — the window's own OS-level title bar already
|
||||
closes it, the same shape every other plugin popup (Advanced Options
|
||||
included) has used with no Back button of its own since round D.
|
||||
CloseLootEditor stays real: ToggleLootEditorVisible (the Profiles-tab
|
||||
"Show Editor" checkbox's own close path) still calls it directly.
|
||||
|
||||
Fix round A also replaced the "↑"/"↓" text buttons (MoveLootRuleUp/Down)
|
||||
with the same DAT move-up/move-down icon glyphs the Monsters grid already
|
||||
uses (0x060028FC / 0x060028FD) — the retail default UI font (0x40000000)
|
||||
|
|
@ -40,8 +49,6 @@
|
|||
-->
|
||||
<panel x="660" y="405" w="268" h="300" title="MossTank Loot Editor"
|
||||
visible="{LootEditorVisible}" resize="none">
|
||||
<button x="198" y="2" w="64" h="18" text="Back"
|
||||
onclick="{CloseLootEditor}" />
|
||||
<field x="4" y="22" w="260" h="18" text="{LootProfileNameDraft}"
|
||||
onchange="{SetLootProfileNameDraft}"
|
||||
onsubmit="{CreateNamedLootProfile}" maxlength="64"
|
||||
|
|
|
|||
|
|
@ -582,13 +582,42 @@
|
|||
catches. Both lists are restored to VTank's full 320x116 at the far
|
||||
left (x=4) and far right (x=524, 848-4-320) with their own
|
||||
120-wide "Add..." row below each list; the whole MossTank-extras
|
||||
block moves into the EMPTY MIDDLE strip between the two lists
|
||||
(x=332..516, the 184px VTank's own layout never uses), stacked
|
||||
compactly: 7 toggles at a 16px pitch, then Difficulty +/-, then
|
||||
Rebuff +/-, then the Buff button + status, then Coverage at y=178
|
||||
(194-16, item 3's bottom-fit rule) — a proportion-preserving
|
||||
compromise fitting a real 184x194 box, not a pixel-for-pixel VVS
|
||||
port (owner's bar: "looks basically the same", never VVS pixels). -->
|
||||
block moves into the EMPTY MIDDLE strip between the two lists,
|
||||
stacked compactly: 7 toggles at a 16px pitch, then Difficulty +/-,
|
||||
then Rebuff +/-, then the Buff button + status, then Coverage
|
||||
right under it — a proportion-preserving compromise fitting a
|
||||
real box, not a pixel-for-pixel VVS port (owner's bar: "looks
|
||||
basically the same", never VVS pixels).
|
||||
|
||||
Round F item 6 (resemblance re-check: "Buffs' 136 px middle gap
|
||||
and the orphaned Coverage label"). Coverage moved from y=213
|
||||
(anchored to the group's bottom edge, a real 55px empty hole
|
||||
above it once the panel grew past its original 194-tall size) to
|
||||
sit directly under the Buff button row instead — no anchor, since
|
||||
nothing below it needs the space that anchor used to protect.
|
||||
|
||||
The middle-gap half of this item turned out to have a hard
|
||||
geometric ceiling: Extra Buff Spells never moves (anchor="left
|
||||
top bottom", pinned at x=4..324) but Blacklisted Buff Families
|
||||
tracks the growing right edge (anchor="right"), sitting at
|
||||
x=524 at the panel's own tested floor (856x236, PanelIsResizable
|
||||
FlooredAtThePreRoundDAuthoredSize) and x=652 at the 984-wide
|
||||
enlarged default — a 128px swing. The extras strip (182px wide)
|
||||
is a single FIXED position, so it can only be centered relative
|
||||
to ONE of those two widths; centering it against the 984 default
|
||||
(x=397) put its right edge at 579, 55px INSIDE where the same
|
||||
list sits at the floor (524) — a real overlap
|
||||
ResolvedMainPanelHasNoOverlapOrOutOfBoundsChildAtThisSize's own
|
||||
856x236 case catches. x=333 is the strip's floor-centered
|
||||
position (9px margin on both sides against the floor's 324..524
|
||||
gap, the widest safe position a fixed strip can take) — the same
|
||||
position fix round B item 2 effectively already used (x=332, 1px
|
||||
off from exactly centered) before Round D's enlargement existed.
|
||||
The residual asymmetric gap at the 984 default (previously ~8/138,
|
||||
now ~9/137) is therefore an accepted, unavoidable-without-a-
|
||||
redesign limitation — the same "dead margin, polish later" trade
|
||||
the resemblance re-check already accepted for six other tabs at
|
||||
this same enlarged size. -->
|
||||
<group x="8" y="42" w="976" h="229" visible="{BuffsVisible}" anchor="left top right bottom">
|
||||
<!-- Fix round B item 14 (owner honesty rule): BuffPlan.Build does not
|
||||
read this set at all yet — a real, tracked wiring gap (see
|
||||
|
|
@ -616,39 +645,39 @@
|
|||
onchange="{DeleteBlacklistedBuffFamilyAt}" tooltip="Click a row to remove it." />
|
||||
<button x="652" y="173" w="120" h="18" text="Add..." onclick="{ShowBlacklistedBuffPicker}" anchor="right bottom" />
|
||||
|
||||
<toggle x="332" y="0" w="180" h="16" text="Trained skills only"
|
||||
<toggle x="333" y="0" w="180" h="16" text="Trained skills only"
|
||||
checked="{TrainedOnlyEnabled}" onclick="{ToggleTrainedOnly}" />
|
||||
<toggle x="332" y="16" w="180" h="16" text="Attributes"
|
||||
<toggle x="333" y="16" w="180" h="16" text="Attributes"
|
||||
checked="{AttributesEnabled}" onclick="{ToggleAttributes}" />
|
||||
<toggle x="332" y="32" w="180" h="16" text="Protections"
|
||||
<toggle x="333" y="32" w="180" h="16" text="Protections"
|
||||
checked="{ProtectionsEnabled}" onclick="{ToggleProtections}" />
|
||||
<toggle x="332" y="48" w="180" h="16" text="Weapon auras"
|
||||
<toggle x="333" y="48" w="180" h="16" text="Weapon auras"
|
||||
checked="{AurasEnabled}" onclick="{ToggleAuras}" />
|
||||
<toggle x="332" y="64" w="180" h="16" text="Armor banes"
|
||||
<toggle x="333" y="64" w="180" h="16" text="Armor banes"
|
||||
checked="{BanesEnabled}" onclick="{ToggleBanes}" />
|
||||
<toggle x="332" y="80" w="180" h="16" text="Regeneration"
|
||||
<toggle x="333" y="80" w="180" h="16" text="Regeneration"
|
||||
checked="{RegenerationEnabled}" onclick="{ToggleRegeneration}" />
|
||||
<toggle x="332" y="96" w="180" h="16" text="Other self-spells"
|
||||
<toggle x="333" y="96" w="180" h="16" text="Other self-spells"
|
||||
checked="{OtherEnabled}" onclick="{ToggleOther}" />
|
||||
|
||||
<label x="332" y="116" w="140" text="{DifficultyText}" color="#FFE8DEC3" />
|
||||
<button x="472" y="112" w="20" h="18" text="-" onclick="{DifficultyDown}"
|
||||
<label x="333" y="116" w="140" text="{DifficultyText}" color="#FFE8DEC3" />
|
||||
<button x="473" y="112" w="20" h="18" text="-" onclick="{DifficultyDown}"
|
||||
tooltip="Decrease the skill-over-difficulty margin." />
|
||||
<button x="494" y="112" w="20" h="18" text="+" onclick="{DifficultyUp}"
|
||||
<button x="495" y="112" w="20" h="18" text="+" onclick="{DifficultyUp}"
|
||||
tooltip="Increase the skill-over-difficulty margin." />
|
||||
<label x="332" y="136" w="140" text="{RebuffText}" color="#FFE8DEC3" />
|
||||
<button x="472" y="132" w="20" h="18" text="-" onclick="{RebuffDown}"
|
||||
<label x="333" y="136" w="140" text="{RebuffText}" color="#FFE8DEC3" />
|
||||
<button x="473" y="132" w="20" h="18" text="-" onclick="{RebuffDown}"
|
||||
tooltip="Rebuff later." />
|
||||
<button x="494" y="132" w="20" h="18" text="+" onclick="{RebuffUp}"
|
||||
<button x="495" y="132" w="20" h="18" text="+" onclick="{RebuffUp}"
|
||||
tooltip="Rebuff earlier." />
|
||||
|
||||
<button x="332" y="154" w="110" h="18" text="{BuffButtonText}" onclick="{Buff}" />
|
||||
<label x="446" y="158" w="70" text="{BuffStatus}" color="#FFC7B98F" />
|
||||
<!-- Round D item 4: the "bottom-fit rule" the original comment names
|
||||
(194-16) now targets the enlarged group's own bottom edge
|
||||
(229-16), anchor="bottom" so a further manual resize keeps it
|
||||
pinned there. -->
|
||||
<label x="332" y="213" w="184" h="16" text="{Coverage}" color="#FF9B9072" anchor="bottom" />
|
||||
<button x="333" y="154" w="110" h="18" text="{BuffButtonText}" onclick="{Buff}" />
|
||||
<label x="447" y="158" w="70" text="{BuffStatus}" color="#FFC7B98F" />
|
||||
<!-- Round F item 6: sits right under the button row above (154+18=172,
|
||||
+4px) instead of anchored to the group's bottom edge — the
|
||||
anchor used to leave a growing empty hole (55px at the enlarged
|
||||
984-wide default) between this label and the row it belongs to. -->
|
||||
<label x="333" y="176" w="184" h="16" text="{Coverage}" color="#FF9B9072" />
|
||||
</group>
|
||||
|
||||
<!-- Route: VTank's own 2-across button grid, row order, and bottom
|
||||
|
|
@ -657,7 +686,13 @@
|
|||
verbatim, +4px left margin for our own convention). The waypoint
|
||||
list is VTank's own clWP/clWPc 2-column grid (Campaign VT S7.5;
|
||||
PluginCore.cs:3576-3599 — any cell click deletes the waypoint).
|
||||
PITCH: text 330+7=337, count (last column) auto.
|
||||
PITCH: text was 330+7=337, count 23+7=30. Round F item 6 narrowed
|
||||
text to 324 (337+30=367 already exceeded this list's own
|
||||
w=370 minus the scrollbar's 16px reservation — 354 — so count
|
||||
was clamped to 17px the moment the list actually needed to
|
||||
scroll) and appended a third, trailing filler column so count is
|
||||
no longer the grid's LAST column and keeps its declared 30px
|
||||
honored instead of silently absorbed/starved.
|
||||
|
||||
MossTank-only extras that have no VTank Route-tab counterpart moved
|
||||
to the Advanced Options popup's own "MossTank Extras" section:
|
||||
|
|
@ -686,8 +721,19 @@
|
|||
<list x="4" y="16" w="370" h="151" rowheight="17" anchor="left top bottom"
|
||||
selected="{SelectedRouteWaypointIndex}" onchange="{SelectRouteWaypoint}"
|
||||
tooltip="Click a waypoint to remove it.">
|
||||
<column type="text" width="337" items="{RouteWaypointTextColumn}" onclick="{DeleteRouteWaypointAt}" />
|
||||
<column type="text" width="324" items="{RouteWaypointTextColumn}" onclick="{DeleteRouteWaypointAt}" />
|
||||
<column type="text" width="30" items="{RouteWaypointCountColumn}" onclick="{DeleteRouteWaypointAt}" />
|
||||
<!-- Round F item 6: a trailing filler so the count column above is
|
||||
no longer the grid's LAST column and keeps its own real 30px
|
||||
width instead of silently absorbing whatever's left. The text
|
||||
column is also narrowed 337->324: 324+30=354 exactly matches
|
||||
this list's own w=370 minus the scrollbar's 16px reservation,
|
||||
so the count column gets its full 30px whether or not the
|
||||
scrollbar is showing — previously 337+30=367 already exceeded
|
||||
354, so the count column was clamped to 17px the moment the
|
||||
list actually needed to scroll, no matter which column was
|
||||
"last". -->
|
||||
<column type="text" width="*" items="{RouteWaypointFillerColumn}" onclick="{RouteWaypointFillerClick}" />
|
||||
</list>
|
||||
|
||||
<menu x="4" y="171" w="80" h="16" items="{RouteModeNames}" anchor="bottom"
|
||||
|
|
|
|||
|
|
@ -1460,6 +1460,58 @@ public sealed class MarkupListColumnsTests
|
|||
Assert.Equal(new[] { 0 }, binding.ActionClicks);
|
||||
}
|
||||
|
||||
private sealed class RouteShapedBinding
|
||||
{
|
||||
public IReadOnlyList<string> Names { get; } =
|
||||
Enumerable.Range(0, 9).Select(static i => $"WP{i}").ToArray();
|
||||
public IReadOnlyList<string> Counts { get; } =
|
||||
Enumerable.Range(0, 9).Select(static i => i.ToString()).ToArray();
|
||||
public IReadOnlyList<string> Filler { get; } = Array.Empty<string>();
|
||||
public int Selected { get; set; } = -1;
|
||||
public Action<int> Click => static _ => { };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round F item 6 (resemblance re-check: "Route's count column
|
||||
/// squeezes to 17 when the list scrolls"). Mirrors the Route tab's
|
||||
/// EXACT real shape (mosstank.xml: a 370px-wide list, columns
|
||||
/// 324/30/*) with enough rows (9, past the 151/17≈8 visible-row
|
||||
/// ceiling) to force the scrollbar — the count column's declared
|
||||
/// 30px was previously only honored while the scrollbar was hidden;
|
||||
/// with it showing, 337(the OLD text width)+30 already exceeded
|
||||
/// 370-16=354, clamping the count column to 17px. Reflects into
|
||||
/// UiMarkupList's own cached column layout (the same one
|
||||
/// DrawColumns/OnEventColumns use) rather than measuring glyphs —
|
||||
/// this is a pure geometry question, no font involved.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void RouteShapedGrid_CountColumnStaysThirtyPxWhenTheListScrolls()
|
||||
{
|
||||
var binding = new RouteShapedBinding();
|
||||
const string xml =
|
||||
"<panel x=\"0\" y=\"0\" w=\"400\" h=\"200\">" +
|
||||
"<list x=\"0\" y=\"0\" w=\"370\" h=\"151\" rowheight=\"17\" " +
|
||||
"selected=\"{Selected}\">" +
|
||||
" <column type=\"text\" width=\"324\" items=\"{Names}\" onclick=\"{Click}\"/>" +
|
||||
" <column type=\"text\" width=\"30\" items=\"{Counts}\" onclick=\"{Click}\"/>" +
|
||||
" <column type=\"text\" width=\"*\" items=\"{Filler}\"/>" +
|
||||
"</list></panel>";
|
||||
|
||||
var panel = MarkupDocument.Build(xml, binding, Sprite);
|
||||
var list = Assert.IsType<UiMarkupList>(panel.Children[0]);
|
||||
|
||||
var (renderer, ctx) = MakeContext(800f, 400f);
|
||||
list.DrawSelfAndChildren(ctx);
|
||||
|
||||
System.Reflection.FieldInfo layoutField = typeof(UiMarkupList).GetField(
|
||||
"_cachedLayout",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!;
|
||||
var layout = ((float x, float w)[])layoutField.GetValue(list)!;
|
||||
|
||||
Assert.Equal(3, layout.Length);
|
||||
Assert.Equal(30f, layout[1].w, 3);
|
||||
}
|
||||
|
||||
private sealed class MonsterShapedBinding
|
||||
{
|
||||
public IReadOnlyList<bool> Checks { get; } = new[] { true, false };
|
||||
|
|
|
|||
|
|
@ -254,6 +254,73 @@ public sealed class MossTankMarkupBuildOverRealFilesTests
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round F item 6 (resemblance re-check: "Buffs' 136 px middle gap").
|
||||
/// <see cref="ResolvedMainPanelHasNoOverlapOrOutOfBoundsChildAtThisSize"/>
|
||||
/// already proves the extras strip never overlaps the Blacklisted
|
||||
/// Buff Families list at the floor or the enlarged size (that generic
|
||||
/// sibling-overlap pass is exactly what caught the original x=397
|
||||
/// attempt at true 984-default centering colliding with the list's
|
||||
/// own floor position, x=524). This is the narrower, POSITIVE claim
|
||||
/// that overlap pass alone doesn't make: the strip is actually
|
||||
/// CENTERED at the panel's floor (856x236) — the one width at which
|
||||
/// centering and non-overlap can both hold, since Extra Buff Spells
|
||||
/// never moves but Blacklisted Buff Families tracks the growing
|
||||
/// right edge.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BuffsExtrasStripStaysCenteredAndNonOverlappingAtTheFloor()
|
||||
{
|
||||
string xml = File.ReadAllText(
|
||||
Path.Combine(MossTankMarkupDirectory, "mosstank.xml"));
|
||||
var panel = new MossTankPanel(new StubHost());
|
||||
|
||||
UiNineSlicePanel built = MarkupDocument.Build(xml, panel, static id => (id, 32, 32));
|
||||
|
||||
UiPanel[] tabGroups = built.Children
|
||||
.Where(static child => child.GetType() == typeof(UiPanel))
|
||||
.Cast<UiPanel>()
|
||||
.ToArray();
|
||||
Assert.Equal(9, tabGroups.Length);
|
||||
foreach (UiPanel group in tabGroups)
|
||||
group.Visible = false;
|
||||
UiPanel buffsGroup = tabGroups[6];
|
||||
buffsGroup.Visible = true;
|
||||
|
||||
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));
|
||||
|
||||
// First draw at the authored default captures anchor baselines;
|
||||
// only then resize down to the panel's own tested floor.
|
||||
built.DrawSelfAndChildren(ctx);
|
||||
built.Width = 856f;
|
||||
built.Height = 236f;
|
||||
built.DrawSelfAndChildren(ctx);
|
||||
|
||||
UiMarkupList[] lists = buffsGroup.Children.OfType<UiMarkupList>().ToArray();
|
||||
Assert.Equal(2, lists.Length);
|
||||
UiMarkupList leftList = lists.Single(static l => l.Left < 300f);
|
||||
UiMarkupList rightList = lists.Single(static l => l.Left >= 300f);
|
||||
|
||||
UiMarkupToggle trainedToggle = Assert.Single(
|
||||
buffsGroup.Children.OfType<UiMarkupToggle>(), static t => t.Text == "Trained skills only");
|
||||
UiSimpleButton rebuffUpButton = Assert.Single(
|
||||
buffsGroup.Children.OfType<UiSimpleButton>(), static b => b.Text == "+" && b.Top > 120f);
|
||||
|
||||
float leftMargin = trainedToggle.Left - (leftList.Left + leftList.Width);
|
||||
float rightMargin = rightList.Left - (rebuffUpButton.Left + rebuffUpButton.Width);
|
||||
Assert.True(
|
||||
rightMargin >= 0f,
|
||||
$"Extras strip (right edge {rebuffUpButton.Left + rebuffUpButton.Width}) "
|
||||
+ $"overlaps the right list (left edge {rightList.Left}) at the floor.");
|
||||
Assert.True(
|
||||
MathF.Abs(leftMargin - rightMargin) <= 4f,
|
||||
$"Extras strip not centered at the floor: left margin "
|
||||
+ $"{leftMargin}px, right margin {rightMargin}px.");
|
||||
}
|
||||
|
||||
private static void AssertResolvedWithinParent(UiElement parent)
|
||||
{
|
||||
foreach (UiElement child in parent.Children)
|
||||
|
|
|
|||
|
|
@ -301,6 +301,102 @@ public sealed class MossTankMarkupContractTests
|
|||
Assert.DoesNotContain("{ProfileNotice}", labelBindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round F item 6 (resemblance re-check nits: "Buffs' 136 px middle
|
||||
/// gap and the orphaned Coverage label"). Coverage sits right under
|
||||
/// the Buff button row instead of anchored to the group's bottom
|
||||
/// edge, which used to leave a 55px empty hole above it as the panel
|
||||
/// grew.
|
||||
///
|
||||
/// The middle-gap half has a hard geometric ceiling documented at
|
||||
/// mosstank.xml's own Buffs comment: Extra Buff Spells never moves
|
||||
/// (x=4..324) but Blacklisted Buff Families tracks the growing right
|
||||
/// edge (anchor="right"), sitting at x=524 at the panel's own tested
|
||||
/// FLOOR (856x236) and x=652 (its authored declaration below) at the
|
||||
/// 984-wide enlarged default — a 128px swing this campaign's own
|
||||
/// Round D item 4 introduced. A single FIXED-position strip can only
|
||||
/// be centered relative to ONE of those two widths; centering
|
||||
/// against the 984 default would put the strip's right edge INSIDE
|
||||
/// where the list sits at the floor — a real overlap
|
||||
/// ResolvedMainPanelHasNoOverlapOrOutOfBoundsChildAtThisSize's own
|
||||
/// 856x236 case would catch. This pins centering against the FLOOR
|
||||
/// value instead (declared x minus the 128px Round D growth delta —
|
||||
/// 984-856) — the widest safe position a fixed strip can take,
|
||||
/// verified against the real-file resolved tree at both sizes by
|
||||
/// <c>MossTankMarkupBuildOverRealFilesTests.BuffsExtrasStripStaysCenteredAndNonOverlappingAtTheFloor</c>
|
||||
/// in the App test project.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BuffsExtrasStripIsCenteredAtThePanelsFloorAndCoverageSitsUnderTheButtonRow()
|
||||
{
|
||||
XDocument document = XDocument.Load(
|
||||
Path.Combine(AppContext.BaseDirectory, "mosstank.xml"));
|
||||
XElement root = Assert.IsType<XElement>(document.Root);
|
||||
XElement buffsGroup = root.Elements("group")
|
||||
.Single(static g => (string?)g.Attribute("visible") == "{BuffsVisible}");
|
||||
|
||||
XElement[] lists = buffsGroup.Elements("list").ToArray();
|
||||
Assert.Equal(2, lists.Length);
|
||||
float leftListRightEdge = Number(lists[0], "x") + Number(lists[0], "w");
|
||||
// Round D item 4's own +128 growth: the declared x below is the
|
||||
// 984-wide authored default; subtracting it back out gives the
|
||||
// resolved position at the panel's tested floor (856x236).
|
||||
const float roundDGrowthDelta = 984f - 856f;
|
||||
float rightListLeftEdgeAtFloor = Number(lists[1], "x") - roundDGrowthDelta;
|
||||
|
||||
XElement trainedToggle = buffsGroup.Elements("toggle")
|
||||
.Single(static t => (string?)t.Attribute("onclick") == "{ToggleTrainedOnly}");
|
||||
XElement rebuffUpButton = buffsGroup.Elements("button")
|
||||
.Single(static b => (string?)b.Attribute("onclick") == "{RebuffUp}");
|
||||
float extrasLeft = Number(trainedToggle, "x");
|
||||
float extrasRight = Number(rebuffUpButton, "x") + Number(rebuffUpButton, "w");
|
||||
|
||||
float leftMargin = extrasLeft - leftListRightEdge;
|
||||
float rightMarginAtFloor = rightListLeftEdgeAtFloor - extrasRight;
|
||||
Assert.True(
|
||||
rightMarginAtFloor >= 0f,
|
||||
$"Extras strip (right edge {extrasRight}) overlaps the "
|
||||
+ $"Blacklisted Buff Families list at the panel's floor "
|
||||
+ $"(left edge {rightListLeftEdgeAtFloor}).");
|
||||
Assert.True(
|
||||
MathF.Abs(leftMargin - rightMarginAtFloor) <= 4f,
|
||||
$"Extras strip not centered at the panel's floor: left margin "
|
||||
+ $"{leftMargin}px, right margin {rightMarginAtFloor}px.");
|
||||
|
||||
XElement buffButton = buffsGroup.Elements("button")
|
||||
.Single(static b => (string?)b.Attribute("onclick") == "{Buff}");
|
||||
XElement coverage = buffsGroup.Elements("label")
|
||||
.Single(static l => (string?)l.Attribute("text") == "{Coverage}");
|
||||
float rowBottom = Number(buffButton, "y") + Number(buffButton, "h");
|
||||
float coverageGap = Number(coverage, "y") - rowBottom;
|
||||
Assert.True(
|
||||
coverageGap is >= 0f and <= 12f,
|
||||
$"Coverage sits {coverageGap}px below the Buff button row — "
|
||||
+ "expected <=12px, not the old 55px hole from anchoring it to "
|
||||
+ "the group's bottom edge instead.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round F item 6 (resemblance re-check: "Loot Editor: drop the
|
||||
/// leftover 'Back' button — the window closes from its title bar
|
||||
/// like the others"). The standalone button is gone;
|
||||
/// CloseLootEditor stays a real, bound property (still called by
|
||||
/// ToggleLootEditorVisible, the Profiles-tab checkbox's own close
|
||||
/// path).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void LootEditorHasNoLeftoverBackButton()
|
||||
{
|
||||
XDocument document = XDocument.Load(
|
||||
Path.Combine(AppContext.BaseDirectory, "mosstank-loot-editor.xml"));
|
||||
XElement root = Assert.IsType<XElement>(document.Root);
|
||||
|
||||
Assert.DoesNotContain(
|
||||
root.Elements("button"),
|
||||
static b => (string?)b.Attribute("text") == "Back");
|
||||
Assert.NotNull(typeof(MossTankPanel).GetProperty("CloseLootEditor"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AuthoredShellFitsTheMinimumCanvasAndEverySizedChildFitsItsParent()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue