fix(ui): complete retail indicator detail panels
Port the authored effect row template, remaining-time and selection details, synchronize the full gmPanelUI child geometry, and route the burden indicator to Character Information panel 3. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
a96767ba6d
commit
d1d603105f
24 changed files with 3696 additions and 147 deletions
|
|
@ -21,8 +21,8 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
private uint? _activePanel;
|
||||
private uint? _deferredPanel;
|
||||
private bool _applying;
|
||||
private bool _synchronizingPlacement;
|
||||
private PanelPlacement? _mainPanelPlacement;
|
||||
private bool _synchronizingGeometry;
|
||||
private PanelGeometry? _mainPanelGeometry;
|
||||
private bool _disposed;
|
||||
|
||||
public RetailPanelUiController(
|
||||
|
|
@ -38,11 +38,11 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
public uint? ActivePanelId => _activePanel;
|
||||
|
||||
/// <summary>
|
||||
/// Registers one of retail <c>gmPanelUI</c>'s primary toolbar children.
|
||||
/// Inventory, Character, and Magic retain panel-specific content/resize
|
||||
/// policy but share the one parent placement. A drag of any registered
|
||||
/// child updates every hidden sibling through typed window handles, so
|
||||
/// persistence observes the same canonical position too.
|
||||
/// Registers one of retail <c>gmPanelUI</c>'s toolbar or detail children.
|
||||
/// All primary and detail children retain panel-specific content but share
|
||||
/// one parent geometry. A move or resize of any registered child updates
|
||||
/// every hidden sibling through typed window handles, so persistence sees
|
||||
/// the same canonical rectangle too.
|
||||
/// </summary>
|
||||
public void RegisterMainPanel(
|
||||
uint panelId,
|
||||
|
|
@ -61,7 +61,7 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
windowName,
|
||||
restorePrevious,
|
||||
window,
|
||||
sharesMainPanelPlacement: true);
|
||||
sharesMainPanelGeometry: true);
|
||||
}
|
||||
|
||||
/// <param name="restorePrevious">
|
||||
|
|
@ -75,14 +75,14 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
windowName,
|
||||
restorePrevious,
|
||||
window: null,
|
||||
sharesMainPanelPlacement: false);
|
||||
sharesMainPanelGeometry: false);
|
||||
|
||||
private void RegisterCore(
|
||||
uint panelId,
|
||||
string windowName,
|
||||
bool restorePrevious,
|
||||
RetailWindowHandle? window,
|
||||
bool sharesMainPanelPlacement)
|
||||
bool sharesMainPanelGeometry)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
if (panelId == 0) throw new ArgumentOutOfRangeException(nameof(panelId));
|
||||
|
|
@ -95,14 +95,17 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
windowName,
|
||||
restorePrevious,
|
||||
window,
|
||||
sharesMainPanelPlacement);
|
||||
sharesMainPanelGeometry);
|
||||
_byPanel.Add(panelId, entry);
|
||||
_byWindow.Add(windowName, panelId);
|
||||
if (window is not null)
|
||||
{
|
||||
window.Moved += OnWindowMoved;
|
||||
window.Resized += OnWindowResized;
|
||||
}
|
||||
|
||||
if (sharesMainPanelPlacement && _mainPanelPlacement is { } placement)
|
||||
MoveWindowTo(entry, placement);
|
||||
if (sharesMainPanelGeometry && _mainPanelGeometry is { } geometry)
|
||||
ApplyWindowGeometry(entry, geometry);
|
||||
if (_isVisible(windowName))
|
||||
ObserveWindowVisibility(windowName, visible: true);
|
||||
}
|
||||
|
|
@ -144,7 +147,7 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
{
|
||||
if (_activePanel == panelId)
|
||||
{
|
||||
PrepareMainPanelPlacement(requested);
|
||||
PrepareMainPanelGeometry(requested);
|
||||
return _show(requested.WindowName);
|
||||
}
|
||||
|
||||
|
|
@ -156,7 +159,7 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
: null;
|
||||
|
||||
if (previous is { } previousEntry)
|
||||
CaptureMainPanelPlacement(previousEntry, synchronizeSiblings: true);
|
||||
CaptureMainPanelGeometry(previousEntry, synchronizeSiblings: true);
|
||||
|
||||
_deferredPanel = requested.RestorePrevious
|
||||
&& previous is { RestorePrevious: false }
|
||||
|
|
@ -165,7 +168,7 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
_activePanel = panelId;
|
||||
if (previous is not null)
|
||||
_hide(previous.Value.WindowName);
|
||||
PrepareMainPanelPlacement(requested);
|
||||
PrepareMainPanelGeometry(requested);
|
||||
return _show(requested.WindowName);
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +178,7 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
return _hide(requested.WindowName);
|
||||
}
|
||||
|
||||
CaptureMainPanelPlacement(requested, synchronizeSiblings: true);
|
||||
CaptureMainPanelGeometry(requested, synchronizeSiblings: true);
|
||||
bool hidden = _hide(requested.WindowName);
|
||||
_activePanel = null;
|
||||
if (_deferredPanel is not uint deferredId
|
||||
|
|
@ -184,7 +187,7 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
|
||||
_deferredPanel = null;
|
||||
_activePanel = deferredId;
|
||||
PrepareMainPanelPlacement(deferred);
|
||||
PrepareMainPanelGeometry(deferred);
|
||||
return _show(deferred.WindowName) || hidden;
|
||||
}
|
||||
finally
|
||||
|
|
@ -205,76 +208,109 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
|
||||
private void OnWindowMoved(RetailWindowHandle window)
|
||||
{
|
||||
if (_disposed || _synchronizingPlacement) return;
|
||||
if (_disposed || _synchronizingGeometry) return;
|
||||
|
||||
foreach (PanelEntry entry in _byPanel.Values)
|
||||
{
|
||||
if (!entry.SharesMainPanelPlacement
|
||||
if (!entry.SharesMainPanelGeometry
|
||||
|| !ReferenceEquals(entry.Window, window))
|
||||
continue;
|
||||
|
||||
_mainPanelPlacement = new PanelPlacement(window.Left, window.Top);
|
||||
SynchronizeMainPanelSiblings(window);
|
||||
CaptureAndSynchronizeMainPanelGeometry(window);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void CaptureMainPanelPlacement(
|
||||
private void OnWindowResized(RetailWindowHandle window)
|
||||
{
|
||||
if (_disposed || _synchronizingGeometry) return;
|
||||
|
||||
foreach (PanelEntry entry in _byPanel.Values)
|
||||
{
|
||||
if (!entry.SharesMainPanelGeometry
|
||||
|| !ReferenceEquals(entry.Window, window))
|
||||
continue;
|
||||
|
||||
CaptureAndSynchronizeMainPanelGeometry(window);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void CaptureAndSynchronizeMainPanelGeometry(RetailWindowHandle source)
|
||||
{
|
||||
_mainPanelGeometry = new PanelGeometry(
|
||||
source.Left,
|
||||
source.Top,
|
||||
source.Width,
|
||||
source.Height);
|
||||
SynchronizeMainPanelSiblings(source);
|
||||
}
|
||||
|
||||
private void CaptureMainPanelGeometry(
|
||||
PanelEntry entry,
|
||||
bool synchronizeSiblings)
|
||||
{
|
||||
if (!entry.SharesMainPanelPlacement || entry.Window is not { } window)
|
||||
if (!entry.SharesMainPanelGeometry || entry.Window is not { } window)
|
||||
return;
|
||||
|
||||
_mainPanelPlacement = new PanelPlacement(window.Left, window.Top);
|
||||
_mainPanelGeometry = new PanelGeometry(
|
||||
window.Left,
|
||||
window.Top,
|
||||
window.Width,
|
||||
window.Height);
|
||||
if (synchronizeSiblings)
|
||||
SynchronizeMainPanelSiblings(window);
|
||||
}
|
||||
|
||||
private void PrepareMainPanelPlacement(PanelEntry entry)
|
||||
private void PrepareMainPanelGeometry(PanelEntry entry)
|
||||
{
|
||||
if (!entry.SharesMainPanelPlacement || entry.Window is not { } window)
|
||||
if (!entry.SharesMainPanelGeometry || entry.Window is not { } window)
|
||||
return;
|
||||
|
||||
if (_mainPanelPlacement is not { } placement)
|
||||
if (_mainPanelGeometry is not { } geometry)
|
||||
{
|
||||
_mainPanelPlacement = new PanelPlacement(window.Left, window.Top);
|
||||
_mainPanelGeometry = new PanelGeometry(
|
||||
window.Left,
|
||||
window.Top,
|
||||
window.Width,
|
||||
window.Height);
|
||||
SynchronizeMainPanelSiblings(window);
|
||||
return;
|
||||
}
|
||||
|
||||
MoveWindowTo(entry, placement);
|
||||
ApplyWindowGeometry(entry, geometry);
|
||||
}
|
||||
|
||||
private void SynchronizeMainPanelSiblings(RetailWindowHandle source)
|
||||
{
|
||||
if (_mainPanelPlacement is not { } placement) return;
|
||||
if (_mainPanelGeometry is not { } geometry) return;
|
||||
|
||||
_synchronizingPlacement = true;
|
||||
_synchronizingGeometry = true;
|
||||
try
|
||||
{
|
||||
foreach (PanelEntry sibling in _byPanel.Values)
|
||||
{
|
||||
if (!sibling.SharesMainPanelPlacement
|
||||
if (!sibling.SharesMainPanelGeometry
|
||||
|| sibling.Window is not { } window
|
||||
|| ReferenceEquals(window, source))
|
||||
continue;
|
||||
MoveWindowTo(sibling, placement);
|
||||
ApplyWindowGeometry(sibling, geometry);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_synchronizingPlacement = false;
|
||||
_synchronizingGeometry = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveWindowTo(PanelEntry entry, PanelPlacement placement)
|
||||
private static void ApplyWindowGeometry(PanelEntry entry, PanelGeometry geometry)
|
||||
{
|
||||
if (entry.Window is not { } window
|
||||
|| (window.Left == placement.Left && window.Top == placement.Top))
|
||||
return;
|
||||
if (entry.Window is not { } window) return;
|
||||
|
||||
window.MoveTo(placement.Left, placement.Top);
|
||||
if (window.Left != geometry.Left || window.Top != geometry.Top)
|
||||
window.MoveTo(geometry.Left, geometry.Top);
|
||||
if (window.Width != geometry.Width || window.Height != geometry.Height)
|
||||
window.ResizeTo(geometry.Width, geometry.Height);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -283,14 +319,21 @@ public sealed class RetailPanelUiController : IDisposable
|
|||
_disposed = true;
|
||||
foreach (PanelEntry entry in _byPanel.Values)
|
||||
if (entry.Window is { } window)
|
||||
{
|
||||
window.Moved -= OnWindowMoved;
|
||||
window.Resized -= OnWindowResized;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly record struct PanelPlacement(float Left, float Top);
|
||||
private readonly record struct PanelGeometry(
|
||||
float Left,
|
||||
float Top,
|
||||
float Width,
|
||||
float Height);
|
||||
|
||||
private readonly record struct PanelEntry(
|
||||
string WindowName,
|
||||
bool RestorePrevious,
|
||||
RetailWindowHandle? Window,
|
||||
bool SharesMainPanelPlacement);
|
||||
bool SharesMainPanelGeometry);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue