Skip to content

Targeted Spells: migrate borders onto DF.Border (+ engine fixes)#164

Open
Krathe82 wants to merge 34 commits into
DanderBot:mainfrom
Krathe82:pr/targeted-spells-border
Open

Targeted Spells: migrate borders onto DF.Border (+ engine fixes)#164
Krathe82 wants to merge 34 commits into
DanderBot:mainfrom
Krathe82:pr/targeted-spells-border

Conversation

@Krathe82

Copy link
Copy Markdown
Contributor

Migrates the Targeted Spells, Personal Targeted Spells, and Targeted List borders onto the shared DF.Border engine, and folds in the border-engine fixes that this work surfaced.

Targeted Spells / Personal Targeted

  • The icon border now uses the full DF.Border toolkit (style, colour, alpha, inset, blend mode, shadow, animation) instead of bespoke per-feature border code — the same controls as everywhere else in the addon.
  • The important-spell highlight becomes its own Important Spell Border (a second DF.Border gated by the Important toggle). A per-profile guarded migration carries old highlight settings (style/colour/size/inset) into the new keys, so customised highlights are preserved.
  • Test-mode preview + teardown move onto DF.Border, and the dead bespoke border helpers are removed.
  • Alpha and Cooldown Swipe move to where the rest of the addon keeps them — Alpha with Icon Size/Scale, Swipe with the duration settings — instead of the functional Settings group.
  • Test-mode toggles added for Targeted Spells and Personal Targeted.

Targeted List

  • The important highlight is now a calm static border (was a glow), with an alpha control on its colour.

DF.Border engine fixes (surfaced here, benefit every border consumer)

  • Thickness 0 now hides the border across all styles (solid / gradient / textured) while animations keep running.
  • Fixed a doubled PROC glow on re-apply (stale pooled texture state); the PROC start-flash is now opt-in.

Note: no changelog entry yet — happy to add one.

Krathe82 added 30 commits June 16, 2026 13:54
Migrate the group per-icon base border off the 4 hand-rolled edge textures
(icon.borderLeft/Right/Top/Bottom) onto the unified DF.Border backend, matching
Personal Targeted Spell / Targeted List and the rest of the Stage 4.x borders.

Create path now allocates iconFrame.border = DF.Border:New(iconFrame); the
per-update ApplyIconSettings drives BuildSpec(db, "targetedSpell", {iconMode})
+ Apply (spec.enabled = showBorder, spec.size = the pixel-perfect thickness),
and insets the icon art + cooldown swipe by that thickness when shown. Reads the
existing targetedSpell* keys, so the current GUI works unchanged; the full
border toolkit (style/alpha/gradient/inset/animation) is now available for a
later CreateBorderControls GUI pass.

The "important spell" highlight is untouched in this stage (Stage 2).
Retire the bespoke important-spell highlight (InitGlow/Solid/AnimatedBorder +
the marching-ants animator + pulse AnimationGroup) in the live render path,
replacing it with a second DF.Border overlay on the existing highlightFrame.
The highlightFrame stays as the secret-safe alpha gate (SetAlphaFromBoolean on
the possibly-secret IsSpellImportant result); only its border content moves to
DF.Border.

The highlightStyle enum is preserved (no saved migration) and mapped at render
time onto a DF.Border animation: glow→PROC, marchingAnts→DF_DASH, pulse→
DF_PULSATE, solidBorder→static SOLID. Both render sites (group + personal) and
both create paths now allocate/drive iconFrame.highlightBorder / icon.highlightBorder.

The bespoke Init/Update/Hide helpers stay defined for now — TestMode's preview
still calls them; they migrate + get deleted in Stage 3. Teardown calls on them
are safe no-ops (the new overlay hides with its container).
…ers (Stage 3a)

TestMode's targeted-spell preview highlight now uses the same DF.Border overlay
+ style→animation mapping as the live path (overlay lazily allocated on the
preview highlightFrame). The active-icon teardown drops its bespoke
HideAnimated/SolidBorder + TargetedSpellAnimator calls for a single
DF.Border:Apply{enabled=false}.

Nothing now references the bespoke Init/Update/Hide Glow/Solid/Animated helpers,
the marching-ants TargetedSpellAnimator driver, or InitPulseAnimation — they are
dead code, deleted in Stage 3b. (Highlights.lua / Dispel.lua have their own
unrelated InitAnimatedBorder / pulseAnim and are untouched.)
Swap the bare Show Border / Size / Colour controls for GUI:CreateBorderControls,
matching the Personal Targeted Spell sibling: adds Style (Solid/Gradient),
Border Alpha, Inset, Blend Mode, Shadow and Animate. (Class/Role colour is
deliberately not included — consistent with the siblings and not meaningful for
"an enemy casting at this unit".) The render path already reads every
targetedSpell* border key via BuildSpec, so the controls light up the engine
with no render change. The now-unused base-border keys keep working as the
Show Border + Size + Colour the control still exposes.
…r (Stage 3b)

The bar highlight (bar.highlightFrame glow via DF.UpdateGlowBorder) now uses a
DF.Border overlay with the PROC animation, matching the icon highlight. Both
live sites (render + the light colour-update path) and the TestMode teardown are
migrated. With this, NOTHING references the bespoke Init/Update/Hide helpers or
the TargetedSpellAnimator driver — they are fully dead and ready to delete.
Remove the entire "HIGHLIGHT STYLE ANIMATIONS" block (~346 lines): the
TargetedSpellAnimator marching-ants/pulse OnUpdate driver, InitAnimatedBorder/
InitSolidBorder/InitGlowBorder (+ Update/Hide) and InitPulseAnimation, plus
their DF.* exports and the DASH/ANIM tunables — all superseded by DF.Border.

Also converts three remaining icon-teardown sites (which called the helpers by
their bare local names — missed by the earlier DF.*-only grep) to a single
DF.Border:Apply{enabled=false}. Highlights.lua / Dispel.lua keep their own
unrelated InitAnimatedBorder / pulseAnim and are untouched.

Targeted Spells borders (base + important highlight, on icons, personal frame,
the Targeted List bar, and test mode) now run entirely through DF.Border.
Stage 1.5 exposed the full DF.Border toolkit for the targetedSpell border but
the new keys were never defaulted, so Border Blend Mode / Animation (and Style /
Gradient / Inset / Shadow / Texture) read nil and the dropdowns showed the
literal "nil". Add the full targetedSpellBorder* default set to both party and
raid, mirroring the personalTargetedSpell sibling (AnimationType="NONE",
BlendMode="BLEND", Style="SOLID", etc.).
Seed the full targetedSpellImportantBorder* key set (party + raid) for the
upcoming 'Important Spell Border' subsection — a second DF.Border gated by the
Highlight Important Spells toggle, replacing the bespoke highlightStyle enum.
Seeded from the old highlight values (Colour {1,0.8,0}, Size 3, Inset 2) with
AnimationType=PROC (old default style 'glow'). Keys are inert until the render
+ GUI + migration land.
…rder keys

DF:MigrateTargetedSpellImportantBorder (Core.lua, per-profile guard
_tsImportantBorderV1; called at login + profile switch) copies any customised
targetedSpellHighlightColor/Size/Inset/Style into the new
targetedSpellImportantBorder* keys, mapping style->animation (glow=PROC,
marchingAnts=DF_DASH, pulse=DF_PULSATE, solidBorder/none=NONE). Additive + no-op
for default profiles (defaults already match); does not change rendering yet.
…er subsection

Switch the group per-icon important-spell highlight render to a full
DF.Border via BuildSpec(db, "targetedSpellImportant", {iconMode}) and
swap the GUI from the bare Style/Colour/Size/Inset controls to
CreateBorderControls. The highlight border now exposes the whole border
toolkit (style, alpha, inset, blend mode, gradient, shadow, animation),
gated by the existing Highlight Important Spells toggle + the secret-safe
SetAlphaFromBoolean(isImportant). Frame offset now follows the
targetedSpellImportant border size/inset. Personal Targeted Spell still
uses the prior style->animation mapping (its render block is shared and
reads a different key prefix).
…ggle

Test mode (Bug 1): the base border still drew the old 4 edge textures
(icon.borderLeft/Right/Top/Bottom), which the live create path retired
when it moved to DF.Border, so no border rendered in test mode. Render it
through DF.Border (lazy-allocated icon.border + BuildSpec) mirroring live
ApplyIconSettings, and migrate the test-mode important highlight onto the
targetedSpellImportant* keys so test mode is WYSIWYG with the new GUI.

Highlight toggle (Bug 2): CreateBorderControls always added its own Show
Border checkbox, so the Important Spells section had two competing gates
(Highlight Important Spells + Show Border) — the animation, gated only by
the master toggle, kept showing when Show Border was unchecked while the
toolkit hid. Add opts.noShowToggle to suppress the built-in checkbox and
let the Highlight Important Spells master be the single gate.
…OC glow

The bar highlight migration hardcoded a PROC (LibCustomGlow ProcGlow)
animation on top of the solid highlight border, so the Targeted List
important highlight flashed/animated where it used to be a calm glow.
The Targeted List highlight exposes only an enable toggle + colour (no
animation control), so drop the animation and render a plain static
solid border in the highlight colour at both apply sites (render +
lightweight colour update).
Enable alpha on the Highlight Color picker and honour color.a in the
highlight border render (was hardcoded a=1) so the static highlight can
be made translucent. Default + reset colour now carry a=1.
The highlight frame offset subtracted the inset (offset = borderSize +
hlSize - hlInset) while BuildSpec ALSO applies the inset via spec.inset in
iconMode, so the Border Inset slider was applied twice and resized the
frame, throwing off centring. Make the frame offset inset-independent
(borderSize + hlSize) and let the engine's symmetric spec.inset own the
inset, at both the live and test-mode render sites.
…border)

The Important Spell Border thickness slider had sizeMin=1, so it couldn't
be set to 0 like the base border (sizeMin=0). Lower to 0; at 0 the solid
edges vanish while any configured animation keeps running, consistent
with every other DF.Border (thickness and animation are independent;
animation is gated by the border being shown, not by thickness).
… the Border group

Both pages parked an icon Alpha slider and a cooldown-swipe toggle under
the Border header, ahead of CreateBorderControls — so the Border group
mixed feature display knobs with the shared engine, and the icon Alpha
sat confusingly next to the engine's own Border Alpha. Move both into the
top-level Settings group (matches Defensive Icon, where Hide Cooldown
Swipe already lives in Settings). The Border header is now purely the
shared DF.Border toolkit on every migrated page.
Apply() always Show()'d the four edge textures in SOLID/GRADIENT mode; at
size 0 they collapse to zero width/height but a degenerate texture could
still leave a hairline. Other borders never exposed this (their sliders
min at 1) but the Targeted Spells base + important borders now allow 0.
Hide the edges when size <= 0 so 0 means no visible border, engine-wide.
Animation overlays are separate frames and keep running, consistent with
thickness being independent of animation.
Texture-style borders clamped edgeSize to 1px at size 0 instead of
hiding, so thickness 0 still showed a 1px textured border — inconsistent
with the solid/gradient path which now hides at 0. Hide the backdrop when
size <= 0 so any border style means no border at 0. Animation overlays
are applied later in Apply gated only on spec.animation, so they keep
running at thickness 0 regardless of style.
…ubsection

Brings the Personal Targeted Spell important-spell highlight to parity with
the group/party side: render switches to BuildSpec(db,
"personalTargetedSpellImportant", {iconMode}) with an inset-independent
frame offset, the GUI swaps the old Style/Colour/Size/Inset controls for
CreateBorderControls (noShowToggle; the Highlight Important Spells toggle is
the single gate), full personalTargetedSpellImportantBorder* Config defaults
seeded in both tables, and the migration maps the old
personalTargetedSpellHighlight* keys across under an independent guard so
profiles already through the group step still migrate personal.
Missing Buff and Personal Targeted Spell borders are animation-capable but
clamped sizeMin to 1, so you couldn't run an animation with no solid edge
(every other animation-capable border already allows 0: buff, debuff,
defensive, targeted spell + important). Lower both to sizeMin 0. Safe now
that Apply hides the edges at 0 while the animation keeps running. Non-
animation borders (pet, resource bar, targeted list) stay at 1 — 0 there
would just duplicate the Show Border toggle.
StartAnimation started the LCG glow (PULSATE/CHASE/FLASH/PROC) immediately
when animRect:GetWidth() was non-zero, only deferring on an exact 0. But a
frame resized during the same layout pass (e.g. a test-mode enable toggle
re-render) reports a stale/unresolved non-zero width, so the glow sized to
the wrong (too-large) rect on alternate re-renders. Always defer the start
to the next frame so it reads the settled size; the start token still
guards against a superseded or stopped start, and one frame of latency is
imperceptible.
PROC was started with startAnim=true, playing LCG's proc start animation
(begins large, shrinks to the border). DF.Border uses PROC as a CONTINUOUS
border animation, so that start flash re-fired on every re-Apply (test-mode
toggles, relayouts); when the prior start animation hadn't fully torn down,
two glows rendered at two sizes (one inset, one further out) — visible as
the highlight flashing/doubling on alternate toggles. Start straight in the
loop state (startAnim=false) for a clean, stable glow with no flash-in.

Also reverts the always-defer glow-start change from the prior commit: it
did not address this and is unnecessary; restore the original
defer-only-when-unsized behaviour.
Replaces the hardcoded startAnim with a per-border setting
(<prefix>BorderAnimationProcStart, default off). BuildSpec reads it into
anim.procStart, StartAnimation passes it to ProcGlow_Start, and animSpecHash
includes it so toggling re-applies cleanly. CreateBorderControls gains a
'Proc Start Flash' checkbox shown only when Animation = PROC.

Default off keeps the clean continuous glow (no flash-in, no doubling on
re-apply). Users who want the proc flash can opt in per border; it plays
cleanly on a normal single appearance — only rapid re-toggling (a test-mode
stress, not real play) can still double it, which is inherent to using a
one-shot proc effect as a continuous animation.
Logs each ProcGlow start (target, pre-existing glow + its ProcStart/ProcLoop
shown state, procStart flag) and each stop (which frame still carries a
glow) to chat when debug mode is on. Lets us see, on one slow toggle cycle,
whether the double is two starts without a stop, a second glow on a new
target, or one frame with both textures shown. To be reverted once the
root cause is identified.
Diagnosis from runtime logs: DF's start/stop reference lifecycle is clean
(every start sees existing=nil, every stop releases the glow), so the
double was NOT an orphaned frame. The glow frame carries two textures —
ProcStart (the big ~3.5x start-flash) and ProcLoop (the small loop). LCG's
pool resetter hides the frame and clears the reference but leaves those
textures' shown/alpha state, so a frame re-acquired from the shared pool
could return with BOTH visible: the inset + further-out double seen on
alternate re-applies.

Fix: in stopAll, before LCG releases the frame, stop its ProcStart/ProcLoop
animation groups and hide+zero both textures, so the next Acquire starts
clean. Keeps the proc start flash working (no need to disable it).
Root cause confirmed and fixed (texture reset on pool release). Strip the
debug prints added for diagnosis.
The new fingerprint Targeted Spells icons and the Personal Targeted display
auto-showed in test mode whenever their feature was enabled, with no test-
panel switch (the old 'Targeted Spell' checkbox slot was repurposed for
Targeted List after Blizzard killed the old display). Add proper toggles:

- testShowTargetedSpell (repurposes the pre-existing dead key, now default
  true) + new testShowPersonalTargeted, in both party + raid config tables.
- Two checkboxes in the test panel's Indicators section, both refreshing via
  UpdateAllTestTargetedSpell (which drives both previews).
- Render gates in UpdateAllTestTargetedSpell: icons + personal now respect
  their toggle (off => hidden, via the existing else-branch hide path).
- Wired into all four presets (Static/Combat/Healer/Full), mirroring
  Targeted List (off in Static/Combat, on in Healer/Full).

Default true preserves the prior auto-show behaviour until a preset/toggle
changes it.
… with Duration

Match the buff/debuff convention — Alpha belongs with Icon Size + Scale, and
the cooldown swipe sits with the duration settings — rather than parked in the
functional Settings group. Both the Targeted Spells and Personal Targeted
pages. The swipe stays enabled independent of the duration text (it's the
radial cooldown sweep, not the numeric text).
…ttings

MigrateTargetedSpellImportantBorder's mapHighlight guarded each copy on the new
…ImportantBorder* key being nil, but the ADDON_LOADED default-merge populates
those keys before the migration runs, so the guard never fired and existing
Highlight settings never carried into the new keys. Gate solely on the
per-profile _tsImportantBorderV1 / _personalTsImportantBorderV1 flags (one run)
and copy the old values unconditionally, mirroring MigrateBorderInsetFold.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant