fix(studio): switch character skills tab on visible list
This commit is contained in:
parent
e7e943a580
commit
5f92493742
2 changed files with 94 additions and 1 deletions
|
|
@ -399,7 +399,9 @@ public static class CharacterStatController
|
||||||
// last duplicate) so we get the wider-label copies (195px) for the unselected state.
|
// last duplicate) so we get the wider-label copies (195px) for the unselected state.
|
||||||
BindFooterDynamic(layout, datFont, data, activeTab, attrSel, skillSel);
|
BindFooterDynamic(layout, datFont, data, activeTab, attrSel, skillSel);
|
||||||
|
|
||||||
UiElement? statList = layout.FindElement(ListBoxId);
|
UiElement? statList =
|
||||||
|
FindInPageContaining(layout, NameId, static el => HasDatElementId(el, ListBoxId))
|
||||||
|
?? layout.FindElement(ListBoxId);
|
||||||
RebuildActiveList();
|
RebuildActiveList();
|
||||||
|
|
||||||
if (layout.Root is { } tabRoot2 && spriteResolve is not null)
|
if (layout.Root is { } tabRoot2 && spriteResolve is not null)
|
||||||
|
|
@ -1228,6 +1230,31 @@ public static class CharacterStatController
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Finds the first descendant matching <paramref name="predicate"/> inside the
|
||||||
|
/// root-level tab page that contains <paramref name="anchorId"/>. This is required for
|
||||||
|
/// duplicated tab-page ids such as the character list box (0x1000023D): <see cref="ImportedLayout"/>
|
||||||
|
/// stores only the last duplicate in its id dictionary, which may be in a hidden page.</summary>
|
||||||
|
private static UiElement? FindInPageContaining(
|
||||||
|
ImportedLayout layout,
|
||||||
|
uint anchorId,
|
||||||
|
Func<UiElement, bool> predicate)
|
||||||
|
{
|
||||||
|
if (layout.FindElement(anchorId) is not { } anchor || layout.Root is not { } root)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
foreach (var page in root.Children)
|
||||||
|
{
|
||||||
|
if (page.Children.Count == 0) continue;
|
||||||
|
if (!ContainsWidget(page, anchor)) continue;
|
||||||
|
return FindInSubtree(page, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool HasDatElementId(UiElement element, uint id)
|
||||||
|
=> element is UiDatElement datElement && datElement.ElementId == id;
|
||||||
|
|
||||||
private static bool ContainsWidget(UiElement node, UiElement target)
|
private static bool ContainsWidget(UiElement node, UiElement target)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(node, target)) return true;
|
if (ReferenceEquals(node, target)) return true;
|
||||||
|
|
|
||||||
|
|
@ -678,6 +678,46 @@ public class CharacterStatControllerTests
|
||||||
Assert.Equal("Strength", rows[0].Children.OfType<UiText>().ToList()[1].LinesProvider()[0].Text);
|
Assert.Equal("Strength", rows[0].Children.OfType<UiText>().ToList()[1].LinesProvider()[0].Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SkillsTab_MouseClick_RebuildsVisibleListWhenListIdIsDuplicated()
|
||||||
|
{
|
||||||
|
var root = new UiPanel { Width = 300, Height = 600 };
|
||||||
|
var attrPage = new UiPanel { Top = 25, Width = 300, Height = 575 };
|
||||||
|
var hiddenPage = new UiPanel { Top = 25, Width = 300, Height = 575 };
|
||||||
|
var name = new UiText();
|
||||||
|
var visibleList = MakeDatElement(CharacterStatController.ListBoxId, top: 112, width: 300, height: 398);
|
||||||
|
var hiddenDuplicateList = MakeDatElement(CharacterStatController.ListBoxId, top: 112, width: 300, height: 398);
|
||||||
|
|
||||||
|
attrPage.AddChild(name);
|
||||||
|
attrPage.AddChild(visibleList);
|
||||||
|
hiddenPage.AddChild(hiddenDuplicateList);
|
||||||
|
root.AddChild(attrPage);
|
||||||
|
root.AddChild(hiddenPage);
|
||||||
|
|
||||||
|
var layout = new ImportedLayout(root, new Dictionary<uint, UiElement>
|
||||||
|
{
|
||||||
|
[CharacterStatController.NameId] = name,
|
||||||
|
// Mirrors the real import: the id dictionary can point at a hidden duplicate.
|
||||||
|
[CharacterStatController.ListBoxId] = hiddenDuplicateList,
|
||||||
|
});
|
||||||
|
|
||||||
|
CharacterStatController.Bind(layout, SampleData.SampleCharacter,
|
||||||
|
spriteResolve: id => (id, 16, 16));
|
||||||
|
|
||||||
|
Assert.Equal("Strength", FirstRowName(visibleList));
|
||||||
|
Assert.Equal("<no row>", FirstRowName(hiddenDuplicateList));
|
||||||
|
|
||||||
|
var ui = new UiRoot { Width = 300, Height = 600 };
|
||||||
|
ui.AddChild(root);
|
||||||
|
Assert.IsType<UiClickablePanel>(ui.Pick(132, 12));
|
||||||
|
|
||||||
|
ui.OnMouseDown(UiMouseButton.Left, 132, 12);
|
||||||
|
ui.OnMouseUp(UiMouseButton.Left, 132, 12);
|
||||||
|
|
||||||
|
Assert.Equal("Melee Defense", FirstRowName(visibleList));
|
||||||
|
Assert.Equal("<no row>", FirstRowName(hiddenDuplicateList));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void SkillsTab_SelectWarMagic_ShowsTrainedSkillFooter()
|
public void SkillsTab_SelectWarMagic_ShowsTrainedSkillFooter()
|
||||||
{
|
{
|
||||||
|
|
@ -1027,6 +1067,32 @@ public class CharacterStatControllerTests
|
||||||
tab.OnClick!();
|
tab.OnClick!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string FirstRowName(UiElement list)
|
||||||
|
{
|
||||||
|
var row = list.Children.OfType<UiClickablePanel>().FirstOrDefault();
|
||||||
|
if (row is null) return "<no row>";
|
||||||
|
var texts = row.Children.OfType<UiText>().ToList();
|
||||||
|
return texts.Count > 1 ? texts[1].LinesProvider()[0].Text : "<no text>";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UiDatElement MakeDatElement(uint id, float top, float width, float height)
|
||||||
|
{
|
||||||
|
var info = new ElementInfo
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Type = 3,
|
||||||
|
Y = top,
|
||||||
|
Width = width,
|
||||||
|
Height = height,
|
||||||
|
};
|
||||||
|
return new UiDatElement(info, static _ => (0u, 0, 0))
|
||||||
|
{
|
||||||
|
Top = top,
|
||||||
|
Width = width,
|
||||||
|
Height = height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Manufacture a minimal UiButton with a fake ElementInfo (no dat sprites).</summary>
|
/// <summary>Manufacture a minimal UiButton with a fake ElementInfo (no dat sprites).</summary>
|
||||||
private static UiButton MakeButton()
|
private static UiButton MakeButton()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue