The talent window, the Vanity and Wardrobe windows it switches between and
the tab row along its bottom are one feature to the player, so they get one
entry in the Skins tree and one master switch gating all three
Initialize calls together. Skinning one of them without the others reads as
a bug.
Scale is a slider per window, 0.5 to 1.5, applied as a multiplier on the
existing scale rather than an absolute -- the three don't ship at the same
size (the vanity store's frame runs about 9% larger than the others), and
that is the server's choice to keep. A setting of 1.0 leaves everything
exactly as it was.
The scale is set on Collections, not on the window itself. All three
windows and the tab row are its children, and it is the only one of them
with mouse enabled -- it is what the player drags. Scaling a window
directly left the drag target at full size, so a shrunk window had to be
grabbed by clicking outside itself, and the tab row, not being a child of
any window, kept whichever size the first-opened one gave it. Scaling the
container moves its hit area with it and the tabs follow as children.
The talent, vanity and wardrobe frames are built from the same handful of
widget templates, but each module carried its own copy of the handling:
close buttons, panels, dropdown pills, tabs and the ADDON_LOADED loader
were all written out three times. The copies had drifted -- tab backdrop
insets of 3 against 2, tabs grown in one frame and not the other, the
wardrobe clearing only three of the six tab textures -- and that drift is
what reads in-game as the same control looking different depending on which
tab you're on.
Modules/Skinning.lua now owns each of those behaviours once, and the three
modules call into it. Where the copies disagreed the values are unified;
tab growth is gated on the tab actually having a label, since growing an
icon-only tab just pushes its icon off the layout, and the SetChecked hook
is guarded because hooksecurefunc errors outright on a missing method.
Titles are pinned to Arial Narrow at 13: the vanity store titled in Friz
Quadrata while the other two used Arial Narrow. Frame scale is left as the
server set it, so the vanity title still renders slightly larger than the
others.
Two things deliberately not shared: the vanity frame still skips
StripTextures, since its currency counters are regions of the frame itself,
and the talent frame's bottom-bar dropdowns stay on their own path -- they
are a different widget, a native dropdown plus a separate caret button.
The 0.5s ScheduleRepeatingTimer poll that caught these frames couldn't
catch them before their first-ever :Show() this session, since they're
created on-demand the instant the player opens them -- native art got
one frame of paint before the poll's next tick could skin it.
Switched to a generic ADDON_LOADED listener instead: it fires
synchronously (before control returns to whatever opens the frame)
the moment the owning addon finishes loading, so skinning now lands
before the frame is ever shown. Confirmed in-game via an ADDON_LOADED
probe on the talent frame's addon before implementing.
Also fixes a regression this introduced: TalentFrame's CropBackground
was caching the background texture's "original" tex coords on its
first-ever call for later crop math. That first call now happens
pre-Show, before Blizzard's own code sets the texture's real art-tile
region, so it was permanently baking in the XML-template default
(full 0..1) as the baseline. Moved the crop to run only from OnShow,
where the real coords are already set.
Skins the outer window, close button, search box, Filter dropdown
(and its arrow and popup panel), Purchase/Deliver buttons, and the
grid pager arrows. Removes nothing else -- the portrait originally
suspected at the top-left corner turned out not to exist as a
separate element, and the card grid/preview panel are left native.