# Retail favorite spell-bar overflow pseudocode This note is the implementation oracle for world-interaction completion Slice 1. Addresses refer to the September 2013 EoR named retail client. The exact element graph and inherited properties were verified against combat LayoutDesc `0x21000073` and the existing imported fixture `combat_21000073.json`. ## Authored element graph Each of the eight `SpellCastSubMenu` groups contains: ```text favorite group scrollbar 0x100000B5, 685x36 decrement button 0x10000071, 23x36 Normal 0x06004CDC Rollover 0x06004CDD increment button 0x10000072, 23x36 Normal 0x06004CDE Rollover 0x06004CDF item list 0x100000B6, x=23, y=2, 639x32 scrollbar property 0x77 = increment button 0x10000072 scrollbar property 0x78 = decrement button 0x10000071 scrollbar property 0x79 = HideDisabled true item-list property 0x71 = horizontal scrollbar 0x100000B5 ``` The spell-bar scrollbar has no authored track or thumb. Its 23-pixel buttons occupy the space immediately outside the 639-pixel item-list viewport. ## Initialization and ownership Retail: - `SpellCastSubMenu::Init @ 0x004C5A90` - `UIElement_Scrollable::PostInit @ 0x004744B0` - `UIElement_Scrollable::OnSetAttribute @ 0x00474630` ```text SpellCastSubMenu.Init(parent, groupId, tabId, tabIndex): group = parent.GetChildRecursive(groupId) spellItemList = group.GetChildRecursive(0x100000B6) register this as the item-list drag handler spellTabElement = parent.GetChildRecursive(tabId) UIElement_Scrollable.OnSetAttribute(property): if property id == 0x71: horizontalScrollbarId = property element id UIElement_Scrollable.PostInit(): horizontalScrollbar = resolve horizontalScrollbarId register for scrollbar messages UpdateScrollbarSize(horizontal=true) ``` The controller does not synthesize arrow buttons. LayoutDesc owns them; the ordinary scrollable/listbox relationship owns the offset. ## Size, disabled state, and visibility Retail: - `UIElement_Scrollable::UpdateScrollbarSize_ @ 0x004741A0` - `UIElement_Scrollbar::SetDisabled @ 0x004703D0` - `UIElement_Scrollbar::SetHideDisabled @ 0x00470400` - `UIElement_Scrollbar::UpdateLayout @ 0x004710D0` ```text UpdateScrollbarSize(horizontal): content = scrollableWidth viewport = element.Width if content <= viewport: content = viewport scrollOffsetX = 0 disabled = true else: disabled = false scrollbar.Horizontal = true scrollbar.Disabled = disabled scrollbar.Proportion = min(1, viewport / content) Scrollbar.UpdateLayout(): scrollingArea = own rectangle position decrement button at the start and subtract its authored width position increment button at the end and subtract its authored width update thumb/track geometry, when those children exist Visible = NOT (Disabled AND HideDisabled) ``` For the favorite bar, disabled plus HideDisabled removes both arrows when every favorite/empty cell fits. With overflow, the arrows remain visible and the item list clips the horizontally translated cells. ## Scroll delta and selection exposure Retail: - `UIElement_Scrollable::HandleScrollbarMessage_ @ 0x00474370` - `UIElement_ListBox::InqScrollDelta @ 0x0046DC10` - `SpellCastSubMenu::SetSelected @ 0x004C5B00` ```text on decrement: delta = -itemList.InqScrollDelta(horizontal, line) set horizontal pixel offset += delta on increment: delta = +itemList.InqScrollDelta(horizontal, line) set horizontal pixel offset += delta ItemList.InqScrollDelta(horizontal, line): if column count is nonzero: return min(viewportWidth, scrollableWidth / columnCount) return 0 SpellCastSubMenu.SetSelected(spellId): for each item in list order: item.Selected = item.spellId == spellId if selected: endowmentSelected = false itemList.ScrollToView(itemIndex) selectedSpellId = spellId ``` The favorite cells are 32 pixels wide, so a line arrow moves exactly 32 pixels. Programmatic or keyboard selection exposes the selected cell even when it was outside the prior viewport. ## Port constraints - Preserve the imported `0x71`/`0x77`/`0x78` relationships. - Preserve each authored button's dimension; do not assume the 16-pixel chat scrollbar button size. - Do not fabricate a track/thumb for this arrow-only control. - Derive disabled state from the shared model's content and viewport extents. - Hide disabled controls from both drawing and hit-testing. - Keep every favorite tab's scroll offset independent.