Commit Graph

3810 Commits

Author SHA1 Message Date
Brues 2b140da5d4 Update CHANGELOG.md 2026-06-22 14:10:17 -05:00
Brues 1c60901f2a release: bootstrap CHANGELOG.md for first tagged release
Packager auto-generates the GitHub release body from git log since the
last tag. The first release has no prior tag, so it walks all history
and overshoots GitHub's 125k-char body limit. Ship a curated
CHANGELOG.md with the highlights and point packager at it via
.pkgmeta's manual-changelog directive. Subsequent releases diff
tag-to-tag and stay small — either delete both files after this
release lands to restore auto-gen, or keep maintaining CHANGELOG.md
manually.
2026-06-22 13:58:43 -05:00
Brues ee17a39445 updatenotify: isolate fork from upstream pfUI traffic + handle dev builds
Switches the addon-message prefix to "pfUI-brues" so we don't share an
inbound queue with upstream pfUI installs at all — they don't register
a listener for this prefix, so our broadcasts get dropped at the engine
level instead of needing branch-string filtering on their end. The
"main" branch tag stays as a tiebreaker for any future fork variant
sharing this prefix.

Source/dev installs leave the toc Version as "@project-version@" until
release tooling substitutes it. pfUI.lua now stamps those as "dev" with
major/minor/fix=0 instead of silently falling back to 1.2.0, and
updatenotify short-circuits on pfUI.version.string == "dev" before
broadcasting so dev installs don't ship a stale low version to everyone
in guild/raid. Single source of truth — the dev marker lives in pfUI.lua.

URLs centralize via the toc's X-Website. updatenotify and firstrun read
it via GetAddOnMetadata + string.format("%s"), and all eight translation
files swap their hardcoded shagu.org references for the same %s slot.

Drive-bys: groupsize math uses ClassicAPI's IsInRaid/IsInGroup; toc
Author typo "modfied" → "modified".
2026-06-22 13:51:00 -05:00
Brues 95e936e9a1 add git release workflow 2026-06-22 13:05:26 -05:00
Brues 7e52683004 nameplates: reset cache.player on plate reassignment to dodge stale hints
The per-unit cache reset only fired when the plate's name changed, so
pool reuse between same-named units (player "Ironforge Guard" → NPC
"Ironforge Guard") carried the previous unit's cache.player into the
next OnDataChanged call. GetUnitInfo then returned the wrong table's
class, unittype flipped to FRIENDLY_PLAYER, and the bar drew in MAGE
class color. Gate the reset on cachedGuid changes too.

Stores cache.player as true/false/nil instead of "PLAYER"/"NPC" so it
flows straight into GetUnitInfo as the isPlayer hint — both in
OnDataChanged and the wait_for_scan retry, which previously dropped
the hint and ping-ponged the flag every frame.
2026-06-22 11:38:19 -05:00
Brues d14d30b00b revert PixelUtil usage 2026-06-22 11:31:27 -05:00
Brues aa912ed20a nameplates: collapse OnDataChanged unit-type resolve to a single pass
Hoists the name-change reset above the GetUnitInfo lookup and folds the
two UnitIsPlayer call sites into one. The earlier shape resolved
cache.player upfront from cachedGuid, then redundantly re-resolved from
unitstr after the name-change reset — and the upfront block could read
stale cache.player on plate reassignment, passing a wrong isPlayer hint
to GetUnitInfo.
2026-06-22 11:15:31 -05:00
Brues 6c64143b60 nameplates: filter libunitscan by player/npc to dodge name collisions
GetUnitInfo() probed the players table first, so an NPC sharing a name
with a known player (e.g. Chromie) inherited the player's class, level,
and guild. Adds an isPlayer hint to GetUnitInfo and resolves each
plate's actual unit type from its cached GUID via UnitIsPlayer before
the lookup. The plate's cache.player gates further work.
2026-06-22 10:11:56 -05:00
Brues fa3f191eea castbar: pixel-snap progress via PixelUtil.SetStatusBarValue
Routes player and nameplate castbar progress through
PixelUtil.SetStatusBarValue so a 1.4s cast on a narrow bar no longer
shimmers across fractional pixels as it ticks. Adds GetMinMaxValues /
GetValue handlers to pfUI's custom StatusBar so PixelUtil can read the
current range.
2026-06-22 10:11:33 -05:00
Brues e6664a4eb6 focus: hand /focus and /clearfocus to ClassicAPI
ClassicAPI's SlashCommandsRegistry now owns the canonical /focus and
/clearfocus commands (matching modern Blizzard's no-alias convention
and delegating to the engine's FocusUnit / ClearFocus polyfills).
pfUI no longer needs to register them.

The TargetByName-based name-resolution workflow that the old
SlashCmdList.PFFOCUS provided ("/focus Hogger" → swap-target, capture
focus) doesn't fit the modern /focus contract, which only takes unit
tokens. Move that behavior into a separate /focusname (alias
/pffocusname) so users who relied on typed names still have a path —
just under a different command name.
2026-06-21 01:32:10 -05:00
Brues 740940dece actionbar: defer to SuperCleveRoidMacros for managed macros
In ButtonMacroScan, when SuperCleveRoidMacros manages the slot
(CleveRoids.IsManagedAction), leave spellslot/booktype unset and return
early. This lets the button's icon, cooldown, and tooltip flow through
the addon's hooked GetActionTexture / GetActionCooldown /
GameTooltip:SetAction so they follow the active conditional dynamically,
instead of being frozen to the first statically-scanned spell.
2026-06-21 00:11:29 -05:00
Brues 49712fc542 bump pfUI min version 2026-06-18 23:35:43 -05:00
Brues 465ad13e9a pfUI: derive ClassicAPI version string from PFUI_CLASSIC_API_MIN
The popup text and chat message both had hard-coded "v1.2.0" strings
that fell out of sync every time the constant bumped. Decode the
packed X*10000 + Y*100 + Z form into "vX.Y.Z" via a FormatVersion
helper and substitute it into both messages. The edit-box URL also
deep-links to the matching releases/tag/<version> page so users land
directly on the release they need.
2026-06-17 21:15:07 -05:00
Brues f35ad0cc94 bump PFUI_CLASSIC_API_MIN 2026-06-17 20:57:48 -05:00
Brues 3ca35feb72 Use UnitSubName from ClassicAPI 2026-06-17 20:56:42 -05:00
Brues b58f2bc62d libunitscan will trigger off NAME_PLAYER_UNIT_ADDED 2026-06-17 20:19:58 -05:00
Brues 5772cf2f91 GetUnitData -> GetUnitInfo
avoid clash
2026-06-17 20:19:42 -05:00
Brues 17291e4d9b nameplates: cut per-tick allocations in OnUpdate path
Six allocation sites firing per visible plate per central tick (or per
throttled OnDataChanged tick) were generating heavy GC pressure visible
in pfDebug's analyzer:

- IterDebuffs callback in PlateCacheDebuffs was a fresh closure per call.
  Hoisted to a module-level function with state in _pcdSelf / _pcdNow /
  _pcdId, matching the pattern the icon-grid IterDebuffs already used.

- string.format("%.2f", remaining) in UpdateCastbar fired every frame per
  active castbar. Factored into SetCastbarText helper that compares a
  rounded integer (centi- or deci-seconds) and only formats + SetTexts
  when the displayed value would actually change. lastTextTick reset
  alongside lastEndTime so back-to-back casts don't collide.

- guid.."target" concat in GetCombatStateColor hit Lua's string intern
  pool every call. Cached in guidTargetTokenCache, evicted alongside
  the other per-guid caches in NAME_PLATE_UNIT_REMOVED.

- plate.name:SetText was unconditional; moved inside the existing
  plate.cache.name change gate so it only fires on real unit changes.

- plate.level:SetText (string.format) was unconditional; gated behind a
  new (level, elite) cache so the format only runs on level-up or
  elite-state flips.

- C_NamePlate.GetNamePlates() poll every 0.5s allocated a fresh Lua
  table just to read its length. Replaced with a visiblePlateCount
  counter maintained event-driven from NAME_PLATE_UNIT_ADDED/_REMOVED.
2026-06-17 13:30:31 -05:00
Brues 50d06f2e7a nameplates: cachedGuid + percent-mode guard + name text position
- Switch the four GUID reads in OnDataChanged from plate.parent:GetName(1)
  (SuperWoW idiom) to plate.cachedGuid (set by NAME_PLATE_UNIT_ADDED via
  UnitGUID(token)). Move the initial OnDataChanged call out of
  OnConfigChange's CREATE path so it runs after UNIT_ADDED has populated
  cachedGuid; re-add it explicitly in the user-config-change loop.

- Reject GetUnitField's health/maxHealth when maxHealth == 100 — the
  engine writes (hp_percent, 100) into UnitFields for non-detailed units
  (UPDATE_PARTIAL packets carry percent only). Without this guard,
  Nampower's raw field read returns the percent and the nameplate displays
  "5 / 100" as if it were real HP. Mirrors libhealth's heuristic so we
  fall through to its estimator instead.

- New config: nametextpos (LEFT/CENTER/RIGHT, defaults to CENTER).
  Decouple the bar's anchor from the name so the name's JustifyH can
  shift left/right without dragging the bar with it.
2026-06-16 19:53:52 -05:00
Brues b3f8745b91 raise power bar above its backdrop
f.power.bar inherits f.power's frame level at creation. Bumping
f.power's level later doesn't propagate to existing children, so
CreateBackdrop's parent.fl - 1 backdrop ends up rendering above
the bar — a black bar appears where the power fill should be.
Set the bar's frame level explicitly to parent.fl + 1 after
CreateBackdrop to restore the bar-over-backdrop order.
2026-06-16 18:04:26 -05:00
Brues 27db97d2c4 bump classicapi min version 2026-06-09 19:36:29 -05:00
Brues 8397c09a8d Bags: Simplify Extract Spell Logic 2026-06-08 11:33:05 -05:00
Brues 8ddcf73da6 extract bagsort logic 2026-06-08 11:16:48 -05:00
Brues dd9e683da2 utilize GetSendMailItemLink and GetInboxItemLink 2026-06-08 11:04:51 -05:00
Brues f586bd2285 it's back to 113% :( 2026-06-07 02:39:53 -05:00
Brues ca9c305663 octo removed 113% cap 2026-06-04 02:13:02 -05:00
Brues 7956463927 questitem: use C_QuestLog.GetQuestDetails
Replaces the SelectQuestLogEntry-based scrape (1..50 quest indices, save/
restore log selection, per-quest GetQuestLogQuestText + GetNumQuestLeaderBoards
+ GetQuestLogLeaderBoard, string-blob with _obj_req_ markers, substring-by-
name match in AddTooltip) with a single C_QuestLog.GetQuestIDForLogIndex +
C_QuestLog.GetQuestDetails round-trip per quest.

Build an itemID-keyed { index, count } map up front and look up directly
in AddTooltip. Fixes false matches where an item name happens to substring-
match unrelated quest text.
2026-06-04 02:10:03 -05:00
Brues 38eac636e7 dont need SetHyperlink hook 2026-06-04 02:09:25 -05:00
Brues e12409de60 utilize IsModifierKeyDown 2026-05-31 13:18:20 -05:00
Brues 38b0c74363 cleanup 2026-05-31 13:13:48 -05:00
brues-code 013fcc6c90 add equipment manager (#3)
* equipmentmanager

* use BAG_UPDATE_DELAYED

* CharacterFrame.backdrop doesn't on creation so check onShow

* adjust button positioning

* Show Equipment Set tooltip

* fix icon select scrolling issue

* Equip Set on double click

* slot tooltips: use location-aware GameTooltip methods

Branch on EquipmentManager_GetLocationData: SetBagItem for bagged items,
SetInventoryItem for equipped, fall back to SetInventoryItemByID for
missing or unresolved entries. Surfaces durability/charges/enchants in
the tooltip when the item is reachable.

Also cache C_EquipmentSet.GetItemLocations once per Refresh and store
it on each slot button instead of re-fetching inside the missing-item
border branch.

* purg esome comments

* use GameTooltip_Hide from !!!classicapi

* moved flyout to character frame

* ignore item icon shows on item slots now

* defer ignored-slot toggles until Save

Toggling a slot's ignored state in the flyout no longer immediately
calls SaveEquipmentSet. Instead the change is recorded in a per-set
pendingIgnoredToggles table; the overlay reflects the effective
state (persisted XOR pending) so the user sees the visual change
right away, and Save commits the toggles by replaying them into
ClassicAPI's session ignored list before SaveEquipmentSet.

Pending toggles clear on Save (committed) and on set deletion.

* overhaul icon picker

* fixed width

* fixed issue where selected icon got cleared out

* correct flyout button order

* backport more equipment manager icons

* refactor window

* fixed gear menu

* remove set cap

* bump minimum classicapi version

* bump minimum version to 1.3.3

* row menu: close on outside click

GLOBAL_MOUSE_DOWN fires regardless of which frame absorbs the click
and (unlike a veil frame) doesn't consume the original event, so
clicking another row's gear closes the old menu and opens the new
one in a single click. The gear's own OnClick handles the same-row
toggle close, since GLOBAL_MOUSE_DOWN's anchorBtn check excludes it.

Bumps minimum ClassicAPI to 1.3.4 for GLOBAL_MOUSE_DOWN /
IsMouseButtonDown.

* use pfUI.path

* comment cleanup

* bump min classicapi version

---------

Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
2026-05-31 12:56:30 -05:00
Brues 671b7f3574 use C_AddOns.GetAddOnName 2026-05-30 23:18:16 -05:00
Brues 671939fe9e add auto sort on open feature - disabled by default 2026-05-30 00:31:47 -05:00
Brues d1e51e5202 durability panel shows your collective durability 2026-05-30 00:10:12 -05:00
Brues 94aee19967 use pfUI's GetColorGradient instead of Fizzle colors 2026-05-29 23:15:35 -05:00
Brues 23cc286a0c Fixed issue where item durability tooltip was missing items 2026-05-29 23:15:04 -05:00
Brues 841399a0c7 classicapi migration 2026-05-29 22:56:12 -05:00
Brues 07377ad92e rep remaining label 2026-05-29 21:30:43 -05:00
Brues 6af7da55d6 Reputation Frame: Enhance faction standing bars 2026-05-29 18:49:38 -05:00
Brues ed5ecb1f93 character: durability % per inventory slot
Adds a Fizzle-style durability label to each character pane slot.
Renders at the bottom of the slot icon as "N%" colored by the existing
DURABILITY_THRESHOLD_COLORS table (red < orange < yellow < invasion <
green), or hidden when the item has no durability stat (necks, rings,
trinkets) or the slot is empty.

api/api.lua: new pfUI.api.CreateFontString(f, key, layer, size, flags,
font) helper following the CreateBackdrop pattern — idempotent
get-or-create that attaches the FontString to the parent frame as the
named field. Defaults to pfUI.font_default at C.global.font_size with
OUTLINE on the OVERLAY layer.

skins/blizzard/character.lua: scoreText migrated from the inline
"if not frame.scoreText then ..." block to the new helper as a working
example; new durabilityText created the same way at BOTTOM/size 10.
Durability render added to RefreshCharacterSlot — runs on every
PaperDollItemSlotButton_Update so equip/unequip/repair/damage all
refresh automatically.

api/config.lua + modules/gui.lua: new C.character.inventory.durability
toggle (default "1"). GUI lives under a new top-level "Character" tab
→ "Inventory" sub-tab, leaving room for future "Reputation" / "Skills"
sub-tabs at the same level.
2026-05-29 18:31:58 -05:00
Brues 201a77ccbd IsContainerItemOpenable will now tell us if we can actually open the item 2026-05-29 00:31:53 -05:00
Brues b8da28ebac use IsContainerItemOpenable and bump minimum ClassicAPI version to 1.2.1 2026-05-28 14:59:31 -05:00
Brues f988dff29f no need to show count for unique items 2026-05-28 14:31:09 -05:00
Brues 7c5e4a0e08 add Item Count module 2026-05-28 13:24:50 -05:00
Brues 1fd7895ca7 move away from RAID_CLASS_COLORS dependency 2026-05-28 13:06:00 -05:00
Brues 1a7532195a added !!!ClassicAPI to deps 2026-05-28 12:41:50 -05:00
Brues 9adc57cae6 prevent load if classicapi is not installed 2026-05-28 01:01:53 -05:00
Brues 8e92cf47b3 whitespace 2026-05-28 00:25:05 -05:00
Brues d47287da3a use GetContainerItemCharges from classicapi 2026-05-27 23:50:10 -05:00
Brues 3ef78044fb bags: third-party sort addons rebind existing buttons
pfUI's built-in sorter (modules/bags.lua) always creates the sort
buttons on the right/left bag frames now, so the third-party
RegisterBagSort path's "if not pfUI.bag.right.sort" guard would skip
button-creation entirely — yet still set pfUI.thirdparty.bagsort to
the registering addon's name. Net effect: user installed SortBags or
MrPlow, our internal sort runs anyway. Silent override of user intent.

Strip the dead button-creation paths; rebind the existing buttons'
OnClick + OnEnter to the registered third-party functions instead.
Third-party addons now actually fire when the user clicks. -53 lines.
2026-05-27 23:30:01 -05:00