# Retail shared main-panel placement — 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 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 placement fact is structural: Inventory, Character/Skills, and Magic are children of one `gmPanelUI`. The switch changes child visibility; there is no child move and no per-panel top-level position. Dragging the parent therefore moves the one position subsequently used by every child. ## 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 placement for the primary toolbar children (Inventory `7`, Character `11`, Magic `13`): ```text on primary child frame moved: canonicalPosition = moved frame position move every other primary child frame to canonicalPosition before showing a primary child: if canonicalPosition exists: move requested child frame to canonicalPosition else: canonicalPosition = requested child frame position before hiding the active primary child: capture its current position as canonicalPosition ``` The controller owns this synchronization and subscribes to typed `RetailWindowHandle.Moved` events. Toolbar commands, keyboard commands, restore-previous effects, persistence restore, and direct window dragging all therefore pass through the same owner. Panel-authored size/resize policy stays with the active child; only the retail parent placement is shared. 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.