fix(ui): share primary panel placement
Port gmPanelUI's persistent parent placement semantics across Inventory, Character, and Magic while preserving each imported child's content and resize policy. Synchronize typed retained-window handles so drag, switching, close/reopen, and layout persistence all observe one canonical location; keep effect panels independent. User-verified in normal Release. Release build and all 5,770 tests passed with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
124e046976
commit
3f3cfdac30
7 changed files with 460 additions and 9 deletions
|
|
@ -1,3 +1,4 @@
|
|||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
|
||||
namespace AcDream.App.Tests.UI.Layout;
|
||||
|
|
@ -74,6 +75,71 @@ public sealed class RetailPanelUiControllerTests
|
|||
Assert.Equal(2u, controller.ActivePanelId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MainPanels_ShareOneCanonicalPlacementAcrossMoveCloseAndSwitch()
|
||||
{
|
||||
var root = new UiRoot { Width = 1280f, Height = 720f };
|
||||
RetailWindowHandle inventory = Mount(root, WindowNames.Inventory, 40f, 60f);
|
||||
RetailWindowHandle character = Mount(root, WindowNames.Character, 540f, 18f);
|
||||
RetailWindowHandle spellbook = Mount(root, WindowNames.Spellbook, 18f, 18f);
|
||||
using var controller = Create(root);
|
||||
controller.RegisterMainPanel(7u, WindowNames.Inventory, inventory);
|
||||
controller.RegisterMainPanel(11u, WindowNames.Character, character);
|
||||
controller.RegisterMainPanel(13u, WindowNames.Spellbook, spellbook);
|
||||
|
||||
int characterMoves = 0;
|
||||
int spellbookMoves = 0;
|
||||
character.Moved += _ => characterMoves++;
|
||||
spellbook.Moved += _ => spellbookMoves++;
|
||||
|
||||
controller.SetPanelVisibility(7u, visible: true);
|
||||
inventory.MoveTo(312f, 147f);
|
||||
|
||||
Assert.Equal((312f, 147f), (character.Left, character.Top));
|
||||
Assert.Equal((312f, 147f), (spellbook.Left, spellbook.Top));
|
||||
Assert.True(characterMoves > 0);
|
||||
Assert.True(spellbookMoves > 0);
|
||||
|
||||
controller.SetPanelVisibility(11u, visible: true);
|
||||
Assert.False(inventory.IsVisible);
|
||||
Assert.True(character.IsVisible);
|
||||
Assert.Equal((312f, 147f), (character.Left, character.Top));
|
||||
|
||||
controller.SetPanelVisibility(11u, visible: false);
|
||||
controller.SetPanelVisibility(13u, visible: true);
|
||||
Assert.False(character.IsVisible);
|
||||
Assert.True(spellbook.IsVisible);
|
||||
Assert.Equal((312f, 147f), (spellbook.Left, spellbook.Top));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RestorePreviousEffect_DoesNotReplaceMainPanelPlacement()
|
||||
{
|
||||
var root = new UiRoot { Width = 1280f, Height = 720f };
|
||||
RetailWindowHandle inventory = Mount(root, WindowNames.Inventory, 40f, 60f);
|
||||
RetailWindowHandle character = Mount(root, WindowNames.Character, 540f, 18f);
|
||||
RetailWindowHandle effect = Mount(root, WindowNames.PositiveEffects, 900f, 30f);
|
||||
using var controller = Create(root);
|
||||
controller.RegisterMainPanel(7u, WindowNames.Inventory, inventory);
|
||||
controller.RegisterMainPanel(11u, WindowNames.Character, character);
|
||||
controller.Register(4u, WindowNames.PositiveEffects, restorePrevious: true);
|
||||
|
||||
controller.SetPanelVisibility(7u, visible: true);
|
||||
inventory.MoveTo(280f, 120f);
|
||||
controller.SetPanelVisibility(4u, visible: true);
|
||||
|
||||
Assert.Equal((900f, 30f), (effect.Left, effect.Top));
|
||||
Assert.False(inventory.IsVisible);
|
||||
Assert.True(effect.IsVisible);
|
||||
|
||||
controller.SetPanelVisibility(4u, visible: false);
|
||||
Assert.True(inventory.IsVisible);
|
||||
Assert.Equal((280f, 120f), (inventory.Left, inventory.Top));
|
||||
|
||||
controller.SetPanelVisibility(11u, visible: true);
|
||||
Assert.Equal((280f, 120f), (character.Left, character.Top));
|
||||
}
|
||||
|
||||
private static RetailPanelUiController Create(Dictionary<string, bool> visible)
|
||||
=> new(
|
||||
name => visible[name],
|
||||
|
|
@ -87,4 +153,28 @@ public sealed class RetailPanelUiControllerTests
|
|||
visible[name] = false;
|
||||
return true;
|
||||
});
|
||||
|
||||
private static RetailPanelUiController Create(UiRoot root)
|
||||
=> new(root.IsWindowVisible, root.ShowWindow, root.HideWindow);
|
||||
|
||||
private static RetailWindowHandle Mount(
|
||||
UiRoot root,
|
||||
string name,
|
||||
float left,
|
||||
float top)
|
||||
{
|
||||
var content = new UiPanel { Width = 300f, Height = 500f };
|
||||
return RetailWindowFrame.Mount(
|
||||
root,
|
||||
content,
|
||||
_ => (0u, 0, 0),
|
||||
new RetailWindowFrame.Options
|
||||
{
|
||||
WindowName = name,
|
||||
Left = left,
|
||||
Top = top,
|
||||
Visible = false,
|
||||
ConstrainDragToParent = true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.UI.Abstractions.Panels.Settings;
|
||||
|
||||
namespace AcDream.App.Tests.UI;
|
||||
|
|
@ -28,6 +29,47 @@ public sealed class RetailWindowLayoutPersistenceTests : IDisposable
|
|||
Assert.False(saved.Visible);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MainPanelMove_PersistsCanonicalPositionForEveryPrimaryChild()
|
||||
{
|
||||
var store = new SettingsStore(PathName);
|
||||
var root = new UiRoot { Width = 800, Height = 600 };
|
||||
RetailWindowHandle inventory = Mount(root, WindowNames.Inventory);
|
||||
RetailWindowHandle character = Mount(root, WindowNames.Character);
|
||||
inventory.Hide();
|
||||
character.Hide();
|
||||
|
||||
using var panels = new RetailPanelUiController(
|
||||
root.IsWindowVisible,
|
||||
root.ShowWindow,
|
||||
root.HideWindow);
|
||||
panels.RegisterMainPanel(
|
||||
RetailPanelCatalog.Inventory,
|
||||
WindowNames.Inventory,
|
||||
inventory);
|
||||
panels.RegisterMainPanel(
|
||||
RetailPanelCatalog.Character,
|
||||
WindowNames.Character,
|
||||
character);
|
||||
using var persistence = new RetailWindowLayoutPersistence(
|
||||
root.WindowManager,
|
||||
store,
|
||||
() => "Alice",
|
||||
() => (800, 600));
|
||||
|
||||
panels.SetPanelVisibility(RetailPanelCatalog.Inventory, visible: true);
|
||||
inventory.MoveTo(244f, 133f);
|
||||
|
||||
UiWindowLayout savedInventory = Assert.IsType<UiWindowLayout>(
|
||||
store.LoadWindowLayout(
|
||||
"Alice", "800x600", WindowNames.Inventory, default));
|
||||
UiWindowLayout savedCharacter = Assert.IsType<UiWindowLayout>(
|
||||
store.LoadWindowLayout(
|
||||
"Alice", "800x600", WindowNames.Character, default));
|
||||
Assert.Equal((244f, 133f), (savedInventory.X, savedInventory.Y));
|
||||
Assert.Equal((244f, 133f), (savedCharacter.X, savedCharacter.Y));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Restore_ClampsBoundsAndReappliesPanelStateAndVisibility()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue