The tick frame is a status bar whose invisible fill sweeps each period
from a duration object, with the spark anchored to the fill's edge
(ClassicAPI v1.19.1). A timer at each period's end rolls the sweep over
by whole periods, paused while hidden and caught up as it shows. The
five-second rule ends on its own timer, and the spark's alpha and the
rule bar update on the events that change them. Full mana now hides the
frame on every event, not just on a power update.
ClassicAPI v1.19.1 moves a status bar texture's rect with the fill, so
the prediction starts at GetStatusBarTexture() and is only as wide as the
incoming heal. It follows the health bar while it animates instead of
sitting at the final value.
Shown buttons on bars 1-10 enable C_ActionBar.EnableActionRangeCheck for
their slot and take ACTION_RANGE_CHECK_UPDATE; hiding a bar or paging
releases the old slot. ACTION_USABLE_CHANGED refreshes only the changed
slots; ACTIONBAR_UPDATE_USABLE is left to the stance buttons. Requires
ClassicAPI v1.19.1.
The pfActionBar frame ran an OnUpdate every frame and fully rebuilt all 140
buttons on events that only touch one part of them.
- Events go where the stock 1.12 bars send them: page and bonus-bar changes
to the main bar's pager only, UPDATE_BINDINGS to the keybind text only,
combat, auto repeat and tradeskill events to the active-border pass, and
aura/form changes to the stance buttons that exist. Full rebuilds are left
for entering the world, slot changes and the drag grid.
- Keybind text is read once per binding change from a fixed per-button
command, no longer formatted and gsub'd on every slot update.
- Updates flush on the next frame through RunNextFrame instead of a 40 Hz
OnUpdate; range is polled on a C_Timer ticker only while glowrange is on.
- Passes check visibility once per bar and walk only its shown buttons; a bar
refreshes its buttons from OnShow, replacing the polled stale catch-up.
Range no longer checks the buttons of disabled bars.
- Cooldowns skip CooldownFrame_SetTimer when start/duration/enable are
unchanged; the active border only touches widgets when its state changes,
and the "statechange" animation now follows every state change.
- PET_BAR_UPDATE only shows or hides the pet bar instead of re-running its
whole layout; unlock mode is hooked instead of polled.
- Stance and pet buttons no longer inherit the previous button's oom tint.
pfUI.bars.update is replaced by pfUI.bars.QueueSlot(slot).
GetPerfectPixel divided by the uiScale option, or by 1 while useUiScale was
off, though the game's automatic scale is never under 0.9, so default
borders came out about a tenth of a pixel thin. The game scales UIParent
only after add-ons and saved variables load, so the pixel now comes from
GetPhysicalScreenSize and the scale the game is about to apply, worked out
from the same options and rules as OnDisplaySizeChanged. UI_SCALE_CHANGED
offers a reload once when the pixel size changes.
The preset dropdown and the pixelperfect module go: its presets were pixel
perfect only at 1080p and its restore path never ran. The settings show the
game's own Use UI-Scale and UI-Scale options, plus a Pixel Perfect UI-Scale
checkbox (one UI unit per screen pixel, kept through window resizes) that
overrides them. The pixel perfect border and HiDPI options go too; border
sizes now count real pixels. CVAR settings rows write their option through
their own config instead of this:GetParent(), which a dropdown's menu
button is not. The first-run slider stops at 0.64, below which the game
drops uiScale for its automatic scale.
GetWidth/GetHeight return an anchor-sized region's size times its effective
scale, so at any UI scale but 1 they disagreed with the sizes and offsets
built from them. The craft spark, raid-marker name shortening, unit frame
indicators, dropdown widening and the cooldown font's first size now read
GetUnscaledWidth/GetUnscaledHeight. The combat log and the settings rows
drop their GetRight()-GetLeft() workarounds for the same bug.
Each bar hands its fill to StatusBar:SetTimerDuration instead of a per-frame
SetValue. Buffwatch's time text moves to a duration text binding holding the
cooldown formatter, now exposed as GetTimeFormatter (replacing
GetColoredTimeString, whose only caller this was). The five-second rule's
overlay style becomes a color-filled StatusBar too, so both styles share one
path; energytick's OnUpdate keeps only the tick spark.
Player/target/focus bars and nameplate castbars hand their fill to
StatusBar:SetTimerDuration and their timer text to a duration text binding.
Pushback re-reads UnitCastingDuration/UnitChannelDuration; a C_Timer clears a
bar whose STOP never arrives. The nameplate castbar throttle is obsolete and
goes with its settings page.
ClassicAPI's option pages now have key binding rows. Their two buttons are
numbered ClassicAPIOptionsControlN like the other controls, but they are
Buttons: strip the UIPanelButtonTemplate2 slices (BACKGROUND layer) and
skin them as buttons.
The control loop's last branch skinned anything unknown as a dropdown,
and SkinDropDown errors without the dropdown's Button, which stopped the
loop for every later control. It now runs only for a control that has
that Button; a type without a branch stays unskinned.
ClassicAPI's pages scroll with retail's MinimalScrollBar, named
ClassicAPIOptionsScrollBarN. SkinScrollbar expects the old named
UIPanelScrollBar parts, so these get their own pass: pfUI arrow buttons,
a backdrop track between them and a flat thumb, as SkinScrollbar draws.
The bar's steppers and thumb set their atlas again on every state
change, so their art is hidden rather than cleared.
The hook gated on an addon folder named exactly DPSMate and a first
window named DPSMate, so repacks under other folder names and renamed
windows never docked (#77). It now waits on login, checks DPSMate's
globals, resolves the first window from DPSMateSettings on every call,
and re-docks after DPSMate rebuilds its frames.
Each feature's settings page now picks its own timers - None, Numbers,
Sweep, or Numbers And Sweep - in place of the "Show Numbers On", "Show
Sweep On" and "Reverse Sweep On" lists on Settings -> Cooldown. Unit
frames get theirs per frame again ("Buff And Debuff Timers" and
"Indicator Timers"), so party and pet can drop their numbers while the
target keeps them. The other dropdowns sit on Action Bars, Bags & Bank,
Buff/Debuff Icons, Totem Icons, Tooltip and Nameplates.
Settings -> Cooldown keeps the shared font, size, threshold, tenths and
colors, plus the timers of Spellbook And Character, Loss Of Control and
Other Addons, which have no page of their own.
CreateCooldown(parent, kind, config, key, name) reads its mode from
config[key]. The kind says only what it times: "spell" hides numbers on
the global cooldown, "aura" drains its sweep, "timer" fills it. The
reverse option is gone; the direction follows the kind.
The migration carries every old setting into its timers: the
C.cooldown kind tables, appearance.cd's foreign and Blizzard toggles,
the buff frame's sweep, the nameplate debuff options, and each unit
frame's timer text, sweep and "Show Time Left" from before the kinds,
so frames that had their own settings keep them. Reverse options are
dropped.
The overlay inherits the engine plate's world stratum, below every UI
stratum. Moving it to BACKGROUND/LOW put it level-for-level against the
chat panels, so plates drew over the chat. The target now rises above
the other plates by raising its engine frame and re-parenting the
overlay, which carries the subtree's levels along. Debuff icons take
their level from the health bar so ones grown on a raised plate stay
above it.
The focus target frame filtered its unit events on the unit's GUID, which
only arrive while nampower fires its raw-GUID events (NP_EnableUnitEventsGuid
on, NP_EnableUnitEventsGuidFiltering off) and SuperWoW watches every unit.
Without them the bars froze until the focus switched targets (#76).
ClassicAPI fires the focus target's unit events as "focustarget" and the
focus's UNIT_TARGET as "focus" whatever nampower does, so the frame follows
those tokens. The swap check keeps its own GUID cache, since eventunit is
no longer a GUID for that frame.
The module polled: a central OnUpdate at 100 Hz over every visible plate,
a full OnDataChanged refresh of each plate every 0.5 s, and per-tick reads
of the engine's name/level regions, frame size, mouse state and
SpellIsTargeting. ClassicAPI feeds every unit event to the nameplateN
tokens, so none of that is needed.
Each bound plate now registers its unit events on its own frame against
its token (UNIT_HEALTH/MAXHEALTH, UNIT_AURA_DELTA, UNIT_FLAGS,
UNIT_DYNAMIC_FLAGS, UNIT_FACTION, UNIT_LEVEL, UNIT_CLASSIFICATION_CHANGED,
UNIT_NAME_UPDATE, UNIT_TARGET, the casts) and each handler updates only
what that event can change; the module-level events (target, combat,
level-up, roster, guild, spell targeting) fan out to the plates they
concern. Health comes from UnitHealth on the token instead of the
engine bar's OnValueChanged hook; name, level and difficulty colour from
UnitName/UnitLevel/GetDifficultyColor instead of the blanked engine
regions (UnitLevel's -1 is exactly the engine's skull case, so "??B"
survives). The engine resets the plate's size at every bind, so the
engine frame's size and click routing are re-applied from its OnShow
instead of being checked every tick; the overlay steps aside for
ground-target spells on CURRENT_SPELL_CAST_CHANGED.
The only OnUpdate left is a driver frame, shown while a castbar sweeps or
the target zoom animates and hidden when both sets are empty; the zoom
is time-based now rather than per-tick multiplication. The
nameplates/nameplates_target/nameplates_mass throttle categories no
longer mean anything and are gone from libthrottle and the GUI;
nameplates_castbar stays as the sweep rate of non-target castbars.
Mouseover tracking is gone (the token already names the unit), and
libhealth's "known" return now decides whether absolute health is shown,
so a unit whose health is only known as a percentage no longer prints
"57 | 57%".
The events table it pruned was never read; expired heals already drop out of UnitGetIncomingHeals by their own timeout. Resurrection offers are now checked by a ticker that runs only while an offer is open.
The Regrowth HoT now goes out on a one-shot timer instead of an always-running OnUpdate, and other units' spellcast events are filtered to the group's tokens, the only casters libpredict can resolve; solo, no one else's casts arrive.
An idle bar stayed shown at alpha 0, so its OnUpdate ran every frame. The fade-out now ends in Hide, a cast shows the bar, and unlock mode keeps it shown for dragging.
Every frame registered the same global events whether shown or not. A frame now keeps only the visibility events for the unit it was created for, and registers the display-only events while shown; OnShow does a full refresh to catch up on what it missed.
- Save the chat history from the frames when leaving the world, through
GetMessageInfo, instead of on every line. Lines written back from the
history carry a mark, so they are saved as they are. History is no longer
recorded while it is off, keeps 30 lines instead of 29, and whispers are
dimmed in the whisper colour (gsub's match count was taken as red).
- Skip the CLINK and URL passes on lines that cannot hold them.
- Colour player links in one gsub with a callback instead of a gsub per name.
- Read a chat line that several frames show only once, by its line ID.
- Build the timestamp once per second.
- Lay the tabs out on hover only when their bar comes back, not 10 times a
second.
- Drop ChatFrame_OnUpdate: it only blinks the flash of the bottom button
pfUI hides. The lines fade in the engine's update.
* Add raidreverse default to unitframes config
Defaults to off, so existing layouts are unchanged.
* Raid frames: add option to reverse group order
Read the new raidreverse setting and mirror the column index when placing raid frames, so group 1 sits on the far right and the following groups grow to the left.
* Add "Reverse Group Order" checkbox to raid settings
Placed under "Raid Fill Direction" in the raid frame options.
/pfui > Settings > Unit Frames > Raid > Layout
* Raid frames: rename reverse option to "Grow Right To Left"
The option mirrors columns in both fill directions, so name it for what
it does. Mirror across the columns maxraid can fill instead of the whole
layout, so smaller raids stay next to the anchor. Lay the raid grid out
through SlotToCoord like the pet grid, move the default next to the other
raid layout keys, and add the label to the locale tables.
---------
Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
The caret at the end scrolled only the box with the focus, and each
visible chat frame's box takes the focus as it opens, so only the last
one shown reached the bottom. Even that one stopped short: 1.12's
OnCursorChanged has no input context, so ScrollCursorIntoView lets the
last line clip.
Each box now measures its scroll box and scrolls it to the end on the
next frame, after the edit box has laid the new text out.
* Add anchor offset for unitframe buff or defuff
* Fix default values
* Stack a shared-corner aura block past the other block's Y offset, read the offsets without a table per icon
---------
Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
pfUI drew its own cooldown numbers before; the native countdown shows
them only with the countdownForCooldowns cvar on, and only the first-run
setup set it. Upgraded installs showed no numbers at all, so the
cooldown settings migration turns the cvar on as it removes
appearance.cd.
The shared appearance.cd values (font, size, threshold, tenths, colors)
move to the cooldown table. "Enable Durations On Foreign Frames" and
"Hide Foreign Cooldown Animations" become the Other Addons numbers and
sweep; the spellbook and character slots take that sweep, and the
foreign numbers when "Enable Durations On Blizzard Frames" was off.
Each module's old options move to its kind: the bars, bags and totems
reverse, the buffs sweep and reverse, and the nameplate debuff text,
sweep and reverse, with "Enable Debuff Timers" off turning off both
numbers and sweep. Unit frames had one set per frame and now share one:
the target frame's timer options and the raid frames' "Show Time Left"
stand for the rest. The per-frame keys, appearance.cd and bars.cd_size
are removed.
The migration is keyed on the old keys rather than the version, so it
also runs on dev installs, and runs once.
Every pfUI cooldown is now made by CreateCooldown(parent, kind) in the
new api/cooldown.lua, which replaces the cooldown module. A kind names
what the cooldown times: actionbar, bags, blizzard (spellbook and
character), unitframe, indicator, nameplate, buff, tooltip, totem or
lossofcontrol. The pfCooldownType, pfCooldownStyleText,
pfCooldownStyleAnimation and pfCooldownSize fields are gone. The new
file owns everything the cooldowns share:
- the numbers' font and size
- the formatter
- each kind's numbers, sweep and sweep direction
- the GCD threshold for spell kinds
- the CooldownFrame_SetTimer hook for other addons' Cooldown frames
UpdateCooldowns applies changed settings to every cooldown at once.
GetAuraTimer moves here from the unit frames.
All settings live in one C.cooldown table, on one page: Settings ->
Cooldown. It has the shared font, size, threshold, tenths and colors,
then "Show Numbers On", "Show Sweep On" and "Reverse Sweep On" lists
with a checkbox per kind. The per-module options are removed:
- each unit frame's timer text, animation and reverse, and the
indicators' "Show Time Left"
- the nameplate debuff timer options
- the Blizzard and foreign font sizes and toggles
- Action Bars' cooldown text size
- the reverse options of bars, bags, buffs and totems
The old appearance.cd settings are not migrated.
The player buff frame and the tooltip aura icons now show the native
countdown too, which replaces their own text and OnUpdate ticking. The
buff frame keeps its inside or below-the-icon placement. Weapon
enchants report only their time left, so they start through
SetCooldownTimeLeft: numbers, no sweep. A slim poll remains for their
charges and renewals, since no event reports those. Buff indicators
now take the aura's real duration, which gives them a correct sweep.
The spellbook and character slots now hide GCD numbers like the other
spell cooldowns.
The cooldown module no longer builds its own text frame with a 10 Hz
OnUpdate per cooldown. The CooldownFrame_SetTimer hook now configures
each Cooldown frame's own countdown instead: SetHideCountdownNumbers
for the per-frame text toggles and omnicc's noCooldownCount,
SetMinimumCountdownDuration for the GCD threshold, and
GetCountdownFontString for the pfUI font and size. The engine ticks
the numbers, gated by the countdownForCooldowns cvar. The cvar gets a
checkbox in the Cooldown settings, and pfUI.SetupCVars turns it on.
The text comes from one shared C_StringUtil numeric rule formatter,
given to each frame with SetCountdownFormatter. Its breakpoints keep
pfUI's format: the number in its unit's cooldown color, a unit (m/h/d)
once the unit below passes 99, and tenths in the low color when
milliseconds are on. Values now round up. GetColoredTimeString formats
through the same formatter, so the buff, buffwatch and tooltip timers
match. A config:changed callback rebuilds the breakpoints, and every
frame picks them up on its next update.
The paper-doll slots swap their indicator Models for Cooldown frames,
as the spellbook and bags already do. They and the spellbook take the
BLIZZARD tag when they are created, replacing the per-update hooks in
the skin module. Models get no numbers. Hide Foreign Cooldown
Animations clears the draw flags instead of setting alpha to 0, so the
numbers stay visible. The buff module's sweep hides its numbers
because buff.timer carries the text.
Both modules waited out their delays in an OnUpdate script. Each now
keeps one C_Timer.NewTimer handle and cancels it whenever a new request
comes in, so the update runs 0.5 s after the last one.
Raid: the roster pass becomes pfUI.uf.raid:UpdateRoster, and
pfUI.uf.raid:QueueUpdate schedules it. Roster events queue it with a
0.5 s delay; a config change or a tank toggle queues it for the next
frame. The frame no longer shows and hides itself to run the pass, and
the extra 1 s throttle is gone because the debounce already merges
bursts.
Questitem: without the OnUpdate script the scanner frame only handled
events, so it moves onto pfUI.events with one callback per event, and
pfUI.questitem becomes a plain table. The showquest check now lives in
QueueSeed.
/radar toggles it and /radar <yards> sets the range; the right-click
menu and the mouse wheel step through 5-40 yd. The map turns with
GetPlayerFacing so ahead is up, and ClassicAPI.UnitPosition places
class-colored dots (the mirrored name, since SuperWoW takes the global
with x, y, z order).
The range ring is two stacked TempPortraitAlphaMask discs: a ring-color
disc under a slightly smaller background-color one. It turns red when a
member is inside the range, and a list under the radar shows the five
nearest with their raid markers inline. Raid markers come from the
markN tokens, so marked mobs show too and a marked member shows the
marker instead of a dot.
Units behind terrain (UnitInLineOfSight, traced 4x a second) are
dimmed. Units on another floor, over 5 yd up or down and steeper than
45 degrees so hills don't count, get an arrow above or below them.
Hovering a blip shows its name, distance and both states; clicking a
blip or a list row targets it.
The world map's shift/ctrl wheel alpha and scale use Clamp, and the
fresh-install profile check uses TableIsEmpty (pfUI_init and pfUI_config
are always tables by then). modf only wrapped math.modf and had no callers.
The indicator moves from the unitxp module to the target frame, so it no
longer needs UnitXP_SP3. Its checkbox and the shared font size move to a
Target Indicators header; unitxp_font_size becomes indicator_font_size.
The unused pfUI.api.UnitInLineOfSight wrapper, which shadowed the
ClassicAPI global inside the pfUI environment, is removed.
The one-shot OnUpdate frame becomes RunNextFrame. Its call into the map loader ran with the delay frame as this, so the loader's hooked flag sat on a different frame than on PLAYER_ENTERING_WORLD and the map hooks went on twice: shift and ctrl mouse wheel changed alpha and scale by two steps. The flag is now a local of the module.
Each chat message queued its own scan for the next frame, so a busy frame scanned the same bubbles several times. MarkDirty runs one scan for all of that frame's messages.
Health and power bars take SmoothStatusBarMixin instead of pfUI's own OnUpdate animation, so the animation no longer runs faster at higher frame rates. The speed dropdown becomes an on/off checkbox, since the mixin's rate is fixed. A new range keeps the bar's filled share, so it doesn't jump before the animation moves on.