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>
150 lines
5.6 KiB
Markdown
150 lines
5.6 KiB
Markdown
# Retail shared main-panel geometry — pseudocode
|
|
|
|
**Date:** 2026-07-17
|
|
**Symptom:** moving Inventory and then opening Character/Skills or Magic opens
|
|
the new panel at its own stale saved position instead of the position just used.
|
|
|
|
## Retail oracle
|
|
|
|
Named Sept-2013 retail symbols:
|
|
|
|
- `gmPanelUI::SetupChildren @ 0x004BC9E0`
|
|
- `gmPanelUI::RecvNotice_SetPanelVisibility @ 0x004BC6F0`
|
|
- `gmPanelUI::PostInit @ 0x004BD010`
|
|
- `gmPanelUI::ResizeTo @ 0x004BC6E0`
|
|
|
|
Verbatim `acclient.h` ownership:
|
|
|
|
```text
|
|
gmPanelUI : UIElement_Field
|
|
SmartArray<PanelChildInfo> m_childrenInfoArray
|
|
UIElement* m_currentlyShownPanel
|
|
UIElement* m_previouslyShownPanel
|
|
UIElement* m_pPanelPagesFrame
|
|
bool m_bStretchMode
|
|
|
|
PanelChildInfo
|
|
UIElement* child
|
|
uint panelID
|
|
```
|
|
|
|
`SetupChildren` resolves each known panel element recursively, stores the
|
|
child pointer together with its property-`0x10000029` panel ID, and initially
|
|
hides every child. It does not create independent top-level windows.
|
|
|
|
## Retail behavior
|
|
|
|
```text
|
|
SetPanelVisibility(panelId, show):
|
|
requested = find m_childrenInfoArray entry by panelId
|
|
if requested is missing:
|
|
return
|
|
|
|
if show:
|
|
if requested.child == m_currentlyShownPanel:
|
|
requested.child.SetVisible(true)
|
|
parent.SetVisible(true)
|
|
return
|
|
|
|
previous = m_currentlyShownPanel
|
|
m_currentlyShownPanel = requested.child
|
|
|
|
if previous is visible:
|
|
if requested restores previous and previous does not:
|
|
m_previouslyShownPanel = previous
|
|
else:
|
|
m_previouslyShownPanel = null
|
|
send SetPanelVisibility(previous.panelID, false)
|
|
|
|
requested.child.SetVisible(true)
|
|
parent.SetVisible(true)
|
|
return
|
|
|
|
if requested.child == m_currentlyShownPanel:
|
|
requested.child.SetVisible(false)
|
|
if m_previouslyShownPanel exists:
|
|
send SetPanelVisibility(previous.panelID, true)
|
|
m_previouslyShownPanel = null
|
|
else:
|
|
m_currentlyShownPanel = null
|
|
parent.SetVisible(false)
|
|
return
|
|
|
|
requested.child.SetVisible(false)
|
|
```
|
|
|
|
The decisive geometry fact is structural: Inventory, Character Information,
|
|
Character/Skills, Magic, Effects, and the other detail pages are children of
|
|
one `gmPanelUI`. The switch changes child visibility; there is no child move,
|
|
resize, or per-panel top-level rectangle. Moving or resizing the parent
|
|
therefore changes the one rectangle subsequently used by every child.
|
|
|
|
## Resize follow-up
|
|
|
|
The production end-of-retail LayoutDesc supplies the missing geometry oracle:
|
|
|
|
```text
|
|
LayoutDesc 0x2100006E
|
|
gmPanelUI host 0x100005FE 310 x 372
|
|
content parent 0x10000180 300 x 362, anchored on all edges
|
|
Character Information 0x10000183 panel 3, 300 x 362
|
|
Helpful Effects 0x10000184 panel 4, 300 x 362
|
|
Harmful Effects 0x10000185 panel 5, 300 x 362
|
|
Inventory child 0x1000018B panel 7, 300 x 362
|
|
Character/Skills child 0x1000018E panel 11, 300 x 362
|
|
Magic child 0x10000190 panel 13, 300 x 362
|
|
|
|
top-center 0x1000065C Type 2 Dragbar, cursor 0x06006119
|
|
bottom-center 0x10000660 Type 9 Resizebar, cursor 0x06005E66
|
|
```
|
|
|
|
Every primary child therefore participates in the shared host's vertical
|
|
resize; Magic is not a fixed-height exception. Named
|
|
`gmPanelUI::ResizeTo @ 0x004BC6E0` delegates directly to
|
|
`UIElement::ResizeTo @ 0x00463C30`, whose only size limits are effective DAT
|
|
properties `0x3C..0x3F`. There is no retail 760-pixel Character limit and no
|
|
maximum captured from the host's original screen position.
|
|
|
|
acdream retains independent wrappers under IA-12, so the faithful adaptation
|
|
is to give each registered child wrapper the same bottom-only vertical resize
|
|
policy,
|
|
leave its maximum unbounded by an authored substitute, and calculate the
|
|
available desktop extent from its current position during the resize. The
|
|
viewport remains the physical limit; an old static maximum must not become a
|
|
smaller limit after the shared panel moves.
|
|
|
|
## acdream port shape
|
|
|
|
acdream imports these child LayoutDesc roots independently, so each currently
|
|
has its own retained wrapper. `RetailPanelUiController` already ports retail's
|
|
one-active-child and restore-previous lifecycle. Complete that logical-parent
|
|
ownership by adding one canonical rectangle for all registered main-panel
|
|
children, including Character Information `3`, Helpful/Harmful `4`/`5`,
|
|
Inventory `7`, Character/Skills `11`, and Magic `13`:
|
|
|
|
```text
|
|
on registered child frame moved or resized:
|
|
canonicalGeometry = frame left, top, width, height
|
|
apply canonicalGeometry to every hidden sibling
|
|
|
|
before showing a registered child:
|
|
if canonicalGeometry exists:
|
|
apply canonicalGeometry to requested child frame
|
|
else:
|
|
canonicalGeometry = requested child frame geometry
|
|
|
|
before hiding the active child:
|
|
capture its current geometry as canonicalGeometry
|
|
```
|
|
|
|
The controller owns this synchronization and subscribes to typed
|
|
`RetailWindowHandle.Moved` and `Resized` events. Toolbar, indicator, and
|
|
keyboard commands, restore-previous effects, persistence restore, and direct
|
|
window dragging all therefore pass through the same owner. Each wrapper
|
|
retains its own imported content tree, but its outer rectangle and bottom-only
|
|
resize contract mirror the shared retail host.
|
|
|
|
ACE contains no client UI implementation, and the in-tree WorldBuilder
|
|
reference contains no `gmPanelUI` port, so neither supplies a competing
|
|
behavioral interpretation. The named retail client and verbatim header are the
|
|
oracle for this UI ownership rule.
|