mirror of
https://github.com/brues-code/pfUI.git
synced 2026-11-03 01:16:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8004f65be0 | ||
|
|
a0c47aa1cf | ||
|
|
f7769ec6ac | ||
|
|
a219bd13dc | ||
|
|
9f5ebf367f |
+1
-1
@@ -13,7 +13,7 @@ do
|
||||
-- on. There pfUI does load, and will throw wherever it reaches for something
|
||||
-- the installed DLL doesn't have yet -- the popup names the cause so those
|
||||
-- errors aren't a mystery.
|
||||
local PFUI_CLASSIC_API_MIN = 11813 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_MIN = 11900 -- (X*10000 + Y*100 + Z)
|
||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||
|
||||
@@ -23,7 +23,7 @@ Provides:
|
||||
- C_NamePlate - Event-driven nameplates (no more per-frame WorldFrame scanning) with real per-plate unit tokens and GUIDs
|
||||
- C_UnitAuras - Replaces over 3k lines of hand-rolled aura tracking
|
||||
- C_Spell - Replaces thousands of hardcoded spell names for each locale and powers castbar
|
||||
- Real cast bars - Actual cast/channel timing, spellID and interrupt state for any unit (C_Spell.UnitCastingInfo)
|
||||
- Real cast bars - Actual cast/channel timing, spellID and interrupt state for any unit (C_Spell.UnitCastingInfo), filled and counted down engine-side (UnitCastingDuration, StatusBar:SetTimerDuration, duration text bindings) with no Lua OnUpdate
|
||||
- Focus - A genuine `focus` unit plus `/focus` and `/clearfocus` (FocusUnit / ClearFocus)
|
||||
- C_EquipmentSet - Full Equipment Manager with GUID-tracked gear sets (tells apart duplicate/enchanted items)
|
||||
- Instant Bag Sorting - C_Container.MoveItem / SwapItems instead of cursor pickup/drop
|
||||
|
||||
+43
-18
@@ -992,28 +992,53 @@ function pfUI.api.GetBorderSize(pref)
|
||||
end
|
||||
end
|
||||
|
||||
-- The scale UIParent ends up with: one UI unit per screen pixel when pixel
|
||||
-- perfect, else the game's own. The game applies its scale only after the
|
||||
-- add-ons and their saved variables are loaded (CGGameUI::Initialize ends in
|
||||
-- OnDisplaySizeChanged), so at load time it is worked out from the same
|
||||
-- options and rules: uiScale while useUiScale is on and it is at least 0.64,
|
||||
-- else 768 over the window height kept within 0.9 and 1. Windows narrower
|
||||
-- than 4:3 cap either at 3/4 of their aspect.
|
||||
local function GetUIScale()
|
||||
if pfUI_config.global.pixelperfect == "1" then return PixelUtil.GetPixelToUIUnitFactor() end
|
||||
|
||||
local width, height = GetPhysicalScreenSize()
|
||||
local aspect = GetCVar("widescreen") == "1" and width / height or 4/3
|
||||
local function fit(scale)
|
||||
return aspect < 4/3 and math.min(scale, aspect * .75) or scale
|
||||
end
|
||||
|
||||
if GetCVar("useUiScale") == "1" then
|
||||
local scale = fit(tonumber(GetCVar("uiScale")))
|
||||
if scale >= .64 then return scale end
|
||||
end
|
||||
|
||||
return math.max(fit(height > 768 and 768 / height or 1), .9)
|
||||
end
|
||||
|
||||
-- [ UpdateUIScale ]
|
||||
-- Gives UIParent the pixel perfect scale when enabled, else leaves the game's
|
||||
-- own. The engine puts its own scale back on every window resize and scale
|
||||
-- option change, so this runs again on each UI_SCALE_CHANGED. Borders keep
|
||||
-- the pixel size they were built with, so a change of it offers a reload once.
|
||||
function pfUI.api.UpdateUIScale()
|
||||
if pfUI_config.global.pixelperfect == "1" then
|
||||
UIParent:SetScale(PixelUtil.GetPixelToUIUnitFactor())
|
||||
end
|
||||
|
||||
if not pfUI.pixel or pfUI.scaleprompt then return end
|
||||
if math.abs(PixelUtil.GetPixelToUIUnitFactor() / UIParent:GetScale() - pfUI.pixel) < .0001 then return end
|
||||
|
||||
pfUI.scaleprompt = true
|
||||
CreateQuestionDialog(T["The UI-Scale has changed. Reload the UI to redraw the borders?"], ReloadUI)
|
||||
end
|
||||
|
||||
-- [ GetPerfectPixel ]
|
||||
-- Returns a number that equals a real pixel on regular scaled frames.
|
||||
-- Respects the current UI-scale and calculates a real pixel based on
|
||||
-- the screen resolution and the 768px sized drawlayer.
|
||||
-- Returns the size of one physical pixel in UIParent units.
|
||||
function pfUI.api.GetPerfectPixel()
|
||||
if pfUI.pixel then return pfUI.pixel end
|
||||
|
||||
if pfUI_config.appearance.border.pixelperfect == "1" then
|
||||
local scale = GetCVar("useUiScale") == "1" and GetCVar("uiScale") or "1"
|
||||
local resolution = GetCVar("gxResolution")
|
||||
local _, _, screenwidth, screenheight = strfind(resolution, "(.+)x(.+)")
|
||||
|
||||
pfUI.pixel = 768 / screenheight / scale
|
||||
pfUI.pixel = pfUI.pixel > 1 and 1 or pfUI.pixel
|
||||
|
||||
-- autodetect and zoom for HiDPI displays
|
||||
if pfUI_config.appearance.border.hidpi == "1" then
|
||||
pfUI.pixel = pfUI.pixel < .5 and pfUI.pixel * 2 or pfUI.pixel
|
||||
end
|
||||
else
|
||||
pfUI.pixel = .7
|
||||
end
|
||||
pfUI.pixel = PixelUtil.GetPixelToUIUnitFactor() / GetUIScale()
|
||||
|
||||
pfUI.backdrop = {
|
||||
bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0,
|
||||
|
||||
@@ -129,9 +129,7 @@ function pfUI:LoadConfig()
|
||||
pfUI:UpdateConfig("appearance", "border", "color", "0.2,0.2,0.2,1")
|
||||
pfUI:UpdateConfig("appearance", "border", "shadow", "0")
|
||||
pfUI:UpdateConfig("appearance", "border", "shadow_intensity", ".35")
|
||||
pfUI:UpdateConfig("appearance", "border", "pixelperfect", "1")
|
||||
pfUI:UpdateConfig("appearance", "border", "force_blizz", "0")
|
||||
pfUI:UpdateConfig("appearance", "border", "hidpi", "1")
|
||||
pfUI:UpdateConfig("appearance", "border", "default", "3")
|
||||
pfUI:UpdateConfig("appearance", "border", "nameplates", "-1")
|
||||
pfUI:UpdateConfig("appearance", "border", "actionbars", "-1")
|
||||
|
||||
+8
-7
@@ -85,7 +85,7 @@ local function SetupCooldown(cooldown)
|
||||
cooldown:SetReverse(kind == "aura")
|
||||
cooldown:SetMinimumCountdownDuration(kind == "spell" and tonumber(C.cooldown.threshold) * 1000 or 0)
|
||||
cooldown:SetCountdownFormatter(GetFormatter())
|
||||
UpdateFont(cooldown, cooldown:GetParent():GetHeight())
|
||||
UpdateFont(cooldown, cooldown:GetParent():GetUnscaledHeight())
|
||||
end
|
||||
|
||||
-- applies the "foreign" timers to another addon's cooldown. They only take
|
||||
@@ -107,7 +107,7 @@ local function SetupForeign(cooldown)
|
||||
|
||||
cooldown:SetMinimumCountdownDuration(tonumber(C.cooldown.threshold) * 1000)
|
||||
cooldown:SetCountdownFormatter(GetFormatter())
|
||||
UpdateFont(cooldown, (cooldown:GetParent() or cooldown):GetHeight())
|
||||
UpdateFont(cooldown, (cooldown:GetParent() or cooldown):GetUnscaledHeight())
|
||||
end
|
||||
|
||||
-- runs as a pfUI cooldown's timer starts: a timer with a total brings back
|
||||
@@ -196,9 +196,10 @@ function pfUI.api.GetAuraTimer(duration, expirationTime)
|
||||
return start, dur
|
||||
end
|
||||
|
||||
-- [ GetColoredTimeString ] --
|
||||
-- 'remaining' [number] the time in seconds that should be converted
|
||||
-- return [string] the time as cooldown numbers show it
|
||||
function pfUI.api.GetColoredTimeString(remaining)
|
||||
return GetFormatter():FormatNumber(remaining)
|
||||
-- [ GetTimeFormatter ] --
|
||||
-- The formatter cooldown numbers use, for other timers to show time the same
|
||||
-- way. Hold it rather than a copy: a settings change updates it in place.
|
||||
-- return [formatter] a NumericRuleFormatter
|
||||
function pfUI.api.GetTimeFormatter()
|
||||
return GetFormatter()
|
||||
end
|
||||
|
||||
+5
-10
@@ -601,7 +601,7 @@ function pfUI.api.SkinDropDown(frame, cr, cg, cb, useSmall)
|
||||
|
||||
button:HookScript("OnClick", function()
|
||||
local DropDownListWidth = DropDownList1:GetWidth()
|
||||
local DropDownFrameWidth = frame.backdrop:GetWidth()
|
||||
local DropDownFrameWidth = frame.backdrop:GetUnscaledWidth()
|
||||
if DropDownListWidth < DropDownFrameWidth then
|
||||
local diff = DropDownFrameWidth - DropDownListWidth
|
||||
DropDownList1:SetWidth(DropDownList1:GetWidth() + diff)
|
||||
@@ -834,10 +834,7 @@ function pfUI.api.CreateInfoBox(text, time, parent, height)
|
||||
end)
|
||||
|
||||
infobox:SetScript("OnUpdate", function()
|
||||
local time = infobox.lastshow + infobox.duration - GetTime()
|
||||
infobox.timeout:SetValue(time)
|
||||
|
||||
if GetTime() > infobox.lastshow + infobox.duration then
|
||||
if infobox.duration:HasExpired() then
|
||||
if not infobox.fade:IsPlaying() then infobox.fade:Play() end
|
||||
elseif MouseIsOverHitRect(this) then
|
||||
this:SetAlpha(max(0.4, this:GetAlpha() - .1))
|
||||
@@ -857,6 +854,8 @@ function pfUI.api.CreateInfoBox(text, time, parent, height)
|
||||
infobox.timeout = CreateFrame("StatusBar", nil, infobox)
|
||||
infobox.timeout:SetStatusBarTexture(pfUI.media["img:bar"])
|
||||
infobox.timeout:SetStatusBarColor(.3,1,.8,1)
|
||||
infobox.duration = C_DurationUtil.CreateDuration()
|
||||
infobox.timeout:SetTimerDuration(infobox.duration, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.RemainingTime)
|
||||
|
||||
infobox:ClearAllPoints()
|
||||
infobox.text:SetAllPoints(infobox)
|
||||
@@ -872,11 +871,7 @@ function pfUI.api.CreateInfoBox(text, time, parent, height)
|
||||
end
|
||||
|
||||
infobox.text:SetText(text)
|
||||
infobox.timeout:SetMinMaxValues(0, time)
|
||||
infobox.timeout:SetValue(time)
|
||||
|
||||
infobox.duration = time
|
||||
infobox.lastshow = GetTime()
|
||||
infobox.duration:SetTimeFromStart(GetTime(), time)
|
||||
|
||||
infobox:SetSize(infobox.text:GetStringWidth() + 50, height)
|
||||
infobox:SetParent(parent)
|
||||
|
||||
+2
-2
@@ -2042,7 +2042,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
local size
|
||||
|
||||
if disptype == "4" or disptype == "3" then
|
||||
size = unit.hp.bar:GetHeight() * tonumber(unit.config.debuff_ind_size)
|
||||
size = unit.hp.bar:GetUnscaledHeight() * tonumber(unit.config.debuff_ind_size)
|
||||
if size ~= indicator.size or disptype ~= indicator.disp or indipos ~= indicator.ipos then
|
||||
indicator:ClearAllPoints()
|
||||
indicator:SetPoint(indipos, 0, 0)
|
||||
@@ -2447,7 +2447,7 @@ function pfUI.uf:AddIcon(frame, pos, icon, timeleft, stacks, start, duration)
|
||||
|
||||
if not frame.hp then return end
|
||||
local frame = frame.hp.bar
|
||||
if pos > 6 or pos > ceil(frame:GetWidth() / iconsize) then return end
|
||||
if pos > 6 or pos > ceil(frame:GetUnscaledWidth() / iconsize) then return end
|
||||
|
||||
frame.icon = frame.icon or CreateFrame("Frame", nil, frame)
|
||||
|
||||
|
||||
Vendored
-1
@@ -907,7 +907,6 @@ pfUI_translation["deDE"] = {
|
||||
["Chat Tab"] = "Chat Tab",
|
||||
["Libpredict"] = "Libpredict",
|
||||
["Panel Alignment"] = "Panel Ausrichtung",
|
||||
["Nameplate Update Rate"] = "Namensplaketten Aktualisierungsrate",
|
||||
["Target/Casting Plates"] = "Ziel/Cast Plaketten",
|
||||
["Tooltip Update Rate"] = "Tooltip Aktualisierungsrate",
|
||||
["Cursor Follow"] = "Cursor Folgen",
|
||||
|
||||
Vendored
-1
@@ -939,7 +939,6 @@ pfUI_translation["enUS"] = {
|
||||
["Chat Tab"] = nil,
|
||||
["Libpredict"] = nil,
|
||||
["Panel Alignment"] = nil,
|
||||
["Nameplate Update Rate"] = nil,
|
||||
["Target/Casting Plates"] = nil,
|
||||
["Tooltip Update Rate"] = nil,
|
||||
["Cursor Follow"] = nil,
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
<Include file="..\modules\gm.lua"/>
|
||||
<Include file="..\modules\mirrortimers.lua"/>
|
||||
<Include file="..\modules\feigndeath.lua"/>
|
||||
<Include file="..\modules\pixelperfect.lua"/>
|
||||
<Include file="..\modules\hdgraphic.lua"/>
|
||||
<Include file="..\modules\share.lua"/>
|
||||
<Include file="..\modules\tracking.lua"/>
|
||||
|
||||
@@ -31,7 +31,6 @@ libthrottle.presetNames = {
|
||||
|
||||
-- Default throttle categories
|
||||
libthrottle.defaults = {
|
||||
nameplates_castbar = "custom",
|
||||
tooltip_cursor = "fastest",
|
||||
chat_tab = "custom",
|
||||
swingtimer = "custom",
|
||||
@@ -155,7 +154,6 @@ libthrottle:SetScript("OnEvent", function()
|
||||
end
|
||||
|
||||
-- Set defaults for custom fields if missing
|
||||
if not _G.pfUI_throttle.nameplates_castbar_custom then _G.pfUI_throttle.nameplates_castbar_custom = "100" end
|
||||
if not _G.pfUI_throttle.tooltip_cursor_custom then _G.pfUI_throttle.tooltip_cursor_custom = "10" end
|
||||
if not _G.pfUI_throttle.chat_tab_custom then _G.pfUI_throttle.chat_tab_custom = "10" end
|
||||
if not _G.pfUI_throttle.swingtimer_custom then _G.pfUI_throttle.swingtimer_custom = "50" end
|
||||
|
||||
+243
-242
@@ -9,7 +9,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
local rawborder, border = GetBorderSize("actionbars")
|
||||
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
|
||||
|
||||
local eventcache = { } -- contains a list of events that shall be processed later -> [event] = true
|
||||
local passcache = { } -- contains the passes over the visible buttons that shall run later -> [pass] = true
|
||||
local updatecache = { } -- contains a list of buttons slots that shall be refreshed later -> [slot] = true
|
||||
local buttoncache = { } -- contains a list of all buttons ever created -> [slot] = frame
|
||||
|
||||
@@ -54,18 +54,21 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
if f.Hide then f:Hide() end
|
||||
end
|
||||
|
||||
-- also abbreviate mouse buttons
|
||||
local OrigGetBindingText = GetBindingText
|
||||
local function GetBindingText(msg, mod, abbrev)
|
||||
local txt = OrigGetBindingText(msg, mod, abbrev)
|
||||
if abbrev then
|
||||
txt = string.gsub(txt, _G[string.format("%s%s", mod, "BUTTON3")], "MB3")
|
||||
txt = string.gsub(txt, _G[string.format("%s%s", mod, "BUTTON4")], "MB4")
|
||||
txt = string.gsub(txt, _G[string.format("%s%s", mod, "BUTTON5")], "MB5")
|
||||
txt = string.gsub(txt, _G[string.format("%s%s", mod, "MOUSEWHEELDOWN")], "MWD")
|
||||
txt = string.gsub(txt, _G[string.format("%s%s", mod, "MOUSEWHEELUP")], "MWU")
|
||||
-- the abbreviated text of the key bound to a command, mouse buttons included
|
||||
local mouse_abbrevs = {
|
||||
[_G.KEY_BUTTON3] = "MB3",
|
||||
[_G.KEY_BUTTON4] = "MB4",
|
||||
[_G.KEY_BUTTON5] = "MB5",
|
||||
[_G.KEY_MOUSEWHEELDOWN] = "MWD",
|
||||
[_G.KEY_MOUSEWHEELUP] = "MWU",
|
||||
}
|
||||
|
||||
local function GetKeybindText(command)
|
||||
local text = GetBindingText(GetBindingKey(command), "KEY_", 1)
|
||||
for name, abbrev in pairs(mouse_abbrevs) do
|
||||
text = text:gsub(name, abbrev)
|
||||
end
|
||||
return txt
|
||||
return text
|
||||
end
|
||||
|
||||
kill(MainMenuBar)
|
||||
@@ -83,33 +86,32 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
_G.SHOW_MULTI_ACTIONBAR_3 = nil
|
||||
_G.SHOW_MULTI_ACTIONBAR_4 = nil
|
||||
|
||||
-- events that provide special updater functions
|
||||
local special_events = {
|
||||
["ACTIONBAR_UPDATE_COOLDOWN"] = true,
|
||||
["ACTIONBAR_UPDATE_USABLE"] = true,
|
||||
["ACTIONBAR_UPDATE_STATE"] = true,
|
||||
-- events that refresh one part of every visible button -> [event] = pass.
|
||||
-- Page changes only touch the main bar, whose pager handles them.
|
||||
local pass_events = {
|
||||
["ACTIONBAR_UPDATE_COOLDOWN"] = "cooldown",
|
||||
["ACTIONBAR_UPDATE_USABLE"] = "usable",
|
||||
["ACTIONBAR_UPDATE_STATE"] = "state",
|
||||
-- the active border of attack, auto repeat and tradeskill actions
|
||||
["PLAYER_ENTER_COMBAT"] = "state",
|
||||
["PLAYER_LEAVE_COMBAT"] = "state",
|
||||
["START_AUTOREPEAT_SPELL"] = "state",
|
||||
["STOP_AUTOREPEAT_SPELL"] = "state",
|
||||
["CRAFT_SHOW"] = "state",
|
||||
["CRAFT_CLOSE"] = "state",
|
||||
["TRADE_SKILL_SHOW"] = "state",
|
||||
["TRADE_SKILL_CLOSE"] = "state",
|
||||
-- fires on every ammo shot / consumable use, but only counts, equipped
|
||||
-- state, cooldowns and usability can change from it
|
||||
["UNIT_INVENTORY_CHANGED"] = true,
|
||||
["UNIT_INVENTORY_CHANGED"] = "inventory",
|
||||
-- the keybind text of every button, shown or not
|
||||
["UPDATE_BINDINGS"] = "bindings",
|
||||
}
|
||||
|
||||
-- events that are shared across all buttons
|
||||
-- events that refresh every button
|
||||
local global_events = {
|
||||
-- slot/button updates
|
||||
["PLAYER_ENTERING_WORLD"] = true,
|
||||
["ACTIONBAR_SLOT_CHANGED"] = true,
|
||||
["UPDATE_BINDINGS"] = true,
|
||||
["ACTIONBAR_PAGE_CHANGED"] = true,
|
||||
["UPDATE_BONUS_ACTIONBAR"] = true,
|
||||
["CRAFT_SHOW"] = true,
|
||||
["CRAFT_CLOSE"] = true,
|
||||
["TRADE_SKILL_SHOW"] = true,
|
||||
["TRADE_SKILL_CLOSE"] = true,
|
||||
["PLAYER_ENTER_COMBAT"] = true,
|
||||
["PLAYER_LEAVE_COMBAT"] = true,
|
||||
-- auto repeat action
|
||||
["START_AUTOREPEAT_SPELL"] = true,
|
||||
["STOP_AUTOREPEAT_SPELL"] = true,
|
||||
}
|
||||
|
||||
-- events that are used for the aura/shapeshift bar
|
||||
@@ -394,37 +396,55 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
self.equipped:SetShown(IsEquippedAction(sid) and C.bars.showequipped == "1")
|
||||
end
|
||||
|
||||
local start, duration, enable, castable, autocast, token
|
||||
local grid, sid, id, bar, active, texture, _
|
||||
-- the keybind text, which an empty hidden button hides as well. The binding
|
||||
-- itself is only read on UPDATE_BINDINGS (the "bindings" pass).
|
||||
local function ButtonKeybindUpdate(self)
|
||||
self.keybind:SetText(not self.hide and self.binding or "")
|
||||
end
|
||||
|
||||
-- the active border of current, attack and auto repeat actions, which the
|
||||
-- "statechange" animation follows. A full update applies it unconditionally.
|
||||
local function ButtonActiveUpdate(self, active, force)
|
||||
if active then
|
||||
if not self.isactive and C.bars.animmode == "statechange" then
|
||||
PlayButtonAnimation(self)
|
||||
end
|
||||
|
||||
if force or not self.isactive then
|
||||
self.backdrop:SetBackdropBorderColor(cr,cg,cb,1)
|
||||
self.active:Show()
|
||||
self.isactive = true
|
||||
end
|
||||
elseif force or self.isactive then
|
||||
self.backdrop:SetBackdropBorderColor(er,eg,eb,ea)
|
||||
self.active:Hide()
|
||||
self.isactive = nil
|
||||
end
|
||||
end
|
||||
|
||||
local castable, autocast, token
|
||||
local grid, sid, active, texture, _
|
||||
local function ButtonSlotUpdate(self)
|
||||
if not self then return end
|
||||
self = self or this
|
||||
sid = self.id -- 1 to 120
|
||||
|
||||
-- reset shared variables
|
||||
castable, autocast, token = nil, nil, nil
|
||||
|
||||
-- set the own ID for compatibility to some vanilla addons
|
||||
self:SetID(self.id)
|
||||
self:SetID(sid)
|
||||
|
||||
grid = self.bar == 12 and showgrid_pet or showgrid
|
||||
|
||||
if self.bar == 11 then
|
||||
-- stance button
|
||||
bar = self.bar
|
||||
id = sid
|
||||
texture, _, active = GetShapeshiftFormInfo(id)
|
||||
texture, _, active = GetShapeshiftFormInfo(sid)
|
||||
elseif self.bar == 12 then
|
||||
-- pet button
|
||||
bar = self.bar
|
||||
id = sid
|
||||
_, _, texture, token, active, castable, autocast = GetPetActionInfo(id)
|
||||
_, _, texture, token, active, castable, autocast = GetPetActionInfo(sid)
|
||||
texture = token and _G[texture] or texture
|
||||
else
|
||||
active = IsCurrentAction(sid) or IsAutoRepeatAction(sid)
|
||||
texture = GetActionTexture(sid)
|
||||
bar = GetActiveBar()
|
||||
id = self.bar == 1 and self.slot or sid-((self.bar)-1)*12
|
||||
end
|
||||
|
||||
if not self.showempty and self.backdrop and not texture and grid == 0 then
|
||||
@@ -435,19 +455,6 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
self.hide = nil
|
||||
end
|
||||
|
||||
-- active border
|
||||
if active then
|
||||
if C.bars.animmode == "statechange" and not self.active:IsShown() then
|
||||
PlayButtonAnimation(self)
|
||||
end
|
||||
|
||||
self.backdrop:SetBackdropBorderColor(cr,cg,cb,1)
|
||||
self.active:Show()
|
||||
else
|
||||
self.backdrop:SetBackdropBorderColor(er,eg,eb,ea)
|
||||
self.active:Hide()
|
||||
end
|
||||
|
||||
ButtonInventoryUpdate(self)
|
||||
|
||||
if self.bar ~= 11 and self.bar ~= 12 then
|
||||
@@ -481,14 +488,8 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
self.autocastable:SetShown(castable and C.bars.showcastable == "1")
|
||||
end
|
||||
|
||||
-- keybinds
|
||||
if not self.hide and self.bar == 1 and self.bar ~= 11 and self.bar ~= 12 then
|
||||
self.keybind:SetText(GetBindingText(GetBindingKey("ACTIONBUTTON"..id), "KEY_", 1))
|
||||
elseif not self.hide and buttontypes[self.bar] then
|
||||
self.keybind:SetText(GetBindingText(GetBindingKey(buttontypes[self.bar]..id), "KEY_", 1))
|
||||
else
|
||||
self.keybind:SetText("")
|
||||
end
|
||||
ButtonActiveUpdate(self, active, true)
|
||||
ButtonKeybindUpdate(self)
|
||||
end
|
||||
|
||||
local sid, usable, oom, _
|
||||
@@ -498,8 +499,9 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
|
||||
if self.bar == 11 then
|
||||
_, _, _, usable = GetShapeshiftFormInfo(sid)
|
||||
oom = nil
|
||||
elseif self.bar == 12 then
|
||||
usable = true
|
||||
usable, oom = true, nil
|
||||
else
|
||||
usable, oom = IsUsableAction(sid)
|
||||
end
|
||||
@@ -545,8 +547,6 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
|
||||
local start, duration, enable
|
||||
local function ButtonCooldownUpdate(button)
|
||||
if not button then return end
|
||||
|
||||
if button.bar == 11 then
|
||||
start, duration, enable = GetShapeshiftFormCooldown(button.id)
|
||||
elseif button.bar == 12 then
|
||||
@@ -556,42 +556,30 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
end
|
||||
|
||||
-- Nil-protect: GetActionCooldown can return nil during macro parsing/indexing
|
||||
if start and duration then
|
||||
CooldownFrame_SetTimer(button.cd, start, duration, enable or 1)
|
||||
end
|
||||
if not start or not duration then return end
|
||||
enable = enable or 1
|
||||
|
||||
-- most buttons keep their cooldown through a cooldown event
|
||||
if start == button.cdstart and duration == button.cdduration and enable == button.cdenable then return end
|
||||
button.cdstart, button.cdduration, button.cdenable = start, duration, enable
|
||||
|
||||
CooldownFrame_SetTimer(button.cd, start, duration, enable)
|
||||
end
|
||||
|
||||
local _, active
|
||||
local function ButtonIsActiveUpdate(button)
|
||||
if not button then return end
|
||||
|
||||
if button.bar == 11 then
|
||||
_, _, active, _ = GetShapeshiftFormInfo(button.id)
|
||||
_, _, active = GetShapeshiftFormInfo(button.id)
|
||||
elseif button.bar == 12 then
|
||||
_, _, _, _, active, _, _ = GetPetActionInfo(button.id)
|
||||
_, _, _, _, active = GetPetActionInfo(button.id)
|
||||
else
|
||||
active = IsCurrentAction(button.id) or IsAutoRepeatAction(button.id)
|
||||
end
|
||||
|
||||
-- active border
|
||||
if active then
|
||||
if not button.border_active then
|
||||
button.backdrop:SetBackdropBorderColor(cr,cg,cb,1)
|
||||
button.border_active = true
|
||||
end
|
||||
|
||||
button.active:Show()
|
||||
else
|
||||
if button.border_active then
|
||||
button.backdrop:SetBackdropBorderColor(er,eg,eb,ea)
|
||||
button.border_active = nil
|
||||
end
|
||||
|
||||
button.active:Hide()
|
||||
end
|
||||
ButtonActiveUpdate(button, active)
|
||||
end
|
||||
|
||||
|
||||
-- everything of a button; the slot update covers its active state
|
||||
local function ButtonFullUpdate(button)
|
||||
if not button then return end
|
||||
|
||||
@@ -599,140 +587,140 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
ButtonRangeUpdate(button)
|
||||
ButtonUsableUpdate(button)
|
||||
ButtonCooldownUpdate(button)
|
||||
ButtonIsActiveUpdate(button)
|
||||
end
|
||||
|
||||
local function BarsEvent(self)
|
||||
self = self or this
|
||||
-- the pfActionBar frame handles the events of every button; its array part
|
||||
-- holds the bar frames, bars[1] to bars[12]
|
||||
local bars = CreateFrame("Frame", "pfActionBar", UIParent)
|
||||
|
||||
-- Updates wait for the next frame, so the events of one frame share one
|
||||
-- pass. Passes and full updates skip hidden bars, which catch up as they
|
||||
-- show (BarShow). The shown buttons of a bar are its first `count` ones.
|
||||
local scheduled
|
||||
local function Flush()
|
||||
scheduled = nil
|
||||
|
||||
local inventory, cooldown, usable, state = passcache.inventory, passcache.cooldown, passcache.usable, passcache.state
|
||||
local bindings = passcache.bindings
|
||||
table.wipe(passcache)
|
||||
|
||||
if inventory or cooldown or usable or state then
|
||||
for i = 1, 12 do
|
||||
local bar = bars[i]
|
||||
if bar:IsVisible() then
|
||||
for j = 1, bar.count do
|
||||
local button = bar[j]
|
||||
if inventory then ButtonInventoryUpdate(button) end
|
||||
if inventory or cooldown then ButtonCooldownUpdate(button) end
|
||||
if inventory or usable then ButtonUsableUpdate(button) end
|
||||
if state then ButtonIsActiveUpdate(button) end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- the keybinds of hidden buttons as well, as they don't catch up on them
|
||||
if bindings then
|
||||
for _, button in pairs(buttoncache) do
|
||||
button.binding = GetKeybindText(button.bindcommand)
|
||||
ButtonKeybindUpdate(button)
|
||||
end
|
||||
end
|
||||
|
||||
-- a slot refreshes its own button and the main bar button paged to it
|
||||
local page = bars[1][1].id - 1
|
||||
for slot in pairs(updatecache) do
|
||||
updatecache[slot] = nil
|
||||
|
||||
local button = buttoncache[slot]
|
||||
if button and button:IsVisible() then
|
||||
pfUI.bars.ButtonFullUpdate(button)
|
||||
end
|
||||
|
||||
local paged = slot > page and slot <= page + 12 and bars[1][slot - page]
|
||||
if paged and paged ~= button and paged:IsVisible() then
|
||||
pfUI.bars.ButtonFullUpdate(paged)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Schedule()
|
||||
if scheduled then return end
|
||||
scheduled = true
|
||||
RunNextFrame(Flush)
|
||||
end
|
||||
|
||||
-- queues a full update of the button in a slot
|
||||
local function QueueSlot(slot)
|
||||
updatecache[slot] = true
|
||||
Schedule()
|
||||
end
|
||||
|
||||
-- queues a pass over the visible buttons
|
||||
local function QueuePass(pass)
|
||||
passcache[pass] = true
|
||||
Schedule()
|
||||
end
|
||||
|
||||
-- ClassicAPI has no range event for action slots yet, so the visible
|
||||
-- buttons are polled at the rate of the stock bars
|
||||
local function RangeUpdate()
|
||||
for i = 1, 10 do
|
||||
local bar = bars[i]
|
||||
if bar:IsVisible() then
|
||||
for j = 1, bar.count do
|
||||
ButtonRangeUpdate(bar[j])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- passes skip hidden bars, so a bar refreshes its buttons as it shows
|
||||
local function BarShow()
|
||||
local offset = (this:GetID() - 1) * 12
|
||||
for j = 1, this.count do
|
||||
QueueSlot(offset + j)
|
||||
end
|
||||
end
|
||||
|
||||
local function BarsEvent()
|
||||
-- refresh only specific slots
|
||||
if event == "ACTIONBAR_SLOT_CHANGED" and arg1 and arg1 ~= 0 then
|
||||
updatecache[arg1] = true
|
||||
QueueSlot(arg1)
|
||||
return
|
||||
end
|
||||
|
||||
-- run special refresh functions on next update
|
||||
if special_events[event] then
|
||||
eventcache[event] = true
|
||||
-- refresh one part of every visible button
|
||||
if pass_events[event] then
|
||||
QueuePass(pass_events[event])
|
||||
return
|
||||
end
|
||||
|
||||
-- handle aura events
|
||||
-- auras and forms change the stance buttons
|
||||
if aura_events[event] then
|
||||
for j=1,12 do
|
||||
if self[11] and self[11][j] then
|
||||
updatecache[self[11][j].slot] = true
|
||||
end
|
||||
for j = 1, bars[11].count do
|
||||
QueueSlot(bars[11][j].slot)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- handle pet events
|
||||
if pet_events[event] then
|
||||
for j=1,12 do
|
||||
if self[12] and self[12][j] then
|
||||
updatecache[self[12][j].slot] = true
|
||||
end
|
||||
for j = 1, bars[12].count do
|
||||
QueueSlot(bars[12][j].slot)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- handle global events
|
||||
for id in pairs(buttoncache) do
|
||||
updatecache[id] = true
|
||||
end
|
||||
end
|
||||
|
||||
local self, button, unlock
|
||||
-- Main update loop with throttle for performance optimization
|
||||
local function BarsUpdate(self)
|
||||
self = self or this
|
||||
|
||||
-- Throttle for performance
|
||||
if (this.tick_main or 0) > GetTime() then return end
|
||||
this.tick_main = GetTime() + 0.025
|
||||
|
||||
if pfUI.unlock then
|
||||
-- update all bars when entering unlock
|
||||
if pfUI.unlock:IsShown() ~= unlock then
|
||||
pfUI.bars:UpdateConfig()
|
||||
unlock = pfUI.unlock:IsShown()
|
||||
end
|
||||
end
|
||||
|
||||
-- The cached passes below only touch visible buttons. Hidden ones (other
|
||||
-- pages, hidden bars) are flagged stale and get a full update once the
|
||||
-- range pass sees them visible again.
|
||||
|
||||
-- run cached inventory changes (ammo, reagents, consumables)
|
||||
if eventcache["UNIT_INVENTORY_CHANGED"] then
|
||||
eventcache["UNIT_INVENTORY_CHANGED"] = nil
|
||||
for id, button in pairs(buttoncache) do
|
||||
if button:IsVisible() then
|
||||
ButtonInventoryUpdate(button)
|
||||
ButtonCooldownUpdate(button)
|
||||
ButtonUsableUpdate(button)
|
||||
else
|
||||
button.stale = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- run cached usable usable actions
|
||||
if eventcache["ACTIONBAR_UPDATE_USABLE"] then
|
||||
eventcache["ACTIONBAR_UPDATE_USABLE"] = nil
|
||||
for id, button in pairs(buttoncache) do
|
||||
if button:IsVisible() then ButtonUsableUpdate(button) else button.stale = true end
|
||||
end
|
||||
end
|
||||
|
||||
-- run cached cooldown events
|
||||
if eventcache["ACTIONBAR_UPDATE_COOLDOWN"] then
|
||||
eventcache["ACTIONBAR_UPDATE_COOLDOWN"] = nil
|
||||
for id, button in pairs(buttoncache) do
|
||||
if button:IsVisible() then ButtonCooldownUpdate(button) else button.stale = true end
|
||||
end
|
||||
end
|
||||
|
||||
-- run cached action state events
|
||||
if eventcache["ACTIONBAR_UPDATE_STATE"] then
|
||||
eventcache["ACTIONBAR_UPDATE_STATE"] = nil
|
||||
for id, button in pairs(buttoncache) do
|
||||
if button:IsVisible() then ButtonIsActiveUpdate(button) else button.stale = true end
|
||||
end
|
||||
end
|
||||
|
||||
for id in pairs(updatecache) do
|
||||
-- run updates based on slot
|
||||
pfUI.bars.ButtonFullUpdate(buttoncache[id])
|
||||
|
||||
-- run updates on paging actionbar if required
|
||||
for i=1,12 do
|
||||
if pfUI.bars[1][i].id == id then
|
||||
pfUI.bars.ButtonFullUpdate(pfUI.bars[1][i])
|
||||
end
|
||||
end
|
||||
|
||||
-- clear update cache
|
||||
updatecache[id] = nil
|
||||
end
|
||||
|
||||
if ( this.tick or .2) > GetTime() then return else this.tick = GetTime() + .2 end
|
||||
|
||||
for id, button in pairs(buttoncache) do
|
||||
if button.stale and button:IsVisible() then
|
||||
-- catch up on updates skipped while hidden
|
||||
button.stale = nil
|
||||
ButtonFullUpdate(button)
|
||||
elseif button:IsShown() then
|
||||
ButtonRangeUpdate(button)
|
||||
-- refresh every button and its keybind
|
||||
if global_events[event] then
|
||||
QueuePass("bindings")
|
||||
for slot in pairs(buttoncache) do
|
||||
QueueSlot(slot)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- create the main event and update handler for pfUI actionbars
|
||||
local bars = CreateFrame("Frame", "pfActionBar", UIParent)
|
||||
|
||||
-- The only unit events in the tables above; both concern the player alone.
|
||||
-- A registration keeps its kind, so these have to go in unit-filtered from
|
||||
-- the start -- RegisterUnitEvent over a plain registration stays plain.
|
||||
@@ -750,7 +738,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
end
|
||||
end
|
||||
|
||||
for event in pairs(special_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(pass_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(global_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(aura_events) do RegisterBarEvent(event) end
|
||||
for event in pairs(pet_events) do RegisterBarEvent(event) end
|
||||
@@ -758,9 +746,6 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
-- refresh actionbar buttons on event
|
||||
bars:SetScript("OnEvent", BarsEvent)
|
||||
|
||||
-- update actionbar buttons
|
||||
bars:SetScript("OnUpdate", BarsUpdate)
|
||||
|
||||
-- enable bar paging via secure functions
|
||||
local function EnablePaging(bar)
|
||||
if not bar.pager then
|
||||
@@ -776,9 +761,8 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
|
||||
local active = GetActiveBar()
|
||||
for i=1,12 do
|
||||
local id = i + (active-1)*12
|
||||
bar[i].id = id
|
||||
updatecache[i] = true
|
||||
bar[i].id = i + (active-1)*12
|
||||
QueueSlot(i)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1006,6 +990,9 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
-- set a static slot
|
||||
f.slot = id
|
||||
|
||||
-- the binding command of the button, fixed on the paged main bar too
|
||||
f.bindcommand = (bar == 1 and "ACTIONBUTTON" or buttontypes[bar]) .. button
|
||||
|
||||
-- cooldown
|
||||
f.cd = CreateCooldown(f, "spell", C.bars, "timers", f:GetName() .. "Cooldown")
|
||||
|
||||
@@ -1168,6 +1155,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
|
||||
-- don't process empty bars
|
||||
if buttons == 0 then
|
||||
bars[i].count = 0
|
||||
bars[i]:Hide()
|
||||
return
|
||||
end
|
||||
@@ -1186,6 +1174,8 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
local init = not bars[i]
|
||||
bars[i] = bars[i] or CreateFrame("Frame", "pfActionBar" .. barnames[i], UIParent)
|
||||
bars[i]:SetID(i)
|
||||
bars[i].count = buttons
|
||||
if init then bars[i]:SetScript("OnShow", BarShow) end
|
||||
|
||||
-- autohide
|
||||
if autohide == "1" then
|
||||
@@ -1201,18 +1191,12 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
-- only show when pet actions exists
|
||||
bars[i]:SetShown(PetHasActionBar() or pfUI.unlock and pfUI.unlock:IsShown())
|
||||
|
||||
-- show/hide petbar on petbar updates
|
||||
-- show/hide petbar on petbar updates; the pet events of the
|
||||
-- pfActionBar frame refresh its buttons
|
||||
if init then
|
||||
bars[i]:RegisterEvent("PET_BAR_UPDATE")
|
||||
bars[i]:SetScript("OnEvent", function()
|
||||
-- hide obsolete buttons
|
||||
for i=1, NUM_PET_ACTION_SLOTS do
|
||||
if not PetHasActionBar() and bars[12][i] then
|
||||
bars[12][i]:Hide()
|
||||
end
|
||||
end
|
||||
-- refresh layout
|
||||
CreateActionBar(12)
|
||||
this:SetShown(PetHasActionBar() or pfUI.unlock and pfUI.unlock:IsShown())
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -1270,7 +1254,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
end
|
||||
|
||||
-- refresh button
|
||||
updatecache[bars[i][j].slot] = true
|
||||
QueueSlot(bars[i][j].slot)
|
||||
end
|
||||
|
||||
for j=buttons+1,12 do
|
||||
@@ -1303,25 +1287,27 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
elseif i == 12 then -- pet
|
||||
bars[i]:SetPoint("BOTTOM", bars[6], "TOP", 0, 3*border)
|
||||
|
||||
-- make stance bar dodge by default
|
||||
bars[i]:SetScript("OnShow", function()
|
||||
if pfUI.unlock and pfUI.unlock:IsShown() then return end
|
||||
if bars[11] and bars[11]:IsShown() then
|
||||
bars[11]:ClearAllPoints()
|
||||
bars[11]:SetPoint("BOTTOM", bars[12], "TOP", 0, 3*border)
|
||||
UpdateMovable(bars[11], true)
|
||||
end
|
||||
end)
|
||||
if init then
|
||||
-- make stance bar dodge by default
|
||||
bars[i]:HookScript("OnShow", function()
|
||||
if pfUI.unlock and pfUI.unlock:IsShown() then return end
|
||||
if bars[11] and bars[11]:IsShown() then
|
||||
bars[11]:ClearAllPoints()
|
||||
bars[11]:SetPoint("BOTTOM", bars[12], "TOP", 0, 3*border)
|
||||
UpdateMovable(bars[11], true)
|
||||
end
|
||||
end)
|
||||
|
||||
-- restore old stance bar position
|
||||
bars[i]:SetScript("OnHide", function()
|
||||
if pfUI.unlock and pfUI.unlock:IsShown() then return end
|
||||
if bars[11] and bars[11]:IsShown() then
|
||||
bars[11]:ClearAllPoints()
|
||||
bars[11]:SetPoint("BOTTOM", bars[6], "TOP", 0, 3*border)
|
||||
UpdateMovable(bars[11], true)
|
||||
end
|
||||
end)
|
||||
-- restore old stance bar position
|
||||
bars[i]:SetScript("OnHide", function()
|
||||
if pfUI.unlock and pfUI.unlock:IsShown() then return end
|
||||
if bars[11] and bars[11]:IsShown() then
|
||||
bars[11]:ClearAllPoints()
|
||||
bars[11]:SetPoint("BOTTOM", bars[6], "TOP", 0, 3*border)
|
||||
UpdateMovable(bars[11], true)
|
||||
end
|
||||
end)
|
||||
end
|
||||
else -- others
|
||||
bars[i]:SetPoint("TOP", 0, -i*50)
|
||||
end
|
||||
@@ -1382,7 +1368,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
|
||||
-- create actionbars
|
||||
pfUI.bars = bars
|
||||
pfUI.bars.update = updatecache
|
||||
pfUI.bars.QueueSlot = QueueSlot
|
||||
pfUI.bars.buttons = buttoncache
|
||||
pfUI.bars.ButtonFullUpdate = ButtonFullUpdate
|
||||
pfUI.bars.ButtonEnter = ButtonEnter
|
||||
@@ -1392,25 +1378,40 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
if not typ then
|
||||
showgrid = state
|
||||
|
||||
for id in pairs(buttoncache) do
|
||||
updatecache[id] = true
|
||||
for slot in pairs(buttoncache) do
|
||||
QueueSlot(slot)
|
||||
end
|
||||
elseif typ == "PET" then
|
||||
showgrid_pet = state
|
||||
for slot=133,142 do
|
||||
updatecache[slot] = true
|
||||
QueueSlot(slot)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local rangeticker
|
||||
pfUI.bars.UpdateConfig = function(self)
|
||||
for i=1,12 do
|
||||
CreateActionBar(i)
|
||||
end
|
||||
|
||||
-- poll range only while it is shown
|
||||
if C.bars.glowrange == "1" and not rangeticker then
|
||||
rangeticker = C_Timer.NewTicker(.2, RangeUpdate)
|
||||
elseif C.bars.glowrange ~= "1" and rangeticker then
|
||||
rangeticker:Cancel()
|
||||
rangeticker = nil
|
||||
end
|
||||
end
|
||||
|
||||
pfUI.bars:UpdateConfig()
|
||||
|
||||
-- update all bars when entering or leaving unlock mode
|
||||
if pfUI.unlock then
|
||||
pfUI.unlock:HookScript("OnShow", function() pfUI.bars:UpdateConfig() end)
|
||||
pfUI.unlock:HookScript("OnHide", function() pfUI.bars:UpdateConfig() end)
|
||||
end
|
||||
|
||||
-- Localize custom keybinds for additional actionbars (see Bindings.xml)
|
||||
local names = {
|
||||
["PAGING"] = T["Paging Actionbar"],
|
||||
@@ -1492,7 +1493,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
if newID then
|
||||
reagent_counts[newID] = reagent_counts[newID] or C_Item.GetItemCount(newID)
|
||||
end
|
||||
updatecache[slot] = true
|
||||
QueueSlot(slot)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1502,7 +1503,7 @@ pfUI:RegisterModule("actionbar", function ()
|
||||
reagent_counts[itemID] = C_Item.GetItemCount(itemID)
|
||||
end
|
||||
for slot in pairs(reagent_slots) do
|
||||
updatecache[slot] = true
|
||||
QueueSlot(slot)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+24
-15
@@ -130,15 +130,14 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
|
||||
local function StatusBarOnUpdate()
|
||||
local remaining = this.endtime - GetTime()
|
||||
this.bar:SetValue(remaining > 0 and remaining or 0)
|
||||
|
||||
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end
|
||||
this.time:SetText(remaining > 0 and GetColoredTimeString(remaining) or "")
|
||||
-- an enabled text binding writes every frame, shown or not
|
||||
local function StatusBarOnShow()
|
||||
this.timer:Enable()
|
||||
this.parent:RefreshPosition()
|
||||
end
|
||||
|
||||
local function StatusBarRefreshParent()
|
||||
local function StatusBarOnHide()
|
||||
this.timer:Disable()
|
||||
this.parent:RefreshPosition()
|
||||
end
|
||||
|
||||
@@ -183,6 +182,16 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
frame.time:SetTextColor(1,1,1,1)
|
||||
frame.time:SetJustifyH("RIGHT")
|
||||
|
||||
-- the bar drains and the time counts down from this, engine-side
|
||||
frame.duration = C_DurationUtil.CreateDuration()
|
||||
frame.bar:SetTimerDuration(frame.duration, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.RemainingTime)
|
||||
frame.timer = C_DurationUtil.CreateDurationTextBinding()
|
||||
frame.timer:SetFontString(frame.time)
|
||||
frame.timer:SetFormatter(GetTimeFormatter())
|
||||
frame.timer:SetDuration(frame.duration)
|
||||
frame.timer:SetExpiredText("")
|
||||
frame.timer:SetZeroDurationText("")
|
||||
|
||||
frame.icon = frame:CreateTexture(nil, "OVERLAY")
|
||||
frame.icon:SetSize(height, height)
|
||||
frame.icon:SetPoint("LEFT", frame, "LEFT", 0, 0)
|
||||
@@ -195,9 +204,8 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
frame.stacks:SetJustifyV("CENTER")
|
||||
|
||||
frame.parent = parent
|
||||
frame:SetScript("OnUpdate", StatusBarOnUpdate)
|
||||
frame:SetScript("OnShow", StatusBarRefreshParent)
|
||||
frame:SetScript("OnHide", StatusBarRefreshParent)
|
||||
frame:SetScript("OnShow", StatusBarOnShow)
|
||||
frame:SetScript("OnHide", StatusBarOnHide)
|
||||
|
||||
frame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||
frame:SetScript("OnClick", StatusBarOnClick)
|
||||
@@ -261,7 +269,6 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
frame.bars[bar].id = data[2]
|
||||
frame.bars[bar].unit = frame.unit
|
||||
frame.bars[bar].type = frame.type
|
||||
frame.bars[bar].endtime = GetTime() + ( data[1] > 0 and data[1] or -1 )
|
||||
|
||||
-- update max duration the cached remaining values is less than
|
||||
-- the real one, indicates a buff renewal
|
||||
@@ -313,10 +320,12 @@ pfUI:RegisterModule("buffwatch", function ()
|
||||
frame.bars[bar].icon:SetTexture(data[4])
|
||||
end
|
||||
|
||||
-- cache maxduration
|
||||
if frame.bars[bar].cacheMaxDuration ~= frame.durations[uuid][2] then
|
||||
frame.bars[bar].cacheMaxDuration = frame.durations[uuid][2]
|
||||
frame.bars[bar].bar:SetMinMaxValues(0, frame.durations[uuid][2])
|
||||
-- the bar spans the longest time left seen for this aura; one without
|
||||
-- a time left (threshold -1) shows an empty bar and no time
|
||||
if data[1] > 0 then
|
||||
frame.bars[bar].duration:SetTimeFromEnd(GetTime() + data[1], frame.durations[uuid][2])
|
||||
else
|
||||
frame.bars[bar].duration:Reset()
|
||||
end
|
||||
|
||||
-- set stacks
|
||||
|
||||
+116
-151
@@ -5,36 +5,68 @@ pfUI:RegisterModule("castbar", function ()
|
||||
local rawborder, default_border = GetBorderSize("unitframes")
|
||||
local cbtexture = pfUI.media[C.appearance.castbar.texture]
|
||||
|
||||
-- Helper function for castbar timer formatting
|
||||
local function FormatCastbarTime(value)
|
||||
if C.unitframes.castbardecimals == "1" then
|
||||
-- 1 decimal, round half up (matches Blizzard spellbook display)
|
||||
return string.format("%.1f", floor(value * 10 + 0.5) / 10)
|
||||
else
|
||||
-- 2 decimals (default)
|
||||
return string.format("%.2f", value)
|
||||
end
|
||||
-- Castbar timer text: 1 decimal rounded half up (matches Blizzard spellbook
|
||||
-- display), or 2 decimals (default)
|
||||
local formatter = C_StringUtil.CreateNumericRuleFormatter()
|
||||
if C.unitframes.castbardecimals == "1" then
|
||||
formatter:AddBreakpoint({ threshold = 0, step = .1, format = "%.1f" })
|
||||
else
|
||||
formatter:AddBreakpoint({ threshold = 0, format = "%.2f" })
|
||||
end
|
||||
|
||||
-- Clear cast state on the bar and start the fade-out. On a normal end the bar
|
||||
-- is left at its current fill (a completed cast is already ~full; nothing
|
||||
-- snaps to full, which used to flash for a frame when the next cast stamped
|
||||
-- the bar). When `failed` is set for a cast that was actually in progress, the
|
||||
-- bar flashes full red before fading — the cancelled-cast indicator.
|
||||
-- "cur / max": a cast counts up, a channel counts down
|
||||
local castText = {
|
||||
{ property = Enum.DurationTextBindingProperty.ElapsedDuration, formatter = formatter },
|
||||
{ property = Enum.DurationTextBindingProperty.TotalDuration, formatter = formatter },
|
||||
}
|
||||
local channelText = {
|
||||
{ property = Enum.DurationTextBindingProperty.RemainingDuration, formatter = formatter },
|
||||
{ property = Enum.DurationTextBindingProperty.TotalDuration, formatter = formatter },
|
||||
}
|
||||
|
||||
-- The bar's fill and timer text both follow cb.duration on their own; only
|
||||
-- the pushback total in front of the text needs a refresh.
|
||||
local function UpdateTimerText(cb)
|
||||
if not cb.showtimer then return end
|
||||
local prefix = ""
|
||||
if cb.delay > 0 then
|
||||
prefix = "|cffffaaaa" .. (cb.isChannel and "-" or "+") .. formatter:FormatNumber(cb.delay) .. " |r "
|
||||
end
|
||||
cb.timer:SetTextFormat(prefix .. "{} / {}", cb.isChannel and channelText or castText)
|
||||
cb.timer:Enable()
|
||||
end
|
||||
|
||||
-- STOP doesn't arrive for every cast (a synthetic cast has none, a remote
|
||||
-- unit's can be missed out of range), so the bar also clears at its end time.
|
||||
local function ArmExpiry(cb)
|
||||
if cb.expiry then cb.expiry:Cancel() end
|
||||
cb.expiry = C_Timer.NewTimer(cb.duration:GetRemainingDuration(), cb.onExpire)
|
||||
end
|
||||
|
||||
-- Clear cast state on the bar and start the fade-out. The fill freezes where
|
||||
-- the cast stopped (SetMinMaxValues drops the timer). When `failed` is set for
|
||||
-- a cast that was actually in progress, the bar flashes full red before
|
||||
-- fading — the cancelled-cast indicator.
|
||||
local function ClearBar(cb, failed)
|
||||
local wasActive = cb.endTime ~= nil
|
||||
cb.startTime, cb.endTime, cb.isChannel = nil, nil, nil
|
||||
if cb.expiry then cb.expiry:Cancel() end
|
||||
cb.expiry = nil
|
||||
cb.timer:Disable()
|
||||
cb:SetScript("OnUpdate", nil)
|
||||
if cb.active then
|
||||
cb.bar:SetMinMaxValues(0, 1)
|
||||
if failed then
|
||||
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar.failcolor))
|
||||
cb.bar:SetValue(1)
|
||||
else
|
||||
cb.bar:SetValue(cb.isChannel and cb.duration:GetRemainingPercent() or cb.duration:GetElapsedPercent())
|
||||
end
|
||||
end
|
||||
cb.active, cb.isChannel = nil, nil
|
||||
cb.activeName, cb.spellID = nil, nil
|
||||
cb.isTradeskill = nil
|
||||
cb.tradeskillTotal, cb.tradeskillCompleted, cb.tradeskillSpellID = nil, nil, nil
|
||||
cb.tradeskillSingleMs, cb.currentCraftStart = nil, nil
|
||||
cb.lastMax = nil
|
||||
cb.tradeskillSingle = nil
|
||||
cb.delay = 0
|
||||
if failed and wasActive then
|
||||
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar.failcolor))
|
||||
cb.bar:SetMinMaxValues(0, 1)
|
||||
cb.bar:SetValue(1)
|
||||
end
|
||||
if cb.bar.spark then cb.bar.spark:Hide() end
|
||||
if cb:IsShown() and not cb.fade:IsPlaying() then cb.fade:Play() end
|
||||
end
|
||||
@@ -51,44 +83,48 @@ pfUI:RegisterModule("castbar", function ()
|
||||
end
|
||||
end
|
||||
|
||||
-- Per-craft spark position: the current craft's share of the bar's width.
|
||||
-- Snaps back to the left edge each time StartTradeskillCraft restarts it.
|
||||
local function MoveSpark()
|
||||
local x = this.craft:GetElapsedPercent() * this.bar:GetUnscaledWidth() - 1
|
||||
this.bar.spark:SetPoint("TOP", this.bar, "TOPLEFT", x, 0)
|
||||
this.bar.spark:SetPoint("BOTTOM", this.bar, "BOTTOMLEFT", x, 0)
|
||||
end
|
||||
|
||||
-- Stretch the bar to span all queued crafts (Quartz-style merge): the bar
|
||||
-- fills continuously across the chain instead of resetting per craft.
|
||||
-- Also arms the per-craft spark — a thin marker that crosses the bar once
|
||||
-- per craft (so it moves N× faster than the main fill on an N-stack).
|
||||
local function EnterTradeskillMerge(cb, startMs, endMs, count)
|
||||
local function EnterTradeskillMerge(cb, count)
|
||||
local start, single = cb.duration:GetStartTime(), cb.duration:GetTotalDuration()
|
||||
cb.tradeskillTotal = count
|
||||
cb.tradeskillCompleted = 0
|
||||
cb.tradeskillSpellID = cb.spellID
|
||||
local single = endMs - startMs
|
||||
cb.tradeskillSingleMs = single
|
||||
cb.currentCraftStart = startMs
|
||||
local mergedEnd = startMs + single * count
|
||||
cb.endTime = mergedEnd
|
||||
local duration = (mergedEnd - startMs) / 1000
|
||||
cb.bar:SetMinMaxValues(0, duration)
|
||||
cb.lastMax = duration
|
||||
if cb.bar.spark then cb.bar.spark:Show() end
|
||||
cb.tradeskillSingle = single
|
||||
cb.craft:SetTimeFromStart(start, single)
|
||||
cb.duration:SetTimeFromStart(start, single * count)
|
||||
ArmExpiry(cb)
|
||||
cb.bar.spark:Show()
|
||||
cb:SetScript("OnUpdate", MoveSpark)
|
||||
UpdateTradeskillLabel(cb)
|
||||
end
|
||||
|
||||
-- Mark the start of craft 2..N within an active merge (called from the
|
||||
-- UNIT_SPELLCAST_START handler). Resets the per-craft spark to the left
|
||||
-- edge of the bar.
|
||||
-- UNIT_SPELLCAST_START handler) and re-fit the bar's end to the crafts left.
|
||||
local function StartTradeskillCraft(cb)
|
||||
cb.currentCraftStart = GetTime() * 1000
|
||||
local remaining = cb.tradeskillTotal - (cb.tradeskillCompleted or 0)
|
||||
cb.endTime = cb.currentCraftStart + cb.tradeskillSingleMs * remaining
|
||||
local duration = (cb.endTime - cb.startTime) / 1000
|
||||
cb.bar:SetMinMaxValues(0, duration)
|
||||
cb.lastMax = duration
|
||||
local now = GetTime()
|
||||
local remaining = cb.tradeskillTotal - cb.tradeskillCompleted
|
||||
cb.craft:SetTimeFromStart(now, cb.tradeskillSingle)
|
||||
cb.duration:SetTimeSpan(cb.duration:GetStartTime(), now + cb.tradeskillSingle * remaining)
|
||||
ArmExpiry(cb)
|
||||
UpdateTradeskillLabel(cb)
|
||||
end
|
||||
|
||||
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
|
||||
-- then animates the fill from this state without touching C_Spell.
|
||||
-- Stamp the bar with cast data and render text/icon/lag once. From here the
|
||||
-- bar's timer and text binding follow cb.duration without any Lua.
|
||||
local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank, noInterrupt)
|
||||
cb.startTime = startMs
|
||||
cb.endTime = endMs
|
||||
cb.duration:SetTimeSpan(startMs / 1000, endMs / 1000)
|
||||
cb.active = true
|
||||
cb.isChannel = isChannel
|
||||
cb.spellID = spellID
|
||||
cb.activeName = name
|
||||
@@ -124,27 +160,18 @@ pfUI:RegisterModule("castbar", function ()
|
||||
cb.icon:Hide()
|
||||
end
|
||||
|
||||
local duration = (endMs - startMs) / 1000
|
||||
if cb.showlag then
|
||||
local _, _, lag = GetNetStats()
|
||||
cb.bar.lag:SetWidth(math.min(cb:GetWidth(), cb:GetWidth() / duration * (lag/1000)))
|
||||
cb.bar.lag:SetWidth(math.min(cb:GetWidth(), cb:GetWidth() / cb.duration:GetTotalDuration() * (lag/1000)))
|
||||
cb.bar.lag:Show()
|
||||
else
|
||||
cb.bar.lag:Hide()
|
||||
end
|
||||
|
||||
cb.bar:SetMinMaxValues(0, duration)
|
||||
cb.lastMax = duration
|
||||
|
||||
-- Prime the fill on this frame. StampBar otherwise leaves the previous
|
||||
-- value in place (ClearBar, run on the prior cast's STOP, leaves it full),
|
||||
-- so the bar would flash full for the frame between here and the next
|
||||
-- OnUpdate tick. Reset the throttle too so the timer text updates promptly.
|
||||
local nowSec = GetTime()
|
||||
local cur = isChannel and (endMs / 1000 - nowSec) or (nowSec - startMs / 1000)
|
||||
if cur < 0 then cur = 0 elseif cur > duration then cur = duration end
|
||||
cb.bar:SetValue(cur)
|
||||
cb.tick = 0
|
||||
cb.bar:SetTimerDuration(cb.duration, Enum.StatusBarInterpolation.Immediate,
|
||||
isChannel and Enum.StatusBarTimerDirection.RemainingTime or Enum.StatusBarTimerDirection.ElapsedTime)
|
||||
UpdateTimerText(cb)
|
||||
ArmExpiry(cb)
|
||||
end
|
||||
|
||||
-- One-shot poll: read C_Spell for the bar's unit, stamp or clear. Called
|
||||
@@ -186,6 +213,10 @@ pfUI:RegisterModule("castbar", function ()
|
||||
cb:SetFrameLevel(8)
|
||||
|
||||
cb.unitstr = unitstr
|
||||
cb.delay = 0
|
||||
cb.duration = C_DurationUtil.CreateDuration()
|
||||
cb.craft = C_DurationUtil.CreateDuration() -- the current craft of a tradeskill merge
|
||||
cb.onExpire = function() ClearBar(cb) end
|
||||
|
||||
-- icon
|
||||
cb.icon = CreateFrame("Frame", nil, cb)
|
||||
@@ -231,6 +262,10 @@ pfUI:RegisterModule("castbar", function ()
|
||||
cb.bar.right:SetFont(font, font_size, "OUTLINE")
|
||||
cb.bar.right:SetJustifyH(C.castbar[unitstr].timealign or "RIGHT")
|
||||
|
||||
cb.timer = C_DurationUtil.CreateDurationTextBinding()
|
||||
cb.timer:SetFontString(cb.bar.right)
|
||||
cb.timer:SetDuration(cb.duration)
|
||||
|
||||
cb.bar.lag = cb.bar:CreateTexture(nil, "OVERLAY")
|
||||
cb.bar.lag:SetPoint("TOPRIGHT", cb.bar, "TOPRIGHT", 0, 0)
|
||||
cb.bar.lag:SetPoint("BOTTOMRIGHT", cb.bar, "BOTTOMRIGHT", 0, 0)
|
||||
@@ -238,7 +273,7 @@ pfUI:RegisterModule("castbar", function ()
|
||||
|
||||
-- Per-craft progress spark for tradeskill merge — a thin vertical line
|
||||
-- that crosses the bar once per craft in the chain (so on a 5-stack it
|
||||
-- moves 5x faster than the main fill). Position is updated by OnUpdate
|
||||
-- moves 5x faster than the main fill). Position is updated by MoveSpark
|
||||
-- while a merge is active; hidden otherwise.
|
||||
cb.bar.spark = cb.bar:CreateTexture(nil, "OVERLAY")
|
||||
cb.bar.spark:SetColorTexture(1, 1, 1, 0.8)
|
||||
@@ -247,79 +282,14 @@ pfUI:RegisterModule("castbar", function ()
|
||||
cb.bar.spark:SetPoint("BOTTOM", cb.bar, "BOTTOMLEFT", 0, 0)
|
||||
cb.bar.spark:Hide()
|
||||
|
||||
-- Fade-out after a cast ends. The bar is hidden while idle, so its OnUpdate
|
||||
-- only runs during a cast; unlock mode keeps it shown for dragging.
|
||||
local function unlocked() return cb.drag and cb.drag:IsShown() end
|
||||
-- Fade-out after a cast ends. The bar is hidden while idle; unlock mode
|
||||
-- keeps it shown for dragging.
|
||||
cb.fade = cb:CreateAnimationGroup()
|
||||
local fade = cb.fade:CreateAnimation("Alpha")
|
||||
fade:SetChange(-1)
|
||||
fade:SetDuration(.4)
|
||||
cb.fade:SetScript("OnFinished", function()
|
||||
if not unlocked() then cb:Hide() end
|
||||
end)
|
||||
|
||||
-- OnUpdate animates the bar fill. All state transitions (cast start/stop/interrupt, channel start/stop,
|
||||
-- pushback) come from the event handler below — we never poll C_Spell
|
||||
-- here.
|
||||
cb:SetScript("OnUpdate", function()
|
||||
if (this.tick or 0) > GetTime() then return end
|
||||
this.tick = GetTime() + 0.020 -- ~50 FPS
|
||||
|
||||
if unlocked() then
|
||||
this.fade:Stop()
|
||||
return
|
||||
end
|
||||
|
||||
if this.fade:IsPlaying() then return end
|
||||
|
||||
if not this.endTime then
|
||||
this:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
-- Non-player bars: if the unit disappears (target died / detarget),
|
||||
-- drop the bar immediately.
|
||||
if this.unitstr ~= "player" and not UnitExists(this.unitstr) then
|
||||
ClearBar(this)
|
||||
return
|
||||
end
|
||||
|
||||
local now = GetTime()
|
||||
local endSec = this.endTime / 1000
|
||||
if now >= endSec then
|
||||
ClearBar(this)
|
||||
return
|
||||
end
|
||||
|
||||
local startSec = this.startTime / 1000
|
||||
local max = endSec - startSec
|
||||
local cur = this.isChannel and (endSec - now) or (now - startSec)
|
||||
if cur > max then cur = max end
|
||||
if cur < 0 then cur = 0 end
|
||||
|
||||
this.bar:SetValue(cur)
|
||||
|
||||
-- Per-craft spark for a tradeskill merge: position by (now - current
|
||||
-- craft's start) / single-craft duration, clamped to [0, 1]. Snaps back
|
||||
-- to the left edge each time StartTradeskillCraft fires for craft N+1.
|
||||
if this.tradeskillTotal and this.tradeskillSingleMs and this.currentCraftStart then
|
||||
local craftElapsed = now * 1000 - this.currentCraftStart
|
||||
local p = craftElapsed / this.tradeskillSingleMs
|
||||
if p < 0 then p = 0 elseif p > 1 then p = 1 end
|
||||
local x = p * this.bar:GetWidth() - 1
|
||||
this.bar.spark:ClearAllPoints()
|
||||
this.bar.spark:SetPoint("TOP", this.bar, "TOPLEFT", x, 0)
|
||||
this.bar.spark:SetPoint("BOTTOM", this.bar, "BOTTOMLEFT", x, 0)
|
||||
end
|
||||
|
||||
if this.showtimer then
|
||||
if (this.delay or 0) > 0 then
|
||||
local prefix = "|cffffaaaa" .. (this.isChannel and "-" or "+") .. FormatCastbarTime(this.delay) .. " |r "
|
||||
this.bar.right:SetText(prefix .. FormatCastbarTime(cur) .. " / " .. FormatCastbarTime(max))
|
||||
else
|
||||
this.bar.right:SetText(FormatCastbarTime(cur) .. " / " .. FormatCastbarTime(max))
|
||||
end
|
||||
end
|
||||
if not (cb.drag and cb.drag:IsShown()) then cb:Hide() end
|
||||
end)
|
||||
|
||||
-- Cast lifecycle, entirely on ClassicAPI's UNIT_SPELLCAST_* events. They
|
||||
@@ -383,7 +353,7 @@ pfUI:RegisterModule("castbar", function ()
|
||||
RefreshBar(this, arg5)
|
||||
if this.isTradeskill and (this.pendingTradeskillCount or 0) > 1
|
||||
and C.castbar.player.mergetradeskill == "1" then
|
||||
EnterTradeskillMerge(this, this.startTime, this.endTime, this.pendingTradeskillCount)
|
||||
EnterTradeskillMerge(this, this.pendingTradeskillCount)
|
||||
end
|
||||
this.pendingTradeskillCount = nil
|
||||
end
|
||||
@@ -392,7 +362,7 @@ pfUI:RegisterModule("castbar", function ()
|
||||
-- count and clear when the chain is done. A no-op for normal casts,
|
||||
-- which are cleared by UNIT_SPELLCAST_STOP.
|
||||
if this.tradeskillTotal and arg3 == this.tradeskillSpellID then
|
||||
this.tradeskillCompleted = (this.tradeskillCompleted or 0) + 1
|
||||
this.tradeskillCompleted = this.tradeskillCompleted + 1
|
||||
if this.tradeskillCompleted >= this.tradeskillTotal then
|
||||
ClearBar(this)
|
||||
else
|
||||
@@ -412,35 +382,30 @@ pfUI:RegisterModule("castbar", function ()
|
||||
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
|
||||
ClearBar(this, true)
|
||||
elseif event == "UNIT_SPELLCAST_INTERRUPTIBLE" or event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
|
||||
if this.endTime then
|
||||
if this.active then
|
||||
SetCastbarShield(this.bar, this.icon, event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE", this.isChannel)
|
||||
end
|
||||
elseif event == "UNIT_SPELLCAST_DELAYED" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
|
||||
-- Pushback: a cast delayed later or a channel shortened. Following
|
||||
-- Quartz, re-poll just the times and accumulate the shift into a running
|
||||
-- Quartz, re-read just the times and accumulate the shift into a running
|
||||
-- this.delay for the +/- indicator, rather than a full restamp (which
|
||||
-- would reset that total and re-render icon/text). ClassicAPI moves
|
||||
-- endMs (SpellDelayed_h bumps g_cast.endMs; the MSG_CHANNEL_UPDATE
|
||||
-- co-hook rewrites g_channel.endMs) while startMs stays put, so we diff
|
||||
-- endMs. delay is a positive magnitude; OnUpdate signs it "+" for casts
|
||||
-- and "-" for channels. Skipped during a tradeskill merge.
|
||||
if this.endTime and not this.tradeskillTotal then
|
||||
local startMs, endMs
|
||||
-- would reset that total and re-render icon/text). Pushback moves the
|
||||
-- end time while the start stays put, so we diff the end. delay is a
|
||||
-- positive magnitude; UpdateTimerText signs it "+" for casts and "-"
|
||||
-- for channels. Skipped during a tradeskill merge.
|
||||
if this.active and not this.tradeskillTotal then
|
||||
local duration
|
||||
if this.isChannel then
|
||||
local _, _, _, s, e = C_Spell.UnitChannelInfo(unit)
|
||||
startMs, endMs = s, e
|
||||
duration = UnitChannelDuration(unit)
|
||||
else
|
||||
local _, _, _, s, e = C_Spell.UnitCastingInfo(unit)
|
||||
startMs, endMs = s, e
|
||||
duration = UnitCastingDuration(unit)
|
||||
end
|
||||
if startMs and endMs then
|
||||
local shift = this.isChannel and (this.endTime - endMs) or (endMs - this.endTime)
|
||||
this.delay = (this.delay or 0) + shift / 1000
|
||||
this.startTime = startMs
|
||||
this.endTime = endMs
|
||||
local newDuration = (endMs - startMs) / 1000
|
||||
this.bar:SetMinMaxValues(0, newDuration)
|
||||
this.lastMax = newDuration
|
||||
if duration then
|
||||
local shift = duration:GetEndTime() - this.duration:GetEndTime()
|
||||
this.delay = this.delay + (this.isChannel and -shift or shift)
|
||||
this.duration:Assign(duration)
|
||||
UpdateTimerText(this)
|
||||
ArmExpiry(this)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2509,13 +2509,7 @@ pfUI:RegisterModule("combatlog", function ()
|
||||
local buttonName, button, textWidth;
|
||||
local buttonIndex = 1;
|
||||
-- subtract the width of the dropdown button
|
||||
local clogleft, clogright = COMBATLOG:GetRight(), COMBATLOG:GetLeft();
|
||||
local maxWidth;
|
||||
if ( clogleft and clogright ) then
|
||||
maxWidth = (COMBATLOG:GetRight()-COMBATLOG:GetLeft())-31; --Hacky hacky because GetWidth goes crazy when it is docked
|
||||
else
|
||||
maxWidth = COMBATLOG:GetWidth() - 31;
|
||||
end
|
||||
local maxWidth = COMBATLOG:GetUnscaledWidth() - 31;
|
||||
|
||||
local additionalFilterButton = CombatLogQuickButtonFrame.AdditionalFilterButton;
|
||||
|
||||
|
||||
+28
-29
@@ -166,8 +166,8 @@ pfUI:RegisterModule("energytick", function()
|
||||
local cost = C_Spell.GetSpellPowerCost(arg3)
|
||||
cost = cost and cost[1]
|
||||
if cost and cost.type == Enum.PowerType.Mana and cost.cost > 0 then
|
||||
this.fsrSpell, this.fsrEnd = arg3, GetTime() + FIVE_SECOND_RULE
|
||||
this.fsrGain = nil
|
||||
this.fsrSpell, this.fsrGain = arg3, nil
|
||||
this.fsr:SetTimeFromStart(GetTime(), FIVE_SECOND_RULE)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -175,7 +175,8 @@ pfUI:RegisterModule("energytick", function()
|
||||
-- Unit::Update won't expire the rule while the spending spell still channels
|
||||
if event == "UNIT_SPELLCAST_CHANNEL_STOP" and arg1 == "player" then
|
||||
if this.fsrSpell and this.fsrSpell == arg3 then
|
||||
this.fsrEnd, this.fsrGain = GetTime() + FIVE_SECOND_RULE, nil
|
||||
this.fsrGain = nil
|
||||
this.fsr:SetTimeFromStart(GetTime(), FIVE_SECOND_RULE)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -189,7 +190,7 @@ pfUI:RegisterModule("energytick", function()
|
||||
-- only a gain can be the tick; a spend never touches the phase
|
||||
if diff > 0 and lockTick(this) then
|
||||
-- a tick inside the window proves regen continues through it
|
||||
if this.fsrEnd and this.fsrEnd > GetTime() then
|
||||
if this.fsr:IsActive() then
|
||||
this.fsrGain = true
|
||||
end
|
||||
end
|
||||
@@ -208,25 +209,15 @@ pfUI:RegisterModule("energytick", function()
|
||||
end
|
||||
this.tick = GetTime() + 0.020 -- ~50 FPS
|
||||
|
||||
-- five-second rule drains to nothing. The display is cosmetic and can be
|
||||
-- hidden on its own; the window itself (fsrEnd/fsrGain) keeps running
|
||||
-- either way -- it still dims the sweep spark below.
|
||||
local remaining = this.fsrEnd and (this.fsrEnd - GetTime()) or 0
|
||||
if this.mode == "MANA" and remaining > 0 then
|
||||
if C.unitframes.player.showfsr == "1" then
|
||||
if fsrOverlay then
|
||||
this.fsrbar:SetWidth(getBarWidth() * remaining / FIVE_SECOND_RULE)
|
||||
else
|
||||
this.fsrbar:SetValue(remaining)
|
||||
end
|
||||
this.fsrbar:Show()
|
||||
else
|
||||
this.fsrbar:Hide()
|
||||
end
|
||||
else
|
||||
this.fsrSpell, this.fsrEnd, this.fsrGain = nil, nil, nil
|
||||
this.fsrbar:Hide()
|
||||
-- five-second rule: fsrbar drains from this.fsr by itself. The display is
|
||||
-- cosmetic and can be hidden on its own; the window itself (fsr/fsrGain)
|
||||
-- keeps running either way -- it still dims the sweep spark below.
|
||||
local fsrUp = this.mode == "MANA" and this.fsr:IsActive()
|
||||
if not fsrUp and this.fsrSpell then
|
||||
this.fsrSpell, this.fsrGain = nil, nil
|
||||
this.fsr:Reset()
|
||||
end
|
||||
this.fsrbar:SetShown(fsrUp and C.unitframes.player.showfsr == "1")
|
||||
|
||||
if not this.start then
|
||||
this.spark:SetAlpha(0)
|
||||
@@ -249,7 +240,7 @@ pfUI:RegisterModule("energytick", function()
|
||||
end
|
||||
|
||||
-- dim while the rule is up and nothing has ticked inside it yet
|
||||
this.spark:SetAlpha((remaining > 0 and not this.fsrGain) and .4 or 1)
|
||||
this.spark:SetAlpha((fsrUp and not this.fsrGain) and .4 or 1)
|
||||
|
||||
if not C.unitframes.player.pheight then
|
||||
return
|
||||
@@ -259,19 +250,21 @@ pfUI:RegisterModule("energytick", function()
|
||||
this.spark:SetPoint("LEFT", pos - ((C.unitframes.player.pheight + 5) / 2), 0)
|
||||
end)
|
||||
|
||||
energytick.fsr = C_DurationUtil.CreateDuration()
|
||||
|
||||
if fsrOverlay then
|
||||
-- classic style: a translucent shade on top of the power bar's own fill
|
||||
energytick.fsrbar = energytick:CreateTexture(nil, "ARTWORK")
|
||||
energytick.fsrbar:SetColorTexture(1, 1, 1, .15)
|
||||
energytick.fsrbar:SetPoint("TOPLEFT", 0, 0)
|
||||
energytick.fsrbar:SetPoint("BOTTOMLEFT", 0, 0)
|
||||
-- classic style: a translucent shade on top of the power bar's own fill,
|
||||
-- under the spark
|
||||
energytick.fsrbar = CreateFrame("StatusBar", nil, pfUI.uf.player.power.bar)
|
||||
energytick.fsrbar:SetAllPoints(energytick)
|
||||
energytick.fsrbar:SetColorFill(1, 1, 1, .15)
|
||||
energytick:SetFrameLevel(energytick.fsrbar:GetFrameLevel() + 1)
|
||||
else
|
||||
-- a real bar below the power bar, not an overlay on top of it -- the same
|
||||
-- treatment nameplate castbars get relative to the health bar, so the
|
||||
-- window can't be mistaken for missing mana
|
||||
energytick.fsrbar = CreateFrame("StatusBar", nil, pfUI.uf.player)
|
||||
energytick.fsrbar:SetStatusBarTexture(cbtexture)
|
||||
energytick.fsrbar:SetMinMaxValues(0, FIVE_SECOND_RULE)
|
||||
energytick.fsrbar:SetPoint("TOPLEFT", pfUI.uf.player.power.bar, "BOTTOMLEFT", 0, -default_border * 2)
|
||||
energytick.fsrbar:SetPoint("TOPRIGHT", pfUI.uf.player.power.bar, "BOTTOMRIGHT", 0, -default_border * 2)
|
||||
energytick.fsrbar:SetHeight(tonumber(C.unitframes.player.fsrheight) or 4)
|
||||
@@ -279,8 +272,14 @@ pfUI:RegisterModule("energytick", function()
|
||||
CreateBackdrop(energytick.fsrbar, default_border)
|
||||
CreateBackdropShadow(energytick.fsrbar)
|
||||
end
|
||||
energytick.fsrbar:SetTimerDuration(energytick.fsr, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.RemainingTime)
|
||||
energytick.fsrbar:Hide()
|
||||
|
||||
-- the bar isn't parented to energytick, and OnUpdate stops with it
|
||||
energytick:SetScript("OnHide", function()
|
||||
this.fsrbar:Hide()
|
||||
end)
|
||||
|
||||
energytick.spark = energytick:CreateTexture(nil, "OVERLAY")
|
||||
energytick.spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
|
||||
energytick.spark:SetHeight(C.unitframes.player.pheight + 15)
|
||||
|
||||
+13
-26
@@ -136,17 +136,19 @@ pfUI:RegisterModule("firstrun", function ()
|
||||
local f = CreateFirstRunPage()
|
||||
f.text:SetText(T["A new installation of |cff33ffccpf|rUI ships with 4 prebuilt design profiles. Click below if you wish to load one of these profiles."])
|
||||
|
||||
local function LoadProfile(name)
|
||||
_G["pfUI_config"] = CopyTable(pfUI_profiles[name])
|
||||
pfUI_init.selected_profile = name
|
||||
pfUI:LoadConfig()
|
||||
ReloadUI()
|
||||
end
|
||||
|
||||
f.Modern = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
|
||||
f.Modern:SetSize(120, 20)
|
||||
f.Modern:SetPoint("BOTTOM", -65, 100)
|
||||
f.Modern:SetTextColor(1,1,1)
|
||||
f.Modern:SetText("Modern")
|
||||
f.Modern:SetScript("OnClick", function()
|
||||
_G["pfUI_config"] = CopyTable(pfUI_profiles["Modern"])
|
||||
pfUI_init.selected_profile = "Modern"
|
||||
pfUI:LoadConfig()
|
||||
ReloadUI()
|
||||
end)
|
||||
f.Modern:SetScript("OnClick", function() LoadProfile("Modern") end)
|
||||
SkinButton(f.Modern)
|
||||
|
||||
f.Nostalgia = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
|
||||
@@ -154,12 +156,7 @@ pfUI:RegisterModule("firstrun", function ()
|
||||
f.Nostalgia:SetPoint("BOTTOM", 65, 100)
|
||||
f.Nostalgia:SetTextColor(1,1,1)
|
||||
f.Nostalgia:SetText("Nostalgia")
|
||||
f.Nostalgia:SetScript("OnClick", function()
|
||||
_G["pfUI_config"] = CopyTable(pfUI_profiles["Nostalgia"])
|
||||
pfUI_init.selected_profile = "Nostalgia"
|
||||
pfUI:LoadConfig()
|
||||
ReloadUI()
|
||||
end)
|
||||
f.Nostalgia:SetScript("OnClick", function() LoadProfile("Nostalgia") end)
|
||||
SkinButton(f.Nostalgia)
|
||||
|
||||
f.Legacy = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
|
||||
@@ -167,12 +164,7 @@ pfUI:RegisterModule("firstrun", function ()
|
||||
f.Legacy:SetPoint("BOTTOM", 65, 75)
|
||||
f.Legacy:SetTextColor(1,1,1)
|
||||
f.Legacy:SetText("Legacy")
|
||||
f.Legacy:SetScript("OnClick", function()
|
||||
_G["pfUI_config"] = CopyTable(pfUI_profiles["Legacy"])
|
||||
pfUI_init.selected_profile = "Legacy"
|
||||
pfUI:LoadConfig()
|
||||
ReloadUI()
|
||||
end)
|
||||
f.Legacy:SetScript("OnClick", function() LoadProfile("Legacy") end)
|
||||
SkinButton(f.Legacy)
|
||||
|
||||
f.Slim = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
|
||||
@@ -180,12 +172,7 @@ pfUI:RegisterModule("firstrun", function ()
|
||||
f.Slim:SetPoint("BOTTOM", -65, 75)
|
||||
f.Slim:SetTextColor(1,1,1)
|
||||
f.Slim:SetText("Slim")
|
||||
f.Slim:SetScript("OnClick", function()
|
||||
_G["pfUI_config"] = CopyTable(pfUI_profiles["Slim"])
|
||||
pfUI_init.selected_profile = "Slim"
|
||||
pfUI:LoadConfig()
|
||||
ReloadUI()
|
||||
end)
|
||||
f.Slim:SetScript("OnClick", function() LoadProfile("Slim") end)
|
||||
SkinButton(f.Slim)
|
||||
|
||||
f.Slider = CreateFrame("Slider", "pfFirstRunWizardScaleSlider", f, "OptionsSliderTemplate")
|
||||
@@ -196,14 +183,14 @@ pfUI:RegisterModule("firstrun", function ()
|
||||
f.Slider:SetSize(240, 20)
|
||||
f.Slider:SetPoint("BOTTOM", 0, 50)
|
||||
f.Slider:SetOrientation('HORIZONTAL')
|
||||
f.Slider:SetMinMaxValues(0.5, 2.0)
|
||||
-- the game drops a uiScale under 0.64 for its automatic scale at login
|
||||
f.Slider:SetMinMaxValues(0.64, 2.0)
|
||||
f.Slider:SetValue(UIParent:GetScale())
|
||||
|
||||
f.Slider:SetScript("OnMouseUp", function()
|
||||
local scale = round(this:GetValue(),2)
|
||||
SetCVar("uiScale", scale)
|
||||
SetCVar("useUiScale", 1)
|
||||
UIParent:SetScale(scale)
|
||||
this:SetValue(scale)
|
||||
end)
|
||||
|
||||
|
||||
+20
-78
@@ -78,7 +78,7 @@ pfUI:RegisterModule("gui", function ()
|
||||
|
||||
-- basic frame
|
||||
local frame = CreateFrame("Frame", nil, this)
|
||||
frame:SetWidth(this.parent:GetRight()-this.parent:GetLeft()-20)
|
||||
frame:SetWidth(this.parent:GetUnscaledWidth()-20)
|
||||
frame:SetHeight(22)
|
||||
frame:SetPoint("TOPLEFT", this, "TOPLEFT", 5, (this.objectCount*-23)-5)
|
||||
|
||||
@@ -130,7 +130,7 @@ pfUI:RegisterModule("gui", function ()
|
||||
category = {}
|
||||
category[config] = tostring(GetCVar(config))
|
||||
ufunc = function()
|
||||
SetCVar(this:GetParent().config, this:GetParent().category[config])
|
||||
SetCVar(config, category[config])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -881,14 +881,6 @@ pfUI:RegisterModule("gui", function ()
|
||||
"35:35",
|
||||
"40:40",
|
||||
},
|
||||
["scaling"] = {
|
||||
"0:" .. T["Off"],
|
||||
"4:" .. T["Huge (PixelPerfect)"],
|
||||
"5:" .. T["Large"],
|
||||
"6:" .. T["Medium"],
|
||||
"7:" .. T["Small"],
|
||||
"8:" .. T["Tiny (PixelPerfect)"],
|
||||
},
|
||||
["abbrevnum"] = {
|
||||
"0:" .. T["Full Numbers (4250)"],
|
||||
"1:" .. T["Abbreviate 2 Decimals (4.25k)"],
|
||||
@@ -1508,7 +1500,24 @@ pfUI:RegisterModule("gui", function ()
|
||||
|
||||
CreateConfig(nil, T["Settings"], nil, nil, "header")
|
||||
CreateConfig(nil, T["Language"], C.global, "language", "dropdown", pfUI.gui.dropdowns.languages)
|
||||
CreateConfig(U["pixelperfect"], T["Enable UI-Scale"], C.global, "pixelperfect", "dropdown", pfUI.gui.dropdowns.scaling)
|
||||
-- the game's own scale options, as in its Video Options; the list keeps
|
||||
-- a value set there that is none of these steps
|
||||
CreateConfig(nil, T["Use UI-Scale"], "CVAR", "useUiScale", "checkbox")
|
||||
CreateConfig(nil, T["UI-Scale"], "CVAR", "uiScale", "dropdown", function()
|
||||
local current = GetCVar("uiScale")
|
||||
local values, found = {}, nil
|
||||
for _, scale in ipairs({ .64, .65, .7, .75, .8, .85, .9, .95, 1, 1.1, 1.2, 1.3, 1.4, 1.5 }) do
|
||||
if math.abs(scale - tonumber(current)) < .001 then
|
||||
found = true
|
||||
table.insert(values, current .. ":" .. scale)
|
||||
else
|
||||
table.insert(values, tostring(scale))
|
||||
end
|
||||
end
|
||||
if not found then table.insert(values, 1, current .. ":" .. round(tonumber(current), 2)) end
|
||||
return values
|
||||
end)
|
||||
CreateConfig(nil, string.format(T["Pixel Perfect UI-Scale: %s (Overrides UI-Scale)"], round(PixelUtil.GetPixelToUIUnitFactor(), 2)), C.global, "pixelperfect", "checkbox")
|
||||
CreateConfig(nil, T["Use Original Game Fonts"], C.global, "font_blizzard", "checkbox")
|
||||
CreateConfig(nil, T["Enable Region Compatible Font"], C.global, "force_region", "checkbox")
|
||||
CreateConfig(nil, T["Standard Text Font"], C.global, "font_default", "dropdown", pfUI.gui.dropdowns.fonts)
|
||||
@@ -1585,8 +1594,6 @@ pfUI:RegisterModule("gui", function ()
|
||||
CreateConfig(nil, T["Frame Shadow Intensity"], C.appearance.border, "shadow_intensity", "dropdown", pfUI.gui.dropdowns.uf_debuff_indicator_size)
|
||||
CreateConfig(nil) -- spacer
|
||||
CreateConfig(nil, T["Force Blizzard Borders (|cffffaaaaExperimental|r)"], C.appearance.border, "force_blizz", "checkbox")
|
||||
CreateConfig(nil, T["Enable Pixel Perfect Borders"], C.appearance.border, "pixelperfect", "checkbox")
|
||||
CreateConfig(nil, T["Scale Border On HiDPI Displays"], C.appearance.border, "hidpi", "checkbox")
|
||||
CreateConfig(nil) -- spacer
|
||||
CreateConfig(nil, T["Global Border Size"], C.appearance.border, "default", "dropdown", pfUI.gui.dropdowns.border)
|
||||
CreateConfig(nil, T["Action Bar Border Size"], C.appearance.border, "actionbars", "dropdown", pfUI.gui.dropdowns.border)
|
||||
@@ -1646,71 +1653,6 @@ pfUI:RegisterModule("gui", function ()
|
||||
end)
|
||||
|
||||
-- Throttling Menu
|
||||
CreateGUIEntry(T["Throttling"], T["Nameplates"], function()
|
||||
local header = CreateConfig(nil, T["Nameplate Update Rate"], nil, nil, "header")
|
||||
header:GetParent().objectCount = header:GetParent().objectCount - 1
|
||||
header:SetHeight(20)
|
||||
|
||||
local castbarCustom
|
||||
|
||||
CreateConfig(function()
|
||||
if castbarCustom and castbarCustom.input then
|
||||
local isCustom = pfUI.throttle:IsCustom("nameplates_castbar")
|
||||
if not isCustom then
|
||||
castbarCustom.input:EnableMouse(false)
|
||||
castbarCustom.input:EnableKeyboard(false)
|
||||
castbarCustom.input:ClearFocus()
|
||||
castbarCustom.input:SetTextColor(.5,.5,.5,1)
|
||||
castbarCustom.input:SetText(tostring(pfUI.throttle:GetFps("nameplates_castbar")))
|
||||
else
|
||||
castbarCustom.input:EnableMouse(true)
|
||||
castbarCustom.input:EnableKeyboard(true)
|
||||
castbarCustom.input:SetTextColor(.2,1,.8,1)
|
||||
if _G.pfUI_throttle.nameplates_castbar_custom then
|
||||
castbarCustom.input:SetText(_G.pfUI_throttle.nameplates_castbar_custom)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, T["Castbar Plates"], _G.pfUI_throttle, "nameplates_castbar", "dropdown", {
|
||||
"very_slow:" .. T["Very Slow"] .. " (2 FPS)",
|
||||
"slow:" .. T["Slow"] .. " (5 FPS)",
|
||||
"normal:" .. T["Normal"] .. " (10 FPS)",
|
||||
"fast:" .. T["Fast"] .. " (20 FPS)",
|
||||
"very_fast:" .. T["Very Fast"] .. " (30 FPS)",
|
||||
"fastest:" .. T["Fastest"] .. " (50 FPS)",
|
||||
"custom:" .. T["Custom"],
|
||||
})
|
||||
|
||||
castbarCustom = CreateConfig(nil, T["Custom FPS"], _G.pfUI_throttle, "nameplates_castbar_custom")
|
||||
|
||||
local isCustom = pfUI.throttle:IsCustom("nameplates_castbar")
|
||||
if not isCustom then
|
||||
castbarCustom.input:EnableMouse(false)
|
||||
castbarCustom.input:EnableKeyboard(false)
|
||||
castbarCustom.input:SetTextColor(.5,.5,.5,1)
|
||||
castbarCustom.input:SetText(tostring(pfUI.throttle:GetFps("nameplates_castbar")))
|
||||
else
|
||||
castbarCustom.input:EnableMouse(true)
|
||||
castbarCustom.input:EnableKeyboard(true)
|
||||
castbarCustom.input:SetTextColor(.2,1,.8,1)
|
||||
if _G.pfUI_throttle.nameplates_castbar_custom then
|
||||
castbarCustom.input:SetText(_G.pfUI_throttle.nameplates_castbar_custom)
|
||||
end
|
||||
end
|
||||
|
||||
-- Spacer before reset button
|
||||
local spacer = CreateConfig(nil, " ", nil, nil, "header")
|
||||
spacer:GetParent().objectCount = spacer:GetParent().objectCount - 1
|
||||
spacer:SetHeight(10)
|
||||
|
||||
-- Reset to defaults button
|
||||
CreateConfig(nil, T["Reset to Defaults"], nil, nil, "button", function()
|
||||
pfUI.throttle:ResetToDefault("nameplates_castbar")
|
||||
_G.pfUI_throttle.nameplates_castbar_custom = "100"
|
||||
Reload()
|
||||
end, true)
|
||||
end)
|
||||
|
||||
CreateGUIEntry(T["Throttling"], T["Tooltips"], function()
|
||||
local header = CreateConfig(nil, T["Tooltip Update Rate"], nil, nil, "header")
|
||||
header:GetParent().objectCount = header:GetParent().objectCount - 1
|
||||
|
||||
@@ -41,7 +41,7 @@ pfUI:RegisterModule("marktracking", function ()
|
||||
|
||||
local function ShortenName(name, row)
|
||||
if not name or name == "" then return "" end
|
||||
local barWidth = row.health:GetWidth()
|
||||
local barWidth = row.health:GetUnscaledWidth()
|
||||
if barWidth < 1 then barWidth = BAR_WIDTH end
|
||||
local available = barWidth - 4
|
||||
if rm_showpct then available = available - 32 end
|
||||
|
||||
+74
-112
@@ -82,7 +82,6 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
local threatMemory = {} -- guid -> true once the mob targeted the player
|
||||
local raidGuidCache = {} -- guid -> name of the player's group
|
||||
local offtanks = {}
|
||||
local activeCasts = {} -- overlay -> true while its castbar sweeps
|
||||
local zooming = {} -- overlay -> true while its target zoom animates
|
||||
local auraSlots = {} -- reusable GetAuraSlots buffer for the per-plate aura scan
|
||||
local targetGuid
|
||||
@@ -100,6 +99,7 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
-- Config caching
|
||||
-- ============================================================================
|
||||
local cfg = {}
|
||||
local castFormatter = C_StringUtil.CreateNumericRuleFormatter()
|
||||
local debufffilter, debufflist
|
||||
|
||||
local function DebuffFilterPopulate()
|
||||
@@ -158,7 +158,13 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
cfg.showguildname = N.showguildname == "1"
|
||||
cfg.abbrevname = C.unitframes.abbrevname == "1"
|
||||
cfg.friendclassnamec = N.friendclassnamec == "1"
|
||||
cfg.castbardecimals = C.unitframes.castbardecimals == "1"
|
||||
-- the plate castbars' text bindings hold this formatter, so they pick the
|
||||
-- change up on their next tick
|
||||
if C.unitframes.castbardecimals == "1" then
|
||||
castFormatter:SetBreakpoints({ { threshold = 0, step = .1, rounding = Enum.NumericRuleFormatRounding.Down, format = "%.1f" } })
|
||||
else
|
||||
castFormatter:SetBreakpoints({ { threshold = 0, format = "%.2f" } })
|
||||
end
|
||||
cfg.fullhealth = N.fullhealth == "1"
|
||||
cfg.keeptarget = N.target == "1"
|
||||
cfg.critters = N.critters == "1"
|
||||
@@ -187,8 +193,6 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
cfg.rightclick = N.rightclick == "1"
|
||||
cfg.hlr, cfg.hlg, cfg.hlb, cfg.hla = GetStringColor(N.highlightcolor)
|
||||
cfg.br, cfg.bg, cfg.bb, cfg.ba = GetStringColor(C.appearance.border.color)
|
||||
-- sweep rate of the castbars on plates other than the target's
|
||||
cfg.throttle_castbar = pfUI.throttle:Get("nameplates_castbar")
|
||||
|
||||
local c = combatstate
|
||||
c.CASTING.r, c.CASTING.g, c.CASTING.b, c.CASTING.a = GetStringColor(N.combatcasting)
|
||||
@@ -227,22 +231,23 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
-- One-shot C_Spell poll. Builds the cast struct for a UNIT_SPELLCAST_* event
|
||||
-- (the payload carries no timing) and seeds a plate that binds while its unit
|
||||
-- is already mid-cast (its START fired before the plate existed). Picks cast
|
||||
-- vs channel itself.
|
||||
-- vs channel itself. A cast whose start was never seen has no duration.
|
||||
local function PollCastInfo(unit)
|
||||
local name, _, texture, startMs, endMs, _, _, noInterrupt, spellID = C_Spell.UnitCastingInfo(unit)
|
||||
local isChannel
|
||||
if not name then
|
||||
name, _, texture, startMs, endMs, _, noInterrupt, spellID = C_Spell.UnitChannelInfo(unit)
|
||||
local name, _, texture, _, _, _, _, noInterrupt, spellID = C_Spell.UnitCastingInfo(unit)
|
||||
local duration, isChannel
|
||||
if name then
|
||||
duration = UnitCastingDuration(unit)
|
||||
else
|
||||
name, _, texture, _, _, _, noInterrupt, spellID = C_Spell.UnitChannelInfo(unit)
|
||||
duration = name and UnitChannelDuration(unit)
|
||||
isChannel = true
|
||||
end
|
||||
if not name or not startMs or not endMs then return nil end
|
||||
if not duration then return nil end
|
||||
return {
|
||||
spellName = name,
|
||||
spellID = spellID,
|
||||
icon = texture,
|
||||
startTime = startMs / 1000,
|
||||
endTime = endMs / 1000,
|
||||
duration = (endMs - startMs) / 1000,
|
||||
duration = duration,
|
||||
isChannel = isChannel,
|
||||
noInterrupt = noInterrupt,
|
||||
}
|
||||
@@ -279,7 +284,7 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
local mobTargetGuid = UnitGUID(target)
|
||||
local hasTarget = mobTargetGuid and mobTargetGuid ~= NULL_GUID
|
||||
local info = castState[guid]
|
||||
local isCasting = info and info.endTime > GetTime()
|
||||
local isCasting = info and not info.duration:HasExpired()
|
||||
local targetingPlayer = hasTarget and UnitIsUnit(target, "player")
|
||||
|
||||
if targetingPlayer then
|
||||
@@ -819,8 +824,7 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- Animation driver: castbar sweeps and the target zoom. Shown only while
|
||||
-- something moves.
|
||||
-- Animation driver: the target zoom. Shown only while a plate zooms.
|
||||
-- ============================================================================
|
||||
local driver = CreateFrame("Frame", nil, UIParent)
|
||||
driver:Hide()
|
||||
@@ -841,98 +845,8 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
driver:Show()
|
||||
end
|
||||
|
||||
-- Skip SetText when the rounded value hasn't changed since last frame.
|
||||
-- `string.format("%.2f", ...)` allocates a fresh string every call; this
|
||||
-- gate compares cheap integers and only formats when the displayed value
|
||||
-- would actually differ. Reset via lastEndTime-changed branch below.
|
||||
local function SetCastbarText(castbar, remaining)
|
||||
local rounded
|
||||
if cfg.castbardecimals then
|
||||
rounded = floor(remaining * 10)
|
||||
if castbar.lastTextTick ~= rounded then
|
||||
castbar.lastTextTick = rounded
|
||||
castbar.text:SetText(rounded / 10)
|
||||
end
|
||||
else
|
||||
rounded = floor(remaining * 100)
|
||||
if castbar.lastTextTick ~= rounded then
|
||||
castbar.lastTextTick = rounded
|
||||
castbar.text:SetFormattedText("%.2f", remaining)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateCastbar(plate, info, now)
|
||||
local castbar = plate.castbar
|
||||
local duration = info.duration
|
||||
if castbar.lastEndTime ~= info.endTime then
|
||||
castbar.lastEndTime = info.endTime
|
||||
castbar.lastTextTick = nil
|
||||
-- Relative 0..duration range to avoid float precision loss with large
|
||||
-- absolute timestamps.
|
||||
castbar:SetMinMaxValues(0, duration)
|
||||
SetCastbarShield(castbar, castbar.icon, info.noInterrupt, info.isChannel)
|
||||
if info.icon then
|
||||
castbar.icon.tex:SetTexture(info.icon)
|
||||
castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)
|
||||
end
|
||||
castbar.spell:SetText(cfg.spellname and info.spellName or "")
|
||||
end
|
||||
|
||||
local value = info.isChannel and (info.endTime - now) or (now - info.startTime)
|
||||
if value < 0 then value = 0 elseif value > duration then value = duration end
|
||||
castbar:SetValue(value)
|
||||
SetCastbarText(castbar, info.endTime - now)
|
||||
if not castbar.isShown then
|
||||
castbar.isShown = true
|
||||
castbar:Show()
|
||||
end
|
||||
end
|
||||
|
||||
function HideCast(plate)
|
||||
activeCasts[plate] = nil
|
||||
local castbar = plate.castbar
|
||||
if castbar.isShown then
|
||||
castbar.isShown = nil
|
||||
castbar.lastEndTime = nil
|
||||
castbar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Start or stop the plate's castbar from the cast cache and the config.
|
||||
function UpdateCast(plate)
|
||||
local info = castState[plate.guid]
|
||||
if info and cfg.showcastbar and (plate.istarget or not cfg.targetcastbar) then
|
||||
if not activeCasts[plate] then
|
||||
activeCasts[plate] = true
|
||||
plate.casttick = 0
|
||||
driver:Show()
|
||||
end
|
||||
UpdateCastbar(plate, info, GetTime())
|
||||
else
|
||||
HideCast(plate)
|
||||
end
|
||||
end
|
||||
|
||||
driver:SetScript("OnUpdate", function()
|
||||
local now = GetTime()
|
||||
|
||||
-- The target's bar sweeps every frame; the others at the castbar rate.
|
||||
for plate in pairs(activeCasts) do
|
||||
if plate.istarget or plate.casttick + cfg.throttle_castbar <= now then
|
||||
plate.casttick = now
|
||||
local info = castState[plate.guid]
|
||||
if info and info.endTime > now then
|
||||
UpdateCastbar(plate, info, now)
|
||||
else
|
||||
-- ran out without a STOP: treat it as one
|
||||
castState[plate.guid] = nil
|
||||
HideCast(plate)
|
||||
UpdateCombatColor(plate)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for plate in pairs(zooming) do
|
||||
local f = (now - plate.zoomStart) / ZOOM_TIME
|
||||
if f >= 1 then
|
||||
@@ -941,10 +855,57 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
end
|
||||
SetZoom(plate, plate.zoomIn and f or 1 - f)
|
||||
end
|
||||
|
||||
if not next(activeCasts) and not next(zooming) then this:Hide() end
|
||||
if not next(zooming) then this:Hide() end
|
||||
end)
|
||||
|
||||
-- ============================================================================
|
||||
-- Castbars: the bar's timer and its text binding follow the cast's duration
|
||||
-- object on their own. Lua only starts, restyles and stops them.
|
||||
-- ============================================================================
|
||||
local function ShowCast(plate, info)
|
||||
local castbar = plate.castbar
|
||||
castbar:SetTimerDuration(info.duration, Enum.StatusBarInterpolation.Immediate,
|
||||
info.isChannel and Enum.StatusBarTimerDirection.RemainingTime or Enum.StatusBarTimerDirection.ElapsedTime)
|
||||
castbar.timer:SetDuration(info.duration)
|
||||
castbar.timer:Enable()
|
||||
SetCastbarShield(castbar, castbar.icon, info.noInterrupt, info.isChannel)
|
||||
if info.icon then
|
||||
castbar.icon.tex:SetTexture(info.icon)
|
||||
castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)
|
||||
end
|
||||
castbar.spell:SetText(cfg.spellname and info.spellName or "")
|
||||
-- armed exactly while the bar shows
|
||||
if castbar.expiry then castbar.expiry:Cancel() end
|
||||
castbar.expiry = C_Timer.NewTimer(info.duration:GetRemainingDuration(), castbar.onExpire)
|
||||
castbar:Show()
|
||||
end
|
||||
|
||||
function HideCast(plate)
|
||||
local castbar = plate.castbar
|
||||
if not castbar.expiry then return end
|
||||
castbar.expiry:Cancel()
|
||||
castbar.expiry = nil
|
||||
castbar.timer:Disable()
|
||||
castbar:Hide()
|
||||
end
|
||||
|
||||
-- Start or stop the plate's castbar from the cast cache and the config.
|
||||
function UpdateCast(plate)
|
||||
local info = castState[plate.guid]
|
||||
if info and not info.duration:HasExpired() and cfg.showcastbar and (plate.istarget or not cfg.targetcastbar) then
|
||||
ShowCast(plate, info)
|
||||
else
|
||||
HideCast(plate)
|
||||
end
|
||||
end
|
||||
|
||||
-- The bar's cast ran out without a STOP: treat it as one.
|
||||
local function ExpireCast(plate)
|
||||
castState[plate.guid] = nil
|
||||
HideCast(plate)
|
||||
UpdateCombatColor(plate)
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- Cast events (per plate)
|
||||
-- ============================================================================
|
||||
@@ -1281,6 +1242,11 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
castbar.text:SetNonSpaceWrap(false)
|
||||
castbar.text:SetTextColor(1,1,1,.5)
|
||||
|
||||
castbar.timer = C_DurationUtil.CreateDurationTextBinding()
|
||||
castbar.timer:SetFontString(castbar.text)
|
||||
castbar.timer:SetFormatter(castFormatter)
|
||||
castbar.onExpire = function() ExpireCast(nameplate) end
|
||||
|
||||
castbar.spell = castbar:CreateFontString("Status", "DIALOG", "GameFontNormal")
|
||||
castbar.spell:SetPoint("CENTER", castbar, "CENTER")
|
||||
castbar.spell:SetNonSpaceWrap(false)
|
||||
@@ -1372,8 +1338,6 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
nameplate.castbar:SetStatusBarTexture(cbtexture or hptexture)
|
||||
local cbr, cbg, cbb, cba = GetStringColor(C.appearance.castbar.castbarcolor)
|
||||
nameplate.castbar:SetStatusBarColor(cbr, cbg, cbb, cba)
|
||||
-- reset endTime cache so color/texture refresh takes effect on next cast
|
||||
nameplate.castbar.lastEndTime = nil
|
||||
CreateBackdrop(nameplate.castbar, default_border)
|
||||
|
||||
nameplate.castbar.text:SetFont(font, font_size, "OUTLINE")
|
||||
@@ -1652,8 +1616,6 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
local plate = info and plateByGuid[guid]
|
||||
if not plate then return end
|
||||
info.noInterrupt = event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE"
|
||||
-- UpdateCastbar only restyles on a new cast; force it
|
||||
plate.castbar.lastEndTime = nil
|
||||
UpdateCast(plate)
|
||||
end
|
||||
events.UNIT_SPELLCAST_NOT_INTERRUPTIBLE = events.UNIT_SPELLCAST_INTERRUPTIBLE
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
pfUI:RegisterModule("pixelperfect", function ()
|
||||
-- pre-calculated min values
|
||||
local statics = {
|
||||
[4] = 1.4222222222222,
|
||||
[5] = 1.1377777777778,
|
||||
[6] = 0.94814814814815,
|
||||
[7] = 0.81269841269841,
|
||||
[8] = 0.71111111111111,
|
||||
}
|
||||
|
||||
-- pixel perfect
|
||||
local function pixelperfect()
|
||||
local conf = tonumber(C.global.pixelperfect)
|
||||
if conf < 4 then
|
||||
-- restore gamesettings
|
||||
local scale = GetCVar("uiScale")
|
||||
local use = GetCVar("useUiScale")
|
||||
|
||||
if use == 1 then
|
||||
UIParent:SetScale(tonumber(use))
|
||||
else
|
||||
UIParent:SetScale(.9)
|
||||
end
|
||||
else
|
||||
local scale = conf and statics[conf] or 1
|
||||
|
||||
SetCVar("uiScale", scale)
|
||||
SetCVar("useUiScale", 1)
|
||||
|
||||
UIParent:SetScale(scale)
|
||||
end
|
||||
end
|
||||
|
||||
-- pixelperfect: native UIScale listener
|
||||
if tonumber(C.global.pixelperfect) > 0 then
|
||||
pfUI.events:RegisterFrameEventAndCallback("PLAYER_ENTERING_WORLD", pixelperfect)
|
||||
pixelperfect()
|
||||
end
|
||||
|
||||
pfUI.pixelperfect = {
|
||||
UpdateConfig = pixelperfect
|
||||
}
|
||||
end)
|
||||
+6
-10
@@ -238,17 +238,11 @@ pfUI:RegisterModule("roll", function ()
|
||||
f.time.bar = CreateFrame("StatusBar", "pfLootRollFrame" .. id .. "TimeBar", f.time)
|
||||
f.time.bar:SetAllPoints(f.time)
|
||||
f.time.bar:SetStatusBarTexture(pfUI.media["img:bar"])
|
||||
f.time.bar:SetMinMaxValues(0, 100)
|
||||
local r, g, b, a = GetStringColor(C.appearance.border.color)
|
||||
f.time.bar:SetStatusBarColor(r, g, b)
|
||||
f.time.bar:SetValue(20)
|
||||
f.time.bar:SetScript("OnUpdate", function()
|
||||
if not this:GetParent():GetParent().rollID then return end
|
||||
local left = GetLootRollTimeLeft(this:GetParent():GetParent().rollID)
|
||||
local min, max = this:GetMinMaxValues()
|
||||
if left < min or left > max then left = min end
|
||||
this:SetValue(left)
|
||||
end)
|
||||
-- drains by itself; UpdateLootRoll sets the roll's time span
|
||||
f.time.duration = C_DurationUtil.CreateDuration()
|
||||
f.time.bar:SetTimerDuration(f.time.duration, Enum.StatusBarInterpolation.Immediate, Enum.StatusBarTimerDirection.RemainingTime)
|
||||
|
||||
return f
|
||||
end
|
||||
@@ -299,7 +293,9 @@ pfUI:RegisterModule("roll", function ()
|
||||
pfUI.roll.frames[id].name.text:SetTextColor(color.r, color.g, color.b, 1)
|
||||
pfUI.roll.frames[id].icon.tex:SetTexture(texture)
|
||||
pfUI.roll.frames[id].backdrop:SetBackdropBorderColor(color.r, color.g, color.b)
|
||||
pfUI.roll.frames[id].time.bar:SetMinMaxValues(0, pfUI.roll.frames[id].rollTime)
|
||||
-- both in milliseconds
|
||||
local left = GetLootRollTimeLeft(pfUI.roll.frames[id].rollID)
|
||||
pfUI.roll.frames[id].time.duration:SetTimeFromEnd(GetTime() + left / 1000, pfUI.roll.frames[id].rollTime / 1000)
|
||||
|
||||
if C.loot.raritytimer == "1" then
|
||||
pfUI.roll.frames[id].time.bar:SetStatusBarColor(color.r, color.g, color.b, .5)
|
||||
|
||||
@@ -899,7 +899,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
|
||||
|
||||
-- trigger the event whenever SuperMacro got an update
|
||||
hooksecurefunc("SM_UpdateActionSpell", function()
|
||||
for slot=1,120 do pfUI.bars.update[slot] = true end
|
||||
for slot=1,120 do pfUI.bars.QueueSlot(slot) end
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
@@ -392,6 +392,10 @@ pfUI:SetScript("OnEvent", function()
|
||||
SetupConfigEnvironment()
|
||||
pfUI:UpdateFonts()
|
||||
|
||||
-- scale UIParent before the modules size their borders from it
|
||||
pfUI.api.UpdateUIScale()
|
||||
pfUI.events:RegisterFrameEventAndCallback("UI_SCALE_CHANGED", pfUI.api.UpdateUIScale)
|
||||
|
||||
-- load modules
|
||||
for _, m in pairs(this.modules) do
|
||||
if not ( pfUI_config["disabled"] and pfUI_config["disabled"][m] == "1" ) then
|
||||
|
||||
Reference in New Issue
Block a user