Feature/player aura bars - #1199
Open
JuJuFX-dev wants to merge 46 commits into
Open
Conversation
Replaces the retired BuffFrame/DebuffFrame reskin with an AuraKit-based Player Aura Bars module. Default Buffs bar and every custom buff bar now share a BM2-modeled filters/extra-spells system with a dedicated Filter Editor; debuff bars keep the existing class-token model. Custom bar creation goes through a Name popup instead of an instant unnamed bar, with sidebar rename support afterward. Fixes discovered during testing: buff spell selection was built on AK.AddAuraSlot, whose buttons never receive a flow-layout anchor and never render -- switched to AK.AddAuraGroup with a candidateFilters.includeSpellIDs restriction (the same mechanism the working catch-all/debuff groups already use), and wired Show All Buffs into custom buff bars to match Show All Debuffs' existing parity. Deduped same-named preset/alt spell entries out of the Extra Spells, Search Spells, and Filter Editor spell-checkbox lists.
Registers a mover for every custom buff/debuff bar (dynamic list, keyed by the bar's permanent id) alongside the existing default Buffs/Debuffs movers, and cleans up unlock registration/anchor links when a custom bar is deleted. Also trims unlock mover labels: default bars now read just "Buffs"/"Debuffs", custom bars read "PAB: <name>".
The unlock overlay's Grow dropdown dispatches to PAB_Get/SetGrowDirection for any barKey prefixed "PAB_", but the bridge only recognized the two literal default-bar keys. Custom-bar keys (PAB_CustomBuff_<id> / PAB_CustomDebuff_<id>) fell through silently: the dropdown always showed LEFT and selecting a direction did nothing. Both functions now resolve the custom bar by id, read/write its growDirection, and reload it.
Custom buff bar tiles in the sidebar showed the flat resolved spell
count ("0 Spells", "1 Spells", ...), which didn't reflect whether the
bar was actually in Show All Buffs mode, filter mode, or just had a few
direct spells. BuildBuffBarSubtitle now shows "Show All Buffs" (+ "N
spells" if Extra Spells also has entries), or up to 3 selected filter
names (3rd truncated to 3 chars + "..." once 3+ filters are assigned),
falling back to the old resolved-count phrasing when no filters are set.
The Filters and Extra Spells checkbox dropdowns only called apply() (engine reload), never RefreshPage -- a full RefreshPage(true) would have torn down the page and closed the open checkbox dropdown mid multi-select, so it was deliberately omitted. That left the sidebar tile subtitle frozen until some other action forced a full rebuild. BuildTile now accepts subtitleFn (in addition to a static subtitle) and registers it with RegisterWidgetRefresh so it re-reads on every lightweight RefreshPage() pass. Both checkbox callbacks now call RefreshPage() (non-force) after apply(), which runs just the registered refresh callbacks in place -- same fast path already used elsewhere in this codebase -- without closing the dropdown.
Same gap as the buff-side fix: the Base Filters checkbox dropdown only called apply(), never RefreshPage, so the sidebar tile subtitle froze until an unrelated full rebuild. The subtitle itself also never checked showAllDebuffs, so it always showed "N classes" even in Show All mode. BuildDebuffBarSubtitle now returns "Show All Debuffs" when that toggle is on, else the existing "N classes" count. The tile switches to subtitleFn (live-refreshing via RegisterWidgetRefresh, same as buffs), and the Base Filters checkbox callback calls RefreshPage() (non-force) after apply() so it re-reads without closing the open dropdown.
Style/grid fallback defaults (used whenever a bar doesn't set the field itself): iconZoom 0.07 -> 0.055, padding 4 -> 5, stackPosition BOTTOMRIGHT -> TOP, stackTextSize 12 -> 11, stackOffsetX/Y 2/-2 -> 0/0, durationOffsetY -2 -> 0. iconsPerRow/maxRows/maxTotal are now isBuff-conditional instead of one shared fallback: 11x3=32 for buffs, 8x2=16 for debuffs (only reached by the two default bars -- every custom bar sets these three explicitly at creation now, see below). showAllDebuffs now defaults to true (nil == on), mirroring showAllBuffs' existing "nil == on" convention -- previously defaulted to off. Updated in ClassEnabled, the Show All Debuffs toggle, its blocking-overlay state, and the debuff tile subtitle. New custom bars (buff + debuff) now start with growDirection LEFT (was RIGHT) and an explicit compact starting grid (iconsPerRow=8, maxRows=1, maxTotal=8) instead of inheriting the default bars' larger grid via fallback. New custom bars' default spawn position is now a single fixed spot (screen center, y=80) instead of staggered by barId -- since it's only ever read as a fallback for a bar with no saved position, an untouched bar (1st, 2nd, 3rd, ...) always starts there regardless of how many other bars exist or have been moved, while a moved bar keeps its own saved position.
hideSwipe = true unconditionally for both buffs and debuffs -- removes
the darkening radial overlay CooldownFrameTemplate draws over the icon
as remaining time shrinks (duration NUMBER text is a separate style
field, unaffected). Live via ApplyStyleToRegions/RestyleSoon, no reload
needed.
cancelButtons = "RightButtonUp" for buffs only (nil for debuffs), same
condition EUI_UnitFrames_AuraContainers.lua already uses for the player
unit ("unit == player and isBuff"), minus the always-true unit check
since PAB is always the player. Routes straight through AK's own
AuraButtonMixin:SetCancelAuraButtons -- same secure right-click-cancel
Blizzard's own BuffFrame/Edit Mode uses, not a hand-rolled macro/
attribute setup. Only applies to buttons created after this change
(AK wires it in MakeInitializer, not the live-restyle path) -- a
/reload picks it up for any buttons already on screen.
ReloadCustomBuffBar/DebuffBarImpl wrote AK.styles[styleKey] = BuildStyle(...) but never called AK.RestyleSoon(styleKey), unlike RestyleBars() for the two default bars. AK's MakeInitializer only runs once per created button, so a style-only change (icon zoom, swipe, stack/duration position, ...) on a custom bar whose buttons already exist (the "spell list unchanged" cheap path) silently kept rendering the OLD style until the container was released and rebuilt for some unrelated reason -- e.g. the swipe-hide fix appearing to not take effect on an already-open custom bar. RestyleSoon re-runs ApplyStyleToRegions against every already-live button under that style key.
… bar
Retires the standalone EllesmereUIUnitFrames_ExternalDefensives.lua
module (and its own Options tab) in favor of a new defaultExternalDefensives
bar inside PAB, using AK's engine-driven EXTERNAL_DEFENSIVE classification
via a single static group (filter={"HELPFUL","EXTERNAL_DEFENSIVE"}) --
no spell/class selection needed since the content is a fixed engine
classification, not user-configurable. Only toggle is enable/disable;
detail pane has no "Assigned" section, just Core/Display.
One-time migration reads any existing db.profile.externalDefensives
(enabled, iconSize, growDirection, showText->durationShow,
textSize->stackTextSize, border color/size, position) on first access.
Border texture/offset/shift/behind and duration-format variants are not
carried over -- PAB doesn't expose those fields at all yet (tracked as a
follow-up in memory, not just for this bar).
Own Unlock Mode element (including Grow Direction dropdown support) and
sidebar tile in the Options UI, alongside the existing Buffs/Debuffs
defaults. Old module file deleted, its .toc load line and Options tab
(PAGE_AURAS) removed entirely, and the old externalDefensives SavedVariables
defaults block dropped (migration reads existing profile data directly,
independent of the defaults table).
Also: ComputeGrid's width/height now use "(N-1) gaps between N icons"
instead of "N cells", removing one extra trailing pad's worth of edge
margin the previous formula baked into every PAB bar's rendered box size
(surfaced by comparing the migrated External Defensives bar's box against
the old standalone module's tighter sizing formula).
hideSwipe only re-applies through AK's ApplyStyleToRegions, which fires at button creation and on explicit Restyle passes -- not on ordinary aura content churn. Blizzard's own engine calls the equivalent of Cooldown:SetCooldown() on d.cooldown internally on every aura update, and that native API implicitly re-Shows the frame, silently undoing our SetShown(false) after the first update. Same "Blizzard keeps re-showing this" pattern already used here for BuffFrame/DebuffFrame: hook d.cooldown's Show and re-Hide it immediately, installed once per button. Covers every PAB bar (default + custom) since PAB_ApplyExtraText runs for all of them. Also lands the ComputeGrid box-sizing tweak from the External Defensives migration: width/height now use "(N-1) gaps between N icons" instead of "N cells", removing one extra trailing pad's worth of edge margin from every PAB bar's rendered box size. Confirmed in-game.
BM2 preset filters (Defensives, Offensive CDs, ...) were only imported when the options page opened, so a buff bar referencing a preset that hadn't been imported yet this session resolved and cached an incomplete spell set at login, never re-resolving until something else forced a signature change. Import now also runs at CreateBars().
BuildChain() unconditionally appended a catch-all group ("everything
not claimed by an enabled class") after the per-class groups, so a
Debuff bar with Show All Debuffs off and specific classes selected
still rendered every other debuff through that catch-all. BuildChain
now takes an includeCatchAll flag, and all three debuff call sites
(default Debuffs bar, ApplyLiveConfig, custom Debuff Bars) gate it on
showAllDebuffs so an explicit class selection is actually exclusive.
…ebuff bar table growth on delete Tooltip fallback text was being passed into L() as if it were a locale key instead of already-resolved text. Custom debuff bar deletion left stale customDebuffContainers/customDebuffDeclared entries behind since bar IDs are never reused.
…me containers GetFontPath was being re-resolved on every ApplyUFText call (the engine's own display-update cadence); it's now cached once per style rebuild since the result only changes when font settings change, which already forces a fresh style table. Duration/stack text color now uses the same change-guard fingerprint pattern already used for font and anchor, instead of calling SetTextColor unconditionally on every update.
… duration=0 on pre-existing buffs Pre-existing buffs (e.g. Battle Shout applied before this client logged in) can occasionally bind to a container with a stale/zero expirationTime if SetUnit lands inside AK's accelerated login build window before the server's own aura-timing sync settles, showing a "0" duration until the aura naturally refreshes. A single delayed UpdateAllAuras() poke per already-built unit re-pulls a fresh snapshot. NOTE: root cause is a suspected client-side timing race, not something reliably reproducible on demand -- this is a best-effort mitigation based on available evidence, not a confirmed fix. The underlying bug may still occur; needs real-world testing/confirmation.
Each bar's detail page now shows a fixed, non-scrolling preview box with fake buffs/debuffs styled from the bar's real BuildStyle/ComputeGrid output, so icon size, growth direction, spacing, border, dispel-type colors, and duration/stack formatting can be tuned live without needing to actually be buffed/debuffed. Buff previews draw from a per-class spell pool; debuffs cycle through a fixed set including one entry per dispel type. The settings area below the preview now scrolls independently via a real ScrollFrame (WrapCompensatedBody previously had no scroll mechanism at all, just silent clipping).
…arance The existing Show-hook fix only catches the swipe reappearing via Cooldown:Show(); after an instance change it was reappearing through some other Blizzard-internal path that hook doesn't cover. SetAlpha(0) is independent of Show/Hide state, so the swipe stays invisible no matter which path re-arms visibility. Confirmed fixed in-game after zone change.
Reverts 8cdfb93d. Tested in-game -- the 2s post-login UpdateAllAuras() poke did not resolve the reported stale duration=0 issue on pre-existing buffs, so the underlying assumption (stale expirationTime snapshot during the accelerated login build window) is not confirmed as the actual root cause. Root cause is still open.
…cing option Duration and Stacks now use EllesmereUI.RESIZE_ICON for their inline popup button, matching the icon RaidFrames' Buff Manager 2 uses for the same Duration Text/Stacks Text popups (Icon Size's own cog stays COGS_ICON). Also adds an optional per-bar Row Spacing field (Icons Per Row's popup), overriding only the row-to-row gap (lineSpacing/groupLineSpacing) while icon-to-icon spacing within a row stays tied to Spacing/padding as before. Defaults to the current padding value until explicitly changed. Threaded through ComputeGrid (new grid.rowGap), ApplyGroupConfig, every default/ custom/external-defensives bar apply path, and the live options preview.
…x wider than intended Preview box (icon grid, header band, divider) previously only recomputed its footprint on a structural tab/bar rebuild, not on live slider/toggle changes -- growing the icon grid left icons overflow the box, shrinking it left a stale gap above the settings fields. PAB_MaybeRefreshPreview now re-derives the same grid every live-apply and resizes box/header/divider, with a new resize hook so the settings scroll area repositions too. Separately, WrapCompensatedBody's padDiff compensation shifted the oversized scroll CHILD instead of the scroll frame itself -- mathematically equivalent to RaidFrames' own settingsScroll (both landed DualRow content at the same relative offset per a full frame-tree dump), but measured in-game as a real ~30px wider left inset than RaidFrames' Debuff Manager (50px vs 20px, confirmed by hand more than once). Restructured to shift `scroll` itself instead, matching RaidFrames' approach line-for-line; AttachEditorScroll gained an optional rightInset param so the scrollbar still lands near the true visible edge instead of the now-wider scroll frame's own edge. PAB_BuildPreviewBox's "PREVIEW" header band had the same shift-the-child pattern and got the same fix.
Threads native AuraContainerSortMethod/SortDirection through every PAB bar (Default Buffs/Debuffs, External Defensives, custom bars) via a new per-bar cfg.sortMethod/sortDirection, applied both at group declaration and live via SetAuraGroupSortMethod. UI exposes a curated 4-value dropdown (Default/Expiration/Name/Important), with Important hidden on buff bars where it has no effect. The embedded options preview simulates the same sorting for its fake icons so slider/dropdown edits show live.
Session handoff/briefing doc, same category as the existing MIDNIGHT_* working documents -- dev-only, never meant to ship with the addon.
Verified against Blizzard's actual PTR source (Gethe/wow-ui-source, AuraUtil.ImportantOnlyAuraCompare): ImportantOnly sorts by the native C_Spell.IsSpellImportant per-spell flag, not by dispel type. It's not debuff-specific, so it's no longer hidden from buff bars' Sort Method dropdown -- the previous hiding was based on a wrong assumption.
Replaces the standalone "Show All Buffs" toggle + blocking-overlay with a single unified Filters checkbox dropdown: "All Buffs" (same cfg field, never locked) and the new "Has Duration" pseudo-filter sit above a divider, followed by the real editable PAB_Filters entries -- all locked while All Buffs is on, using BuildVisOptsCBDropdown's existing per-row lockedFn/ lockedTooltip mechanism (no shared-widget changes needed). Has Duration uses the native candidateFilters.maxDuration (verified against Blizzard's PTR source), which implicitly excludes permanent (duration=0) buffs. Applied to every active buff group via a new extraCand parameter on ApplyGroupConfig, re-applied live through SetAuraGroupCandidateFilters. Buffs-only; no native stacks-based equivalent exists. Also sorts every editable-filters list (Filters dropdown, Filter Editor sidebar) alphabetically via a shared SortFiltersByName helper, always on a fresh copy since ns.PAB_Filters() returns the live persisted list.
Has Duration was wrongly locked alongside real filters while All Buffs was on, making it permanently unselectable -- it narrows the All Buffs catch-all group too (BuffCandidateExtras applies to every active buff group), so unlike real filters it's never redundant and must stay usable. Extra Spells now shares ffRow with Filters instead of its own row below. Turning All Buffs on also clears cfg.filters (real filter selections would be locked/redundant anyway) -- Extra Spells and Has Duration are left untouched since both stay meaningful alongside All Buffs.
… Spells The embedded options preview always rendered fake example icons regardless of actual config, misleadingly implying content even when the real bar would show nothing (e.g. All Buffs off with no filters selected). New HasFillerSource(isBuff, cfg) mirrors the exact condition the engine uses to decide whether a catch-all/class-token chain would render anything (buffs: showAllBuffs or any filter; debuffs: showAllDebuffs or any class -- BuildChain's includeCatchAll fully respects both, correcting a stale assumption that debuffs could never show nothing). BuildPreviewSlots assigns each icon slot a kind: buffs' Extra Spells always occupy the leading slots with their real icon (not the fake pool), the remaining slots are fake example icons when HasFillerSource is true or a placeholder (grey box + red X, reusing eui-close.png) otherwise. Border now draws for every slot kind, including placeholders.
Fake filler icons now only appear when All Buffs is on -- it has no finite spell list, so padding with examples is a fair approximation. Real Filters/Extra Spells resolve to a concrete, finite set (ns.PAB_ResolveSpells), so they now render as their own real icons in the leading slots with placeholders for any remaining capacity, instead of fake icons pretending more content exists (e.g. 4 resolved spells with room for 8 icons and All Buffs off now shows 4 real icons + 4 placeholders). Also dedupes the resolved list by icon texture, not just spell ID: a filter's alt/rank spell IDs for the same buff were rendering as duplicate icons since ns.PAB_ResolveSpells only dedupes by spell ID.
PREVIEW_DEBUFF_SPELLS grows from 6 to 66 (Magic/Curse/Disease/Poison/Bleed x10 + 9 non-dispellable) -- list supplied directly by Joel, since unlike CLASS_PREVIEW_BUFFS there was no existing verified debuff catalog anywhere in this repo to draw from. New BuildDebuffPreviewPool() shuffles it once per preview box build, same treatment BuildBuffPreviewPool already gets. The pool threading (RenderPreviewIcons, ns.PAB_BuildPreviewBox, PAB_MaybeRefreshPreview, activePreview) is renamed from buffPool to the generic pool, since both polarities now get a shuffled pool instead of debuffs using the static list directly.
Documents the settled behavior: the combined 134-entry class-buff+extras pool is shuffled with no per-class priority, since it's already far larger than any configured grid (maxTotal defaults to 32) -- "notfalls" fallback padding essentially never triggers. A brief own-class-first variant was tried and reverted within the same session before landing here.
Was W:SectionHeader, a shared widget fixed at 40px tall with its label anchored only 8px from the block's bottom -- built for spacing consistency among stacked option rows, not this floating title/desc/box context, and left ~20px of pure blank padding above the "PREVIEW" text. Replaced with a lightweight, purpose-built label + separator at 18px, matching the same look via EllesmereUI.TEXT_SECTION/BORDER_COLOR (already exposed on the shared table) without touching the shared widget file.
Row Spacing is icon-to-icon gap between rows, same family as Spacing (padding), not a grid-size concern like Icons Per Row/Max Rows/Max Total.
ns.PAB_ResolveSpells unions every selected Filter's + Extra Spells' ids into one set sorted purely by raw spell id. Truncating that to fewer available icon slots than resolved spells meant whichever Filter happened to contain the lowest-numbered spells won every visible slot, and every other selected Filter (plus Extra Spells) never appeared at all. New BuildMixedRealSpells(cfg) interleaves round-robin across sources (each selected Filter is its own source, Extra Spells is one more) instead of a flat numeric sort, so truncation always samples a bit of everything. Deterministic on purpose -- no reshuffle on every live-apply refresh. Also applies SortPreviewList to these real extra icons, not just the fake filler pool -- with All Buffs off, content is mostly/only these real slots, so Sort Method/Direction had no visible effect there before.
…t order Both the real "extra" icons (Filters/Extra Spells) and the fake "All Buffs" filler had the same bug: sorting the full candidate list BEFORE truncating to the available icon-slot count meant a sort change could pull a DIFFERENT subset into the surviving slots, not just reorder the ones already visible. Fixed by selecting first, sorting second, in both places: the real extra icons truncate BuildMixedRealSpells' deduped/mixed list to `count` before sorting; the fake filler now selects its fixed slice from the stable per-box-build pool (no longer pre-sorted in RenderPreviewIcons) before sorting that slice. Sort Method/Direction now only reorders whatever's already showing.
Ports Raid Frames' DebuffManager fx system (per-category Icon Glow/ Border/Size overrides) to PAB's debuff bars (Default Debuffs + every Custom Debuff Bar). PAB's debuff classes are a mutual-exclusion chain (unlike Raid Frames' overlapping records), so matching a button's category to an fx block is a single dictionary lookup via a d.dmCat stamp set in ApplyGroupConfig's extraInit. Size overrides needed more than expected: PAB's icon size is entirely style-driven (button:SetSize from style.width/height), not group-layout- driven, so a per-category size needed its own sized-style-variant system (EnsurePabSizedStyle) mirroring Raid Frames' EnsureBaseSizeStyle, plus a `|sz`-suffixed group-key variant so a size toggle swaps groups cleanly. Curated the debuff filter vocabulary (Base Filters + Icon Effects Filters) to match Raid Frames exactly: Important, Crowd Control, Boss Debuffs, Role Debuffs, Raid, Raid In Combat, Dispellable By You, Dispels. Raid/Raid In Combat are now real, functional categories (previously excluded as "roster-context, doesn't apply to a standalone display" -- reversed since they're per-aura flags, not roster-size-dependent). Added the missing "Dispels" (any dispel type) filter as a new value-bearing candidate class (includeDispelTypes) in the shared EUI_UnitFrames_AuraContainers.lua class tables, threading a new candValue field through both that file's and PAB's own independent BuildChain/ApplyGroupConfig implementations. Preview panel changes: - Every active fx block claims 1-2 fake icons directly, independent of Base Filters/Show All Debuffs state -- requiring the same category in both dropdowns made the preview show nothing in the normal case. - Real per-icon flow packing (slotSize/colOffset/rowYOffset) instead of a uniform worst-case cell, so an oversized icon doesn't overlap its neighbor without inflating the gap around every other icon. - ComputeGrid's box/parent-frame footprint (MaxIconSizeFor) accounts for the largest configured icon size -- a real bug on the live bar too, not just the preview, since the parent frame never grew to fit an oversized category before this.
style.stackColor is always a keyed {r,g,b} table across every caller in
the addon, but ApplyStyleToRegions indexed it as an array, so
SetTextColor received nils and errored. Latent since AK.lua's
introduction; only surfaced now because Player Aura Bars is the first
module to skip noDefaultFonts and hit this default path.
Options UI dropdown/slider fallbacks (stackPosition, padding, rowSpacing, iconsPerRow, maxRows, maxTotal, iconZoom, stackTextSize) disagreed with the actual render-time defaults, making fresh profiles show wrong values in the UI even though rendering was correct. Also changes Row Spacing's default to a fixed 12px, decoupled from Padding/Spacing.
Extends PAB's Growth Direction beyond Left/Right with Up/Down, wiring AK's existing column-flow axis (AK.SetContainerAxis) through every live-apply/create/reload path, ComputeGrid's width/height swap, and a new column-major packing branch in the options preview's hand-rolled icon layout. Adds a cog-only Icon Wrap (Left/Right) setting for multi-column vertical bars, and updates the unlock-mode drag popup so its Grow menu offers Up/Down for PAB bars too. Also caps the options preview area's height (proportional shrink, matches the existing panel-zoom scaling) so Up/Down bars with many icons per column don't blow up the options page height.
d.dmCat (a button's category stamp for Icon Effects matching) was always "all" on the default Debuffs bar, since its BuildChain always routes everything through the catch-all group unless Show All Debuffs is off -- and Icon Effects deliberately never match the catch-all key. Per-aura category can't be read back from an AK-engine button after the fact (confirmed via the dispel-ring mechanism: that data is engine-secret in 12.1), so the fix instead forces a real per-category group into existence whenever an active Icon Effects block targets that category, same as if the user had manually enabled the matching Base Filter. Also fixes a duplicate-icon side effect this exposed: candidate classes (e.g. "Dispels") had no token to negate forward into the catch-all, so forcing one active while the catch-all was still included rendered the same debuff twice. BuildChain now propagates excludeDispelTypes forward once the dispel-typed candidate class is active. The three boolean candidate classes (Boss/Role/Priority Debuffs) have no confirmed Blizzard exclude counterpart, so those are deliberately left requiring Show All Debuffs off + the matching Base Filter, same as before this fix.
…le module on first PAB use On a profile's very first PAB run, position/icon size/icons-per-row/grow direction now seed from the live BuffFrame/DebuffFrame EditMode state instead of PAB's hardcoded defaults, so a first-time user doesn't lose an already-customized Blizzard layout. If the old retired "Styled Player Auras" module was previously enabled, its border/duration-show/text-size settings are layered on top too. Guarded by a one-time flag so existing profiles are never touched.
# Conflicts: # EllesmereUIUnitFrames/EUI_UnitFrames_Options.lua
…object crash
Icon Effects Per-Filter's glow could render behind the per-filter border
override: both landed on the same AuraKit frame level (borderHost+2).
AuraKit's border/dispel-ring/text ladder is shifted one level higher
(dispel ring +3->+4, text +4->+5) to give the glow its own level
(borderHost+3), and PAB/RaidFrames' ApplyDmFx now use that level -- final
order is border < fx border < glow < dispel ring < text, with no ties.
PAB's glow/border overlay frames are now pre-created unconditionally at
button creation (mirroring AuraKit's own dispelHolder), instead of lazily
on first use. Turning on a previously-inactive filter's glow/border no
longer needs a /reload: the frame already exists, so it's just Show/Hide
+ StartGlow/StopGlow, which is legal outside the button's one-time
creation window (CreateFrame-parenting a new frame to the secure engine
button is not).
Attempted to stop unconditionally remapping driver-ticked glow styles
(Pixel Glow, Action Button Glow, Auto-Cast Shine, Shape Glow) to their
FlipBook-safe equivalents on live debuff icons, so the selected style
would render as picked instead of always downgrading. Reverted after a
field crash: parenting one of these to a real AuraButton and letting it
register with the central glow driver hard-errors ("Attempt to access
forbidden object from code tainted by an AddOn") the moment the driver
calls wrapper:IsVisible() on it. Confirmed in Blizzard's own PTR 12.1
source that AuraButton is unconditionally forbidden (useForbiddenObjectTable
+ ForbiddenAspects baked into the base template), so PAB_ApplyDmFx keeps
the unconditional RestrictionSafeStyle remap. Those four styles are now
hidden from the Icon Effects Per-Filter glow dropdown entirely, since
picking one never actually renders as selected on a live icon.
Also: renaming a custom Buff/Debuff bar now re-registers its Unlock Mode
label immediately (Apply() was missing from the rename flow, unlike
toggle/delete), instead of showing the old name until the next /reload.
…code File-untracking from 9b25c16 stays in effect; only the .gitignore addition is reverted so it doesn't show as an unrelated change in the upcoming PR against upstream.
EUI_QoL_Options.lua registers its page under the key "QoL" (PAGE_QOL), not "Quality of Life" -- these four _ELEMENT_SETTINGS_MAP entries silently broke Unlock Mode's jump-to for FPS/Secondary Stats/BattleRes/Bloodlust since 04bf744. Unrelated to Player Aura Bars, reverting to keep the PR scoped.
…ns UI Also drops several stale entries the committed file carried that .tools/extract-locale-keys.sh cannot statically produce (tip/offTip table fields in EUI__General_Options.lua, not literal L() calls) -- pre-existing drift on upstream/main itself, confirmed by running the script against a clean upstream/main checkout (658 keys there vs the 666 the committed file claims). Unrelated to PAB; this commit only brings our branch's file back in sync with what the script actually produces.
Only reproducible with a bar's declared row capacity >=2 (usedRows) at a UIParent scale other than PP.PixelBestSize() -- e.g. 0.7111 at 1440p instead of the native 0.53333. Root cause was raw, never-PP.Scale'd numbers reaching two different places: BuildStyle/MaxIconSizeFor fed cfg.iconSize straight into both the button's SetSize and ComputeGrid's cross-axis extent math. ApplyGroupConfig fed cfg.padding/cfg.rowSpacing straight into the native AuraContainer engine's SetAuraGroupLayout (elementSpacing/lineSpacing). An exhaustive 1-20 sweep of Row Spacing (everything else held fixed) showed only 2 of 20 values reproduced the border defect, with no clean divisibility pattern -- consistent with the native engine's own internal pixel rounding landing on the wrong side of a boundary for specific raw inputs it was never guaranteed to receive on a pixel boundary in the first place. All three now run through PP.Scale before use. Separately, PAB's four bar-position SetPoint call sites (ApplyBarPosition, ApplyExtDefPosition, ApplyCustomBarPosition, and the CENTER-anchor recompensation blocks in ApplyLiveConfig/ApplyExtDefLiveConfig) applied saved x/y coordinates raw, unlike EllesmereUIUnitFrames.lua's own ApplyFramePosition which snaps via PP.SnapCenterForDim/PP.SnapForES first. Added a matching SnapBarPos helper and wired it into all four sites. This alone did not resolve the reported symptom, but is a real, independently-justified fix for the same class of bug and is kept. Ruled out during investigation (confirmed via a temporary secret-safe debug dump, since removed): d.borderHost:GetEffectiveScale() reads are fully reliable on aura-button-parented frames, including during live bug reproduction -- not the cause, contrary to earlier suspicion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Player Aura Bars
Replaces
EllesmereUIUnitFrames_PlayerAuras.lua(the old aura-style module) with Player Aura Bars (PAB): a filter-driven buff/debuff bar system built onEllesmereUI.AuraKit, with a redesigned options UI and an embedded live preview.Features
EUI_UnitFrames_AuraContainers.lua'sTOKEN_CLASSES/CANDIDATE_CLASSESinstead of hardcoded spell lists. Multiple filters combine per bar.EUI_PlayerAuraBars_ManagerPages.lua) simulates Filters, Sort, Extra Spells and Icon Effects against a placeholder/real-spell-icon pool without requiring live auras in-game.EUI_UnlockMode.lua's generic mover (see below).Bug fixes bundled in this branch
duration = 0on pre-existing buffs after login/reload (2s post-login aura-container poke, with an earlier poke variant reverted as ineffective).L().Shared/global file changes — and why
This branch touches four files other modules depend on. None of them change existing behavior for non-PAB consumers except where noted:
EllesmereUI_AuraKit.luaApplyStyleToRegions's stack-count text color to readc.r/c.g/c.b/c.ainstead ofc[1..4]—stackColoris stored as an{r,g,b,a}table everywhere it's built, so the old indexed access returnedniland crashed. This is a real AuraKit bug affecting any consumer with a customstackColor, not PAB-specific; PAB's Icon Effects work just surfaced it.+3 → +4, stack/duration text carrier+4 → +5) to open a level for the DM per-filter glow (ApplyDmFx/PAB_ApplyDmFx), which now sits between the per-filter border override (+2) and the dispel ring. Without this, PAB's per-filter glow could render on top of the dispel ring/text, or (the forbidden-object crash) collide with a level Blizzard's engine already owns.EUI_RaidFrames_AuraContainers.lua'sApplyDmFxframe levels are updated in lockstep (+2 → +3, carrier+4 → +5) to match this shared ladder.EllesmereUIUnitFrames/EUI_UnitFrames_AuraContainers.luadispeltypedcandidate class (TYPED_DEBUFF_TYPES) and threadedcandValuethroughBuildChain/DeclareElementGroup/ApplyGroupConfigso a candidate class can carry a value set, not just a boolean — needed for PAB's own filter resolution to reuse the exact same class definitions.TOKEN_CLASSES/CANDIDATE_CLASSESasns.UF_TokenClasses/ns.UF_CandidateClassesso PAB shares one source of truth for the class vocabulary instead of maintaining a second copy that could silently drift.debuffAnchorBuffs("Anchor Buffs with Debuffs") merge path inAnchorContainer/ApplyGroupConfig. This was the old aura-style module's mechanism for stacking buffs onto the debuff container; PAB owns bar composition itself now (separate bars, separate anchoring), so the merge became dead weight and a second, conflicting anchoring path for buffs. Confirmed intentional, not incidental scope creep.SetTextColorchange-guarding via aCK()color fingerprint (d.ufDurColor/d.ufStackColor) and cachedstyle.fontPathonce per style rebuild instead of resolving it on everyApplyUFTextcall — this runs on every registered aura button on display updates, so redundantSetTextColor/GetFontPathcalls are real, avoidable per-frame cost.EUI_UnlockMode.luaCreateMovernow recognizes thePAB_bar-key prefix:canGrowincludes it, and the Grow-direction popup reads/writes direction viaEllesmereUIUnitFrames:GetGrowDirectionForBar/SetGrowDirectionForBarinstead of the ActionBars/CDM-specific paths those functions already used for other bar families.PAB_bars: AuraKit'sSetFlowLayoutGrowthDirection(AnchorUtil.FlowDirection) is a strict Left/Right/Up/Down axis with no centered concept, unlike the CDM/ActionBars bar renderer this popup was originally built for. Offering it would show a selectable option PAB's layout can't actually honor.Files touched
EllesmereUIUnitFrames/EllesmereUIUnitFrames_PlayerAuraBars.lua(new, ~4.3k lines) — core PAB moduleEllesmereUIUnitFrames/EUI_PlayerAuraBars_ManagerPages.lua(new, ~2.5k lines) — options UI / manager pagesEllesmereUIUnitFrames/EllesmereUIUnitFrames_PlayerAuras.lua— removed (superseded by PAB)EllesmereUIUnitFrames/EUI_UnitFrames_Options.lua,EllesmereUIUnitFrames.lua,EllesmereUIUnitFrames.toc— wiring/registrationEUI_UnlockMode.lua,EllesmereUIUnitFrames/EUI_UnitFrames_AuraContainers.lua,EllesmereUIRaidFrames/EUI_RaidFrames_AuraContainers.lua,EllesmereUI_AuraKit.lua— shared-file changes, see aboveTesting
luac5.1 -p.