1697 lines
70 KiB
Lua
1697 lines
70 KiB
Lua
BNP = BNP or {}
|
|
|
|
local _, optionsPlayerClass = UnitClass("player")
|
|
local comboOptionsClass = (optionsPlayerClass == "ROGUE" or optionsPlayerClass == "DRUID")
|
|
|
|
local function Round(value, step)
|
|
return math.floor((value / step) + 0.5) * step
|
|
end
|
|
|
|
local function RoundSignedInteger(value)
|
|
value = tonumber(value) or 0
|
|
if value >= 0 then return math.floor(value + 0.5) end
|
|
return math.ceil(value - 0.5)
|
|
end
|
|
|
|
local sliderCount = 0
|
|
local function CreateSlider(parent, label, minValue, maxValue, step, y, x, width)
|
|
sliderCount = sliderCount + 1
|
|
local slider = CreateFrame("Slider", "BNPOptionsSlider" .. sliderCount, parent, "OptionsSliderTemplate")
|
|
slider:SetPoint("TOPLEFT", parent, "TOPLEFT", x or 28, y)
|
|
slider:SetWidth(width or 220)
|
|
slider:SetHeight(16)
|
|
slider:SetMinMaxValues(minValue, maxValue)
|
|
slider:SetValueStep(step)
|
|
getglobal(slider:GetName() .. "Low"):SetText(tostring(minValue))
|
|
getglobal(slider:GetName() .. "High"):SetText(tostring(maxValue))
|
|
getglobal(slider:GetName() .. "Text"):SetText(label)
|
|
return slider
|
|
end
|
|
|
|
local function CreateCheck(parent, label, y, onclick, x)
|
|
local check = CreateFrame("CheckButton", nil, parent, "UICheckButtonTemplate")
|
|
check:SetPoint("TOPLEFT", parent, "TOPLEFT", x or 22, y)
|
|
check:SetWidth(24)
|
|
check:SetHeight(24)
|
|
|
|
local text = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
text:SetPoint("LEFT", check, "RIGHT", 4, 0)
|
|
text:SetText(label)
|
|
check.BNPLabel = text
|
|
|
|
check:SetScript("OnClick", onclick)
|
|
return check
|
|
end
|
|
|
|
-- 1.12-safe emergency recorder ------------------------------------------------
|
|
--
|
|
-- Keep a compact recorder directly in this already proven options file. The
|
|
-- full diagnostic module replaces BNP.OpenAuraRecorder later when it loads.
|
|
-- If an old/private 1.12 client refuses that larger module, this fallback still
|
|
-- provides the window and the ClassicAPI aura data we actually need.
|
|
|
|
local emergency = BNP.emergencyAuraRecorder or {}
|
|
BNP.emergencyAuraRecorder = emergency
|
|
emergency.lines = emergency.lines or {}
|
|
emergency.active = false
|
|
|
|
local function EmergencyValue(value, limit)
|
|
if value == nil then return "nil" end
|
|
local text = tostring(value)
|
|
text = string.gsub(text, "\r", "\\r")
|
|
text = string.gsub(text, "\n", "\\n")
|
|
text = string.gsub(text, "\t", "\\t")
|
|
limit = limit or 240
|
|
if string.len(text) > limit then text = string.sub(text, 1, limit) .. "..." end
|
|
return text
|
|
end
|
|
|
|
local function EmergencyAppend(text)
|
|
text = EmergencyValue(text, 1300)
|
|
if string.len(table.concat(emergency.lines, "\n")) + string.len(text) > 60000 then
|
|
if not emergency.limitHit then
|
|
table.insert(emergency.lines, "[REPORT LIMIT REACHED - recording stopped]")
|
|
emergency.limitHit = true
|
|
emergency.active = false
|
|
end
|
|
return
|
|
end
|
|
table.insert(emergency.lines, text)
|
|
emergency.dirty = true
|
|
end
|
|
|
|
local function EmergencyFields(data)
|
|
if type(data) ~= "table" then return EmergencyValue(data) end
|
|
local fields = {}
|
|
local key, value
|
|
for key, value in pairs(data) do
|
|
local kind = type(value)
|
|
if kind ~= "table" and kind ~= "function" and kind ~= "userdata" then
|
|
table.insert(fields, EmergencyValue(key, 80) .. "=" .. EmergencyValue(value, 180))
|
|
end
|
|
end
|
|
table.sort(fields)
|
|
return table.concat(fields, " | ")
|
|
end
|
|
|
|
local function EmergencyGUID(unit)
|
|
local exists, guid = UnitExists(unit)
|
|
if exists and guid then return guid end
|
|
if UnitGUID then
|
|
local ok, value = pcall(UnitGUID, unit)
|
|
if ok then return value end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function EmergencyWantedAura(aura)
|
|
if type(aura) ~= "table" then return true end
|
|
local spellID = tonumber(aura.spellId or aura.spellID)
|
|
local name = string.lower(tostring(aura.name or ""))
|
|
if spellID == 17794 or spellID == 17797 or spellID == 17798 or spellID == 17799 or spellID == 17800 then return true end
|
|
if name == "shadow vulnerability" or name == "schattenverwundbarkeit" then return true end
|
|
|
|
local playerGUID = EmergencyGUID("player")
|
|
if aura.sourceGUID and playerGUID then return aura.sourceGUID == playerGUID end
|
|
if aura.sourceUnit then return aura.sourceUnit == "player" end
|
|
return false
|
|
end
|
|
|
|
local function EmergencyIsShadowBolt(spellID, spellName)
|
|
local numeric = tonumber(spellID)
|
|
if numeric == 686 or numeric == 695 or numeric == 705 or numeric == 1088 or
|
|
numeric == 1106 or numeric == 7641 or numeric == 11659 or numeric == 11660 or
|
|
numeric == 11661 or numeric == 25307 then return true end
|
|
local name = string.lower(tostring(spellName or ""))
|
|
return name == "shadow bolt" or name == "schattenblitz"
|
|
end
|
|
|
|
local function EmergencyRefresh()
|
|
if not emergency.edit then return end
|
|
emergency.edit:SetText(table.concat(emergency.lines, "\n"))
|
|
emergency.edit:SetHeight(math.max(300, table.getn(emergency.lines) * 16 + 30))
|
|
if emergency.status then
|
|
if emergency.active then
|
|
emergency.status:SetText("RECORDING | Target: " .. EmergencyValue(UnitName("target") or "none", 100))
|
|
emergency.status:SetTextColor(0.2, 1, 0.35)
|
|
else
|
|
emergency.status:SetText("STOPPED | " .. tostring(table.getn(emergency.lines)) .. " lines")
|
|
emergency.status:SetTextColor(1, 0.82, 0)
|
|
end
|
|
end
|
|
emergency.dirty = false
|
|
end
|
|
|
|
local function EmergencySnapshot(reason, force)
|
|
if not UnitExists("target") then
|
|
if force then EmergencyAppend("AURA_SNAPSHOT | reason=" .. reason .. " | no target") end
|
|
return
|
|
end
|
|
|
|
local auraLines = {}
|
|
local signatureParts = {}
|
|
local count = 0
|
|
local classic = type(C_UnitAuras) == "table" and type(C_UnitAuras.GetDebuffDataByIndex) == "function"
|
|
local i
|
|
|
|
if classic then
|
|
for i = 1, 64 do
|
|
local ok, aura = pcall(C_UnitAuras.GetDebuffDataByIndex, "target", i)
|
|
if not ok then
|
|
EmergencyAppend("CLASSICAPI_ERROR | " .. EmergencyValue(aura, 800))
|
|
break
|
|
end
|
|
if not aura then break end
|
|
if EmergencyWantedAura(aura) then
|
|
count = count + 1
|
|
local fields = EmergencyFields(aura)
|
|
table.insert(signatureParts, fields)
|
|
table.insert(auraLines, " CLASSIC_AURA " .. tostring(i) .. " | " .. fields)
|
|
end
|
|
end
|
|
else
|
|
for i = 1, 64 do
|
|
local ok, texture, stacks, dispelType, spellID, r5, r6, r7, r8, r9, r10 = pcall(UnitDebuff, "target", i)
|
|
if not ok or not texture then break end
|
|
count = count + 1
|
|
local fields = "spellId=" .. EmergencyValue(spellID) ..
|
|
" | stacks=" .. EmergencyValue(stacks) ..
|
|
" | type=" .. EmergencyValue(dispelType) ..
|
|
" | texture=" .. EmergencyValue(texture, 160) ..
|
|
" | r5=" .. EmergencyValue(r5) .. " | r6=" .. EmergencyValue(r6) ..
|
|
" | r7=" .. EmergencyValue(r7) .. " | r8=" .. EmergencyValue(r8) ..
|
|
" | r9=" .. EmergencyValue(r9) .. " | r10=" .. EmergencyValue(r10)
|
|
table.insert(signatureParts, fields)
|
|
table.insert(auraLines, " LEGACY_AURA " .. tostring(i) .. " | " .. fields)
|
|
end
|
|
end
|
|
|
|
local signature = table.concat(signatureParts, "||")
|
|
if emergency.baselineOnly then
|
|
emergency.lastSignature = signature
|
|
return
|
|
end
|
|
if not force and signature == emergency.lastSignature then return end
|
|
emergency.lastSignature = signature
|
|
EmergencyAppend(
|
|
"[+" .. string.format("%.3f", GetTime() - (emergency.startedAt or GetTime())) .. "] AURA_SNAPSHOT" ..
|
|
" | reason=" .. EmergencyValue(reason) ..
|
|
" | guid=" .. EmergencyValue(EmergencyGUID("target")) ..
|
|
" | source=" .. (classic and "ClassicAPI" or "UnitDebuff") ..
|
|
" | count=" .. tostring(count)
|
|
)
|
|
if count == 0 then
|
|
EmergencyAppend(" AURA none")
|
|
else
|
|
for i = 1, table.getn(auraLines) do EmergencyAppend(auraLines[i]) end
|
|
end
|
|
end
|
|
|
|
local function EmergencyUnregister()
|
|
if emergency.eventFrame then pcall(emergency.eventFrame.UnregisterAllEvents, emergency.eventFrame) end
|
|
end
|
|
|
|
local function EmergencyStop(reason)
|
|
if not emergency.active then EmergencyRefresh() return end
|
|
EmergencySnapshot("final", true)
|
|
emergency.active = false
|
|
EmergencyUnregister()
|
|
if emergency.frame then emergency.frame:SetScript("OnUpdate", nil) end
|
|
EmergencyAppend("=== END | reason=" .. EmergencyValue(reason or "user") .. " ===")
|
|
EmergencyRefresh()
|
|
end
|
|
|
|
local function EmergencyStart()
|
|
EmergencyUnregister()
|
|
emergency.lines = {}
|
|
emergency.limitHit = false
|
|
emergency.lastSignature = nil
|
|
emergency.startedAt = GetTime()
|
|
emergency.elapsed = 0
|
|
emergency.active = true
|
|
if emergency.frame and emergency.onUpdate then emergency.frame:SetScript("OnUpdate", emergency.onUpdate) end
|
|
EmergencyAppend("BNP_CLASSICAPI_AURA_REPORT v2")
|
|
EmergencyAppend(
|
|
"ClassicAPI | version=" .. EmergencyValue(CLASSIC_API_VERSION or "not detected") ..
|
|
" | C_UnitAuras=" .. ((type(C_UnitAuras) == "table" and type(C_UnitAuras.GetDebuffDataByIndex) == "function") and "yes" or "no") ..
|
|
" | CopyToClipboard=" .. (CopyToClipboard and "yes" or "no")
|
|
)
|
|
EmergencyAppend("Aura filter | own auras + Shadow Vulnerability from any Warlock")
|
|
EmergencyAppend("Target | name=" .. EmergencyValue(UnitName("target")) .. " | guid=" .. EmergencyValue(EmergencyGUID("target")))
|
|
EmergencyAppend("Test | proc aura, refresh it while active, then let it expire")
|
|
EmergencyAppend("=== LIVE RECORDING ===")
|
|
|
|
local events = {
|
|
"UNIT_CASTEVENT", "UNIT_AURA", "PLAYER_TARGET_CHANGED",
|
|
"UNIT_SPELLCAST_SENT", "UNIT_SPELLCAST_START", "UNIT_SPELLCAST_STOP",
|
|
"UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_CHANNEL_START", "UNIT_SPELLCAST_CHANNEL_STOP",
|
|
}
|
|
local i
|
|
for i = 1, table.getn(events) do pcall(emergency.eventFrame.RegisterEvent, emergency.eventFrame, events[i]) end
|
|
-- Learn the target's existing auras without printing them. Only changes
|
|
-- occurring after Start Recording belong in the diagnostic report.
|
|
emergency.baselineOnly = true
|
|
EmergencySnapshot("baseline", false)
|
|
emergency.baselineOnly = false
|
|
EmergencyRefresh()
|
|
end
|
|
|
|
local function EmergencyCreateWindow()
|
|
if emergency.frame then return emergency.frame end
|
|
|
|
local frame = CreateFrame("Frame", "BNPEmergencyAuraRecorderFrame", UIParent)
|
|
frame:SetWidth(720)
|
|
frame:SetHeight(520)
|
|
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 20)
|
|
frame:SetFrameStrata("DIALOG")
|
|
frame:SetBackdrop({
|
|
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
|
|
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
|
tile = true, tileSize = 32, edgeSize = 32,
|
|
insets = { left = 11, right = 12, top = 12, bottom = 11 }
|
|
})
|
|
frame:SetMovable(true)
|
|
frame:EnableMouse(true)
|
|
frame:RegisterForDrag("LeftButton")
|
|
frame:SetScript("OnDragStart", function() this:StartMoving() end)
|
|
frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
|
frame:SetScript("OnHide", function() EmergencyStop("window closed") end)
|
|
emergency.frame = frame
|
|
|
|
local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
title:SetPoint("TOP", frame, "TOP", 0, -18)
|
|
title:SetText("Missing Spell / Aura Recorder")
|
|
|
|
local status = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
status:SetPoint("TOPLEFT", frame, "TOPLEFT", 26, -50)
|
|
status:SetWidth(660)
|
|
status:SetJustifyH("LEFT")
|
|
emergency.status = status
|
|
|
|
local start = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
start:SetPoint("TOPLEFT", frame, "TOPLEFT", 26, -76)
|
|
start:SetWidth(126)
|
|
start:SetHeight(24)
|
|
start:SetText("Start Recording")
|
|
start:SetScript("OnClick", EmergencyStart)
|
|
|
|
local stop = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
stop:SetPoint("LEFT", start, "RIGHT", 8, 0)
|
|
stop:SetWidth(82)
|
|
stop:SetHeight(24)
|
|
stop:SetText("Stop")
|
|
stop:SetScript("OnClick", function() EmergencyStop("user") end)
|
|
|
|
local copy = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
copy:SetPoint("LEFT", stop, "RIGHT", 8, 0)
|
|
copy:SetWidth(110)
|
|
copy:SetHeight(24)
|
|
copy:SetText(CopyToClipboard and "Copy Report" or "Select All")
|
|
copy:SetScript("OnClick", function()
|
|
EmergencyRefresh()
|
|
local report = table.concat(emergency.lines, "\n")
|
|
if CopyToClipboard and pcall(CopyToClipboard, report) then
|
|
emergency.status:SetText("COPIED | Paste with Ctrl+V")
|
|
emergency.status:SetTextColor(0.2, 1, 0.35)
|
|
else
|
|
emergency.edit:SetFocus()
|
|
emergency.edit:HighlightText()
|
|
emergency.status:SetText("SELECTED | Press Ctrl+C")
|
|
end
|
|
end)
|
|
|
|
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
|
|
close:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -5, -5)
|
|
|
|
local scroll = CreateFrame("ScrollFrame", "BNPEmergencyAuraRecorderScroll", frame, "UIPanelScrollFrameTemplate")
|
|
scroll:SetPoint("TOPLEFT", frame, "TOPLEFT", 26, -112)
|
|
scroll:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -48, 30)
|
|
|
|
local edit = CreateFrame("EditBox", "BNPEmergencyAuraRecorderEdit", scroll)
|
|
edit:SetWidth(640)
|
|
edit:SetHeight(300)
|
|
edit:SetMultiLine(true)
|
|
edit:SetAutoFocus(false)
|
|
edit:SetFontObject(ChatFontNormal)
|
|
edit:SetMaxLetters(65000)
|
|
edit:SetScript("OnEscapePressed", function() this:ClearFocus() end)
|
|
scroll:SetScrollChild(edit)
|
|
emergency.edit = edit
|
|
|
|
emergency.eventFrame = CreateFrame("Frame", "BNPEmergencyAuraRecorderEvents")
|
|
emergency.eventFrame:SetScript("OnEvent", function()
|
|
if not emergency.active then return end
|
|
if event == "UNIT_AURA" and arg1 ~= "target" then return end
|
|
if event == "UNIT_CASTEVENT" and arg1 ~= EmergencyGUID("player") then return end
|
|
EmergencyAppend(
|
|
"[+" .. string.format("%.3f", GetTime() - emergency.startedAt) .. "] EVENT | " .. EmergencyValue(event) ..
|
|
" | a1=" .. EmergencyValue(arg1) .. " | a2=" .. EmergencyValue(arg2) ..
|
|
" | a3=" .. EmergencyValue(arg3) .. " | a4=" .. EmergencyValue(arg4) ..
|
|
" | a5=" .. EmergencyValue(arg5) .. " | a6=" .. EmergencyValue(arg6)
|
|
)
|
|
emergency.forceSnapshot = event == "PLAYER_TARGET_CHANGED" or
|
|
(event == "UNIT_CASTEVENT" and EmergencyIsShadowBolt(arg4)) or
|
|
(event == "UNIT_SPELLCAST_SENT" and EmergencyIsShadowBolt(arg4, arg5)) or
|
|
(event ~= "UNIT_SPELLCAST_SENT" and string.find(tostring(event or ""), "UNIT_SPELLCAST_", 1, true) and EmergencyIsShadowBolt(arg3, arg4))
|
|
end)
|
|
|
|
emergency.onUpdate = function()
|
|
if not emergency.active then return end
|
|
emergency.elapsed = (emergency.elapsed or 0) + arg1
|
|
if emergency.elapsed >= 0.12 then
|
|
emergency.elapsed = 0
|
|
EmergencySnapshot(emergency.forceSnapshot and "event" or "poll", emergency.forceSnapshot)
|
|
emergency.forceSnapshot = false
|
|
if emergency.dirty then EmergencyRefresh() end
|
|
end
|
|
end
|
|
|
|
return frame
|
|
end
|
|
|
|
-- This remains available even if the full recorder loads, so that module can
|
|
-- fall back when a private client rejects one of the larger window calls.
|
|
function BNP:OpenEmergencyAuraRecorder()
|
|
local frame = EmergencyCreateWindow()
|
|
frame:Show()
|
|
EmergencyRefresh()
|
|
end
|
|
|
|
function BNP:StartEmergencyAuraRecorder()
|
|
EmergencyStart()
|
|
end
|
|
|
|
-- This is intentionally defined before the large optional recorder module.
|
|
-- A successful module load overwrites it; otherwise the button still works.
|
|
function BNP:OpenAuraRecorder()
|
|
self:OpenEmergencyAuraRecorder()
|
|
end
|
|
|
|
function BNP:CreateOptions()
|
|
if self.optionsFrame then return end
|
|
|
|
local frame = CreateFrame("Frame", "BNPOptionsFrame", UIParent)
|
|
frame:SetWidth(430)
|
|
frame:SetHeight(550)
|
|
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 40)
|
|
frame:SetFrameStrata("DIALOG")
|
|
frame:SetBackdrop({
|
|
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
|
|
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
|
tile = true, tileSize = 32, edgeSize = 32,
|
|
insets = { left = 11, right = 12, top = 12, bottom = 11 }
|
|
})
|
|
frame:SetMovable(true)
|
|
frame:EnableMouse(true)
|
|
frame:RegisterForDrag("LeftButton")
|
|
frame:SetScript("OnDragStart", function() this:StartMoving() end)
|
|
frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
|
frame:Hide()
|
|
|
|
local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
title:SetPoint("TOP", frame, "TOP", 0, -18)
|
|
title:SetText("Blizz Nameplates+")
|
|
|
|
local version = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
version:SetPoint("TOP", title, "BOTTOM", 0, -4)
|
|
version:SetText("Version " .. tostring(BNP.version or "?"))
|
|
frame.versionText = version
|
|
|
|
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
|
|
close:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -5, -5)
|
|
|
|
local function CreatePage()
|
|
local page = CreateFrame("Frame", nil, frame)
|
|
page:SetPoint("TOPLEFT", frame, "TOPLEFT", 18, -104)
|
|
page:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -18, 22)
|
|
page:Hide()
|
|
return page
|
|
end
|
|
|
|
local function CreateSection(parent, label, y)
|
|
local text = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
text:SetPoint("TOPLEFT", parent, "TOPLEFT", 8, y)
|
|
text:SetText(label)
|
|
|
|
local line = parent:CreateTexture(nil, "ARTWORK")
|
|
line:SetTexture(1, 1, 1, 0.16)
|
|
line:SetPoint("LEFT", text, "RIGHT", 8, 0)
|
|
line:SetPoint("RIGHT", parent, "RIGHT", -8, 0)
|
|
line:SetHeight(1)
|
|
|
|
return text
|
|
end
|
|
|
|
local function SetCheckEnabled(check, enabled)
|
|
if not check then return end
|
|
if enabled then
|
|
if check.Enable then check:Enable() end
|
|
check:SetAlpha(1.0)
|
|
if check.BNPLabel then check.BNPLabel:SetTextColor(1, 0.82, 0) end
|
|
else
|
|
if check.Disable then check:Disable() end
|
|
check:SetAlpha(0.45)
|
|
if check.BNPLabel then check.BNPLabel:SetTextColor(0.5, 0.5, 0.5) end
|
|
end
|
|
end
|
|
|
|
-- Compact tab navigation. Totems stays separate from aura tracking so PvP
|
|
-- nameplate indicators never touch the debuff/CC state machine.
|
|
frame.pages = {
|
|
nameplates = CreatePage(),
|
|
auras = CreatePage(),
|
|
totems = CreatePage(),
|
|
castbar = CreatePage(),
|
|
target = CreatePage(),
|
|
tools = CreatePage(),
|
|
}
|
|
frame.tabs = {}
|
|
|
|
local tabDefs = {
|
|
{ key = "nameplates", label = "Nameplates", width = 76 },
|
|
{ key = "auras", label = "Auras", width = 52 },
|
|
{ key = "totems", label = "Totems", width = 58 },
|
|
{ key = "castbar", label = "Castbar", width = 60 },
|
|
{ key = "target", label = "Target", width = 56 },
|
|
{ key = "tools", label = "Tools", width = 50 },
|
|
}
|
|
|
|
function frame:ShowTab(key)
|
|
local pageKey, page
|
|
for pageKey, page in pairs(self.pages) do
|
|
if pageKey == key then page:Show() else page:Hide() end
|
|
end
|
|
|
|
local i
|
|
for i = 1, table.getn(tabDefs) do
|
|
local def = tabDefs[i]
|
|
local button = self.tabs[def.key]
|
|
if button then
|
|
if def.key == key then
|
|
if button.Disable then button:Disable() end
|
|
button:SetAlpha(1.0)
|
|
else
|
|
if button.Enable then button:Enable() end
|
|
button:SetAlpha(0.80)
|
|
end
|
|
end
|
|
end
|
|
self.selectedTab = key
|
|
end
|
|
|
|
local tabX = 28
|
|
local i
|
|
for i = 1, table.getn(tabDefs) do
|
|
local def = tabDefs[i]
|
|
local button = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
button:SetWidth(def.width)
|
|
button:SetHeight(24)
|
|
button:SetPoint("TOPLEFT", frame, "TOPLEFT", tabX, -68)
|
|
button:SetText(def.label)
|
|
button.BNPTabKey = def.key
|
|
button:SetScript("OnClick", function()
|
|
frame:ShowTab(this.BNPTabKey)
|
|
end)
|
|
frame.tabs[def.key] = button
|
|
tabX = tabX + def.width + 4
|
|
end
|
|
|
|
-- NAMEPLATES TAB ---------------------------------------------------------
|
|
local nameplatesPage = frame.pages.nameplates
|
|
CreateSection(nameplatesPage, "General", -4)
|
|
|
|
local scale = CreateSlider(nameplatesPage, "Nameplate Scale", 0.70, 1.50, 0.05, -36, 28, 150)
|
|
scale:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = Round(this:GetValue(), 0.05)
|
|
BNP_DB.nameplateScale = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Nameplate Scale: " .. string.format("%.2f", value))
|
|
if BNP.ApplyNameplateScaleAll then BNP:ApplyNameplateScaleAll() end
|
|
end)
|
|
frame.scaleSlider = scale
|
|
|
|
local yOffset = CreateSlider(nameplatesPage, "Nameplate Y Offset", 0, 50, 1, -36, 220, 150)
|
|
yOffset:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.nameplateYOffset = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Nameplate Y Offset: +" .. value)
|
|
if BNP.ApplyNameplateYOffsetAll then BNP:ApplyNameplateYOffsetAll() end
|
|
end)
|
|
frame.yOffsetSlider = yOffset
|
|
|
|
local nonTargetAlpha = CreateSlider(nameplatesPage, "Non-Target Alpha", 30, 100, 5, -82, 28, 150)
|
|
nonTargetAlpha:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local percent = math.floor((this:GetValue() / 5) + 0.5) * 5
|
|
if percent < 30 then percent = 30 end
|
|
if percent > 100 then percent = 100 end
|
|
BNP_DB.nonTargetAlpha = percent / 100
|
|
getglobal(this:GetName() .. "Text"):SetText("Non-Target Alpha: " .. percent .. "%")
|
|
if BNP.RefreshNonTargetAlpha then BNP:RefreshNonTargetAlpha() end
|
|
end)
|
|
frame.nonTargetAlphaSlider = nonTargetAlpha
|
|
|
|
local classColors = CreateCheck(nameplatesPage, "Class Colors", -78, function()
|
|
BNP_DB.classColors = this:GetChecked() and true or false
|
|
if BNP.RefreshClassColors then BNP:RefreshClassColors() end
|
|
end, 214)
|
|
frame.classColorsCheck = classColors
|
|
|
|
CreateSection(nameplatesPage, "Names", -138)
|
|
|
|
local hidePlayerNames = CreateCheck(nameplatesPage, "Hide Player Names", -166, function()
|
|
BNP_DB.hidePlayerNames = this:GetChecked() and true or false
|
|
if BNP.RefreshNameVisibility then BNP:RefreshNameVisibility() end
|
|
end, 22)
|
|
frame.hidePlayerNamesCheck = hidePlayerNames
|
|
|
|
local tank = CreateCheck(nameplatesPage, "Tank Mode", -106, function()
|
|
BNP_DB.tankMode = this:GetChecked() and true or false
|
|
if BNP.UpdateTankMode then BNP:UpdateTankMode() end
|
|
end)
|
|
tank:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText("Tank Mode", 1, 0.82, 0)
|
|
GameTooltip:AddLine("Green: the unit is targeting you.", 1, 1, 1)
|
|
GameTooltip:AddLine("Red: the unit is targeting someone else.", 1, 1, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
tank:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
frame.tankCheck = tank
|
|
|
|
local hideNPCNames = CreateCheck(nameplatesPage, "Hide NPC/Mob Names", -166, function()
|
|
BNP_DB.hideNPCNames = this:GetChecked() and true or false
|
|
if BNP.RefreshNameVisibility then BNP:RefreshNameVisibility() end
|
|
end, 214)
|
|
frame.hideNPCNamesCheck = hideNPCNames
|
|
|
|
CreateSection(nameplatesPage, "Health Text", -250)
|
|
|
|
local healthTextLabel = nameplatesPage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
healthTextLabel:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 28, -278)
|
|
healthTextLabel:SetText("Display")
|
|
|
|
local healthTextDropdown = CreateFrame("Frame", "BNPHealthTextDropdown", nameplatesPage, "UIDropDownMenuTemplate")
|
|
healthTextDropdown:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 10, -290)
|
|
UIDropDownMenu_SetWidth(150, healthTextDropdown)
|
|
|
|
local healthModeLabels = {
|
|
off = "Off",
|
|
percent = "Percent",
|
|
hp = "HP",
|
|
both = "HP + Percent",
|
|
}
|
|
|
|
local function SetHealthTextMode(mode)
|
|
if not healthModeLabels[mode] then mode = "off" end
|
|
BNP_DB.healthText = mode
|
|
BNP_DB.healthPercent = (mode == "percent" or mode == "both")
|
|
UIDropDownMenu_SetSelectedValue(healthTextDropdown, mode)
|
|
UIDropDownMenu_SetText(healthModeLabels[mode], healthTextDropdown)
|
|
if BNP.RefreshHealthPercent then BNP:RefreshHealthPercent() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(healthTextDropdown, function()
|
|
local modes = { "off", "percent", "hp", "both" }
|
|
local n
|
|
for n = 1, table.getn(modes) do
|
|
local mode = modes[n]
|
|
local info = {}
|
|
info.text = healthModeLabels[mode]
|
|
info.value = mode
|
|
info.func = function() SetHealthTextMode(this.value) end
|
|
info.checked = (BNP:GetHealthTextMode() == mode)
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.healthTextDropdown = healthTextDropdown
|
|
frame.SetHealthTextMode = SetHealthTextMode
|
|
|
|
local healthFontSize = CreateSlider(nameplatesPage, "Health Font Size", 8, 20, 1, -344, 28, 150)
|
|
healthFontSize:SetScript("OnValueChanged", function()
|
|
if not BNP_DB or frame.BNPSyncingHealthTextControls then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.healthTextFontSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Health Font Size: " .. value)
|
|
if BNP.RefreshHealthPercent then BNP:RefreshHealthPercent() end
|
|
end)
|
|
frame.healthTextFontSizeSlider = healthFontSize
|
|
|
|
local healthOutlineLabel = nameplatesPage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
healthOutlineLabel:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 220, -278)
|
|
healthOutlineLabel:SetText("Outline")
|
|
|
|
local healthOutlineDropdown = CreateFrame("Frame", "BNPHealthOutlineDropdown", nameplatesPage, "UIDropDownMenuTemplate")
|
|
healthOutlineDropdown:SetPoint("TOPLEFT", nameplatesPage, "TOPLEFT", 200, -290)
|
|
UIDropDownMenu_SetWidth(150, healthOutlineDropdown)
|
|
|
|
local healthOutlineLabels = {
|
|
none = "None",
|
|
outline = "Outline",
|
|
thick = "Thick Outline",
|
|
}
|
|
|
|
local function SetHealthTextOutline(value)
|
|
if not healthOutlineLabels[value] then value = "outline" end
|
|
BNP_DB.healthTextOutline = value
|
|
UIDropDownMenu_SetSelectedValue(healthOutlineDropdown, value)
|
|
UIDropDownMenu_SetText(healthOutlineLabels[value], healthOutlineDropdown)
|
|
if BNP.RefreshHealthPercent then BNP:RefreshHealthPercent() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(healthOutlineDropdown, function()
|
|
local values = { "none", "outline", "thick" }
|
|
local n
|
|
for n = 1, table.getn(values) do
|
|
local value = values[n]
|
|
local info = {}
|
|
info.text = healthOutlineLabels[value]
|
|
info.value = value
|
|
info.func = function() SetHealthTextOutline(this.value) end
|
|
info.checked = (BNP:GetHealthTextOutline() == value)
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.healthTextOutlineDropdown = healthOutlineDropdown
|
|
frame.SetHealthTextOutline = SetHealthTextOutline
|
|
|
|
if comboOptionsClass then
|
|
CreateSection(nameplatesPage, "Combo Points", -380)
|
|
|
|
local comboPoints = CreateCheck(nameplatesPage, "Combo Points", -406, function()
|
|
BNP_DB.comboPoints = this:GetChecked() and true or false
|
|
if BNP.RefreshComboPoints then BNP:RefreshComboPoints() end
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
end, 22)
|
|
frame.comboPointsCheck = comboPoints
|
|
|
|
local comboYOffset = CreateSlider(nameplatesPage, "Combo Point Y Offset", -50, 50, 1, -408, 220, 150)
|
|
comboYOffset:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = RoundSignedInteger(this:GetValue())
|
|
BNP_DB.comboPointsYOffset = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Combo Point Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
if BNP.RefreshComboPoints then BNP:RefreshComboPoints() end
|
|
end)
|
|
frame.comboPointsYOffsetSlider = comboYOffset
|
|
end
|
|
|
|
-- Name text controls are independent from Nameplate Scale. The size setting
|
|
-- only touches the Blizzard name FontString; the Y offset only moves it.
|
|
local nameFontSize = CreateSlider(nameplatesPage, "Name Font Size", 8, 24, 1, -210, 28, 150)
|
|
nameFontSize:SetScript("OnValueChanged", function()
|
|
if not BNP_DB or frame.BNPSyncingNameControls then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.nameFontSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Name Font Size: " .. value)
|
|
if BNP.RefreshNameAppearance then BNP:RefreshNameAppearance() end
|
|
end)
|
|
frame.nameFontSizeSlider = nameFontSize
|
|
|
|
local nameFontYOffset = CreateSlider(nameplatesPage, "Name Y Offset", -50, 50, 1, -210, 220, 150)
|
|
nameFontYOffset:SetScript("OnValueChanged", function()
|
|
if not BNP_DB or frame.BNPSyncingNameControls then return end
|
|
local value = RoundSignedInteger(this:GetValue())
|
|
BNP_DB.nameFontYOffset = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Name Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
if BNP.ApplyNameFontYOffsetAll then BNP:ApplyNameFontYOffsetAll() end
|
|
end)
|
|
frame.nameFontYOffsetSlider = nameFontYOffset
|
|
|
|
-- AURAS TAB --------------------------------------------------------------
|
|
local aurasPage = frame.pages.auras
|
|
CreateSection(aurasPage, "Debuffs", -4)
|
|
|
|
local icon = CreateSlider(aurasPage, "Aura Icon Size", 12, 32, 1, -78, 28, 150)
|
|
icon:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.iconSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Aura Icon Size: " .. value)
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.iconSlider = icon
|
|
|
|
local debuffYOffset = CreateSlider(aurasPage, "Debuff Y Offset", -50, 50, 1, -78, 220, 150)
|
|
debuffYOffset:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = RoundSignedInteger(this:GetValue())
|
|
BNP_DB.debuffYOffset = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Debuff Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.debuffYOffsetSlider = debuffYOffset
|
|
|
|
local ccIcon = CreateSlider(aurasPage, "CC Icon Size", 12, 32, 1, -196, 28, 150)
|
|
ccIcon:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.ccIconSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("CC Icon Size: " .. value)
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.ccIconSlider = ccIcon
|
|
|
|
local ccYOffset = CreateSlider(aurasPage, "CC Y Offset", -50, 50, 1, -196, 220, 150)
|
|
ccYOffset:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = RoundSignedInteger(this:GetValue())
|
|
BNP_DB.ccYOffset = value
|
|
getglobal(this:GetName() .. "Text"):SetText("CC Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.ccYOffsetSlider = ccYOffset
|
|
|
|
local debuffs = CreateCheck(aurasPage, "Enable Debuffs", -30, function()
|
|
BNP_DB.debuffs = this:GetChecked() and true or false
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.debuffsCheck = debuffs
|
|
|
|
local debuffPositionDropdown = CreateFrame("Frame", "BNPDebuffPositionDropdown", aurasPage, "UIDropDownMenuTemplate")
|
|
debuffPositionDropdown:SetPoint("TOPLEFT", aurasPage, "TOPLEFT", 188, -24)
|
|
UIDropDownMenu_SetWidth(112, debuffPositionDropdown)
|
|
|
|
local debuffPositionLabels = {
|
|
top = "Top Mid",
|
|
top_left = "Top Left",
|
|
top_right = "Top Right",
|
|
left = "Left",
|
|
right = "Right",
|
|
bottom_mid = "Bottom Mid",
|
|
bottom_left = "Bottom Left",
|
|
bottom_right = "Bottom Right",
|
|
}
|
|
|
|
local function SetDebuffPosition(position)
|
|
if not debuffPositionLabels[position] then position = "top" end
|
|
BNP_DB.debuffPosition = position
|
|
UIDropDownMenu_SetSelectedValue(debuffPositionDropdown, position)
|
|
UIDropDownMenu_SetText(debuffPositionLabels[position], debuffPositionDropdown)
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if BNP.RefreshTotemIndicators then BNP:RefreshTotemIndicators() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(debuffPositionDropdown, function()
|
|
local positions = { "top", "top_left", "top_right", "left", "right", "bottom_mid", "bottom_left", "bottom_right" }
|
|
local n
|
|
for n = 1, table.getn(positions) do
|
|
local position = positions[n]
|
|
local info = {}
|
|
info.text = debuffPositionLabels[position]
|
|
info.value = position
|
|
info.func = function() SetDebuffPosition(this.value) end
|
|
info.checked = (BNP:GetDebuffPosition() == position)
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.debuffPositionDropdown = debuffPositionDropdown
|
|
frame.SetDebuffPosition = SetDebuffPosition
|
|
|
|
local debuffPositionLabel = aurasPage:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
debuffPositionLabel:SetPoint("BOTTOMLEFT", debuffPositionDropdown, "TOPLEFT", 18, 5)
|
|
debuffPositionLabel:SetText("Debuff Position")
|
|
frame.debuffPositionLabel = debuffPositionLabel
|
|
|
|
CreateSection(aurasPage, "Crowd Control", -122)
|
|
|
|
local crowdControl = CreateCheck(aurasPage, "Enable Crowd Control", -148, function()
|
|
BNP_DB.crowdControl = this:GetChecked() and true or false
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.crowdControlCheck = crowdControl
|
|
|
|
local ccPositionDropdown = CreateFrame("Frame", "BNPCCPositionDropdown", aurasPage, "UIDropDownMenuTemplate")
|
|
ccPositionDropdown:SetPoint("TOPLEFT", aurasPage, "TOPLEFT", 188, -142)
|
|
UIDropDownMenu_SetWidth(92, ccPositionDropdown)
|
|
|
|
local ccPositionLabels = {
|
|
top = "Top",
|
|
left = "Left",
|
|
right = "Right",
|
|
}
|
|
|
|
local function SetCCPosition(position)
|
|
if not ccPositionLabels[position] then position = "top" end
|
|
BNP_DB.ccPosition = position
|
|
UIDropDownMenu_SetSelectedValue(ccPositionDropdown, position)
|
|
UIDropDownMenu_SetText(ccPositionLabels[position], ccPositionDropdown)
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(ccPositionDropdown, function()
|
|
local positions = { "top", "left", "right" }
|
|
local n
|
|
for n = 1, table.getn(positions) do
|
|
local position = positions[n]
|
|
local info = {}
|
|
info.text = ccPositionLabels[position]
|
|
info.value = position
|
|
info.func = function() SetCCPosition(this.value) end
|
|
info.checked = (BNP:GetCCPosition() == position)
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.ccPositionDropdown = ccPositionDropdown
|
|
frame.SetCCPosition = SetCCPosition
|
|
|
|
local ccPositionLabel = aurasPage:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
ccPositionLabel:SetPoint("BOTTOMLEFT", ccPositionDropdown, "TOPLEFT", 18, 5)
|
|
ccPositionLabel:SetText("CC Position")
|
|
frame.ccPositionLabel = ccPositionLabel
|
|
|
|
local separateCCRow = CreateCheck(aurasPage, "Display CCs in Separate Row", -230, function()
|
|
BNP_DB.separateCCRow = this:GetChecked() and true or false
|
|
if BNP.RefreshAllAuraLayouts then BNP:RefreshAllAuraLayouts() end
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end, 42)
|
|
frame.separateCCRowCheck = separateCCRow
|
|
|
|
local showOtherCCs = CreateCheck(aurasPage, "Show CCs from Other Players", -256, function()
|
|
BNP_DB.showOtherCCs = this:GetChecked() and true or false
|
|
if BNP.RefreshDebuffVisibility then BNP:RefreshDebuffVisibility() end
|
|
end, 42)
|
|
frame.showOtherCCsCheck = showOtherCCs
|
|
|
|
CreateSection(aurasPage, "Immunities / Important Buffs", -294)
|
|
|
|
local pvpImmunities = CreateCheck(aurasPage, "Enable PvP Immunities", -320, function()
|
|
BNP_DB.pvpImmunities = this:GetChecked() and true or false
|
|
if BNP.RefreshImmunityVisibility then BNP:RefreshImmunityVisibility() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end, 22)
|
|
frame.pvpImmunitiesCheck = pvpImmunities
|
|
|
|
local immunityPositionDropdown = CreateFrame("Frame", "BNPImmunityPositionDropdown", aurasPage, "UIDropDownMenuTemplate")
|
|
immunityPositionDropdown:SetPoint("TOPLEFT", aurasPage, "TOPLEFT", 188, -314)
|
|
UIDropDownMenu_SetWidth(92, immunityPositionDropdown)
|
|
|
|
local immunityPositionLabels = {
|
|
top = "Top",
|
|
left = "Left",
|
|
right = "Right",
|
|
}
|
|
|
|
local function SetImmunityPosition(position)
|
|
if not immunityPositionLabels[position] then position = "top" end
|
|
BNP_DB.immunityPosition = position
|
|
UIDropDownMenu_SetSelectedValue(immunityPositionDropdown, position)
|
|
UIDropDownMenu_SetText(immunityPositionLabels[position], immunityPositionDropdown)
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(immunityPositionDropdown, function()
|
|
local positions = { "top", "left", "right" }
|
|
local n
|
|
for n = 1, table.getn(positions) do
|
|
local position = positions[n]
|
|
local info = {}
|
|
info.text = immunityPositionLabels[position]
|
|
info.value = position
|
|
info.func = function() SetImmunityPosition(this.value) end
|
|
info.checked = (BNP:GetImmunityPosition() == position)
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.immunityPositionDropdown = immunityPositionDropdown
|
|
frame.SetImmunityPosition = SetImmunityPosition
|
|
|
|
local immunityPositionLabel = aurasPage:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
immunityPositionLabel:SetPoint("BOTTOMLEFT", immunityPositionDropdown, "TOPLEFT", 18, 5)
|
|
immunityPositionLabel:SetText("Immunity Position")
|
|
frame.immunityPositionLabel = immunityPositionLabel
|
|
|
|
local immunityIcon = CreateSlider(aurasPage, "Immunity Icon Size", 12, 32, 1, -368, 28, 150)
|
|
immunityIcon:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.immunityIconSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Immunity Icon Size: " .. value)
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.immunityIconSlider = immunityIcon
|
|
|
|
local immunityYOffset = CreateSlider(aurasPage, "Immunity Y Offset", -50, 50, 1, -368, 220, 150)
|
|
immunityYOffset:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = RoundSignedInteger(this:GetValue())
|
|
BNP_DB.immunityYOffset = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Immunity Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
if BNP.RefreshAllImmunityLayouts then BNP:RefreshAllImmunityLayouts() end
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.immunityYOffsetSlider = immunityYOffset
|
|
|
|
-- TOTEMS TAB -------------------------------------------------------------
|
|
local totemsPage = frame.pages.totems
|
|
CreateSection(totemsPage, "Totem Indicators", -4)
|
|
|
|
local totemIndicators = CreateCheck(totemsPage, "Enable Totem Icons", -42, function()
|
|
BNP_DB.totemIndicators = this:GetChecked() and true or false
|
|
if BNP.RefreshTotemIndicators then BNP:RefreshTotemIndicators() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
end)
|
|
frame.totemIndicatorsCheck = totemIndicators
|
|
|
|
local totemIcon = CreateSlider(totemsPage, "Totem Icon Size", 16, 36, 1, -92)
|
|
totemIcon:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.totemIconSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Totem Icon Size: " .. value)
|
|
if BNP.RefreshTotemIndicators then BNP:RefreshTotemIndicators() end
|
|
end)
|
|
frame.totemIconSlider = totemIcon
|
|
|
|
local totemNote = totemsPage:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
totemNote:SetPoint("TOPLEFT", totemsPage, "TOPLEFT", 28, -150)
|
|
totemNote:SetWidth(340)
|
|
totemNote:SetJustifyH("LEFT")
|
|
totemNote:SetText("Replaces all visible shaman totem nameplates with compact icons. There are no individual totem filters.")
|
|
|
|
|
|
-- CASTBAR TAB ------------------------------------------------------------
|
|
local castbarPage = frame.pages.castbar
|
|
CreateSection(castbarPage, "Castbar", -4)
|
|
|
|
local castbars = CreateCheck(castbarPage, "Castbars", -42, function()
|
|
local enabled = this:GetChecked() and true or false
|
|
if BNP.SetCastbarsEnabled then BNP:SetCastbarsEnabled(enabled) else BNP_DB.castbars = enabled end
|
|
end)
|
|
frame.castbarsCheck = castbars
|
|
|
|
local castbarTest = CreateCheck(castbarPage, "Test Castbars", -42, function()
|
|
if BNP.SetCastbarTestMode then BNP:SetCastbarTestMode(this:GetChecked() and true or false) end
|
|
end, 164)
|
|
castbarTest:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText("Test Castbars", 1, 0.82, 0)
|
|
GameTooltip:AddLine("Shows a looping simulated castbar on every visible nameplate.", 1, 1, 1, true)
|
|
GameTooltip:AddLine("Use it to adjust height and spacing live. The test mode is not saved.", 0.8, 0.8, 0.8, true)
|
|
GameTooltip:Show()
|
|
end)
|
|
castbarTest:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
frame.castbarTestCheck = castbarTest
|
|
|
|
local castbarHeight = CreateSlider(castbarPage, "Castbar Height", 4, 14, 1, -94)
|
|
castbarHeight:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.castbarHeight = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Castbar Height: " .. value)
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() elseif BNP.RefreshCastbarHeights then BNP:RefreshCastbarHeights() end
|
|
end)
|
|
frame.castbarHeightSlider = castbarHeight
|
|
|
|
local castbarSpacing = CreateSlider(castbarPage, "Castbar Spacing", 0, 10, 1, -148)
|
|
castbarSpacing:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.castbarSpacing = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Castbar Spacing: " .. value .. " px")
|
|
if BNP.RefreshCastbarLayout then BNP:RefreshCastbarLayout() end
|
|
end)
|
|
frame.castbarSpacingSlider = castbarSpacing
|
|
|
|
-- TARGET TAB -------------------------------------------------------------
|
|
local targetPage = frame.pages.target
|
|
CreateSection(targetPage, "Target", -4)
|
|
|
|
local targetFocus = CreateCheck(targetPage, "Target Glow", -42, function()
|
|
BNP_DB.targetFocus = this:GetChecked() and true or false
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
end)
|
|
frame.targetFocusCheck = targetFocus
|
|
|
|
local glowColorLabel = targetPage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
glowColorLabel:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 28, -88)
|
|
glowColorLabel:SetText("Target Color")
|
|
frame.glowColorLabel = glowColorLabel
|
|
|
|
local glowColorDropdown = CreateFrame("Frame", "BNPTargetGlowColorDropdown", targetPage, "UIDropDownMenuTemplate")
|
|
glowColorDropdown:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 10, -100)
|
|
UIDropDownMenu_SetWidth(150, glowColorDropdown)
|
|
|
|
local glowColorLabels = {
|
|
white = "White",
|
|
gold = "Gold",
|
|
blue = "Blue",
|
|
green = "Green",
|
|
red = "Red",
|
|
purple = "Purple",
|
|
}
|
|
|
|
local function SetTargetGlowColor(color)
|
|
if not glowColorLabels[color] then color = "white" end
|
|
BNP_DB.targetGlowColor = color
|
|
UIDropDownMenu_SetSelectedValue(glowColorDropdown, color)
|
|
UIDropDownMenu_SetText(glowColorLabels[color], glowColorDropdown)
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(glowColorDropdown, function()
|
|
local colors = { "white", "gold", "blue", "green", "red", "purple" }
|
|
local n
|
|
for n = 1, table.getn(colors) do
|
|
local color = colors[n]
|
|
local info = {}
|
|
info.text = glowColorLabels[color]
|
|
info.value = color
|
|
info.func = function() SetTargetGlowColor(this.value) end
|
|
info.checked = ((BNP_DB and BNP_DB.targetGlowColor) or "white") == color
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.glowColorDropdown = glowColorDropdown
|
|
frame.SetTargetGlowColor = SetTargetGlowColor
|
|
|
|
local glowSize = CreateSlider(targetPage, "Target Glow Size", 0, 20, 1, -168)
|
|
glowSize:SetWidth(145)
|
|
glowSize:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.targetGlowSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Target Glow Size: +" .. value .. " px")
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end)
|
|
frame.targetGlowSizeSlider = glowSize
|
|
|
|
local glowOpacity = CreateSlider(targetPage, "Target Glow Opacity", 20, 100, 5, -222)
|
|
glowOpacity:SetWidth(145)
|
|
glowOpacity:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.targetGlowOpacity = value / 100
|
|
getglobal(this:GetName() .. "Text"):SetText("Target Glow Opacity: " .. value .. "%")
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end)
|
|
frame.targetGlowOpacitySlider = glowOpacity
|
|
|
|
local targetArrows = CreateCheck(targetPage, "Target Arrows", -42, function()
|
|
BNP_DB.targetArrows = this:GetChecked() and true or false
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
end)
|
|
targetArrows:ClearAllPoints()
|
|
targetArrows:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 204, -42)
|
|
frame.targetArrowsCheck = targetArrows
|
|
|
|
local arrowColorLabel = targetPage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
arrowColorLabel:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 210, -88)
|
|
arrowColorLabel:SetText("Arrow Color")
|
|
frame.arrowColorLabel = arrowColorLabel
|
|
|
|
local arrowColorDropdown = CreateFrame("Frame", "BNPTargetArrowColorDropdown", targetPage, "UIDropDownMenuTemplate")
|
|
arrowColorDropdown:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 192, -100)
|
|
UIDropDownMenu_SetWidth(140, arrowColorDropdown)
|
|
|
|
local arrowColorLabels = {
|
|
match = "Match Target Color",
|
|
white = "White",
|
|
gold = "Gold",
|
|
blue = "Blue",
|
|
green = "Green",
|
|
red = "Red",
|
|
purple = "Purple",
|
|
}
|
|
|
|
local function SetTargetArrowColor(color)
|
|
if not arrowColorLabels[color] then color = "match" end
|
|
BNP_DB.targetArrowColor = color
|
|
UIDropDownMenu_SetSelectedValue(arrowColorDropdown, color)
|
|
UIDropDownMenu_SetText(arrowColorLabels[color], arrowColorDropdown)
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(arrowColorDropdown, function()
|
|
local colors = { "match", "white", "gold", "blue", "green", "red", "purple" }
|
|
local n
|
|
for n = 1, table.getn(colors) do
|
|
local color = colors[n]
|
|
local info = {}
|
|
info.text = arrowColorLabels[color]
|
|
info.value = color
|
|
info.func = function() SetTargetArrowColor(this.value) end
|
|
info.checked = ((BNP_DB and BNP_DB.targetArrowColor) or "match") == color
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.arrowColorDropdown = arrowColorDropdown
|
|
frame.SetTargetArrowColor = SetTargetArrowColor
|
|
|
|
local arrowStyleLabel = targetPage:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
arrowStyleLabel:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 210, -142)
|
|
arrowStyleLabel:SetText("Arrow Style")
|
|
frame.arrowStyleLabel = arrowStyleLabel
|
|
|
|
local arrowStyleDropdown = CreateFrame("Frame", "BNPTargetArrowStyleDropdown", targetPage, "UIDropDownMenuTemplate")
|
|
arrowStyleDropdown:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 192, -154)
|
|
UIDropDownMenu_SetWidth(140, arrowStyleDropdown)
|
|
|
|
local arrowStyleLabels = {
|
|
chevron = "Chevron",
|
|
triangle = "Triangle",
|
|
slim_triangle = "Slim Triangle",
|
|
double_chevron = "Double Chevron",
|
|
diamond_tip = "Diamond Tip",
|
|
}
|
|
|
|
local function SetTargetArrowStyle(style)
|
|
if not arrowStyleLabels[style] then style = "chevron" end
|
|
BNP_DB.targetArrowStyle = style
|
|
UIDropDownMenu_SetSelectedValue(arrowStyleDropdown, style)
|
|
UIDropDownMenu_SetText(arrowStyleLabels[style], arrowStyleDropdown)
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end
|
|
|
|
UIDropDownMenu_Initialize(arrowStyleDropdown, function()
|
|
local styles = { "chevron", "triangle", "slim_triangle", "double_chevron", "diamond_tip" }
|
|
local n
|
|
for n = 1, table.getn(styles) do
|
|
local style = styles[n]
|
|
local info = {}
|
|
info.text = arrowStyleLabels[style]
|
|
info.value = style
|
|
info.func = function() SetTargetArrowStyle(this.value) end
|
|
info.checked = ((BNP_DB and BNP_DB.targetArrowStyle) or "chevron") == style
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end)
|
|
frame.arrowStyleDropdown = arrowStyleDropdown
|
|
frame.SetTargetArrowStyle = SetTargetArrowStyle
|
|
|
|
local arrowSize = CreateSlider(targetPage, "Target Arrow Size", 10, 24, 1, -222)
|
|
arrowSize:ClearAllPoints()
|
|
arrowSize:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 210, -222)
|
|
arrowSize:SetWidth(145)
|
|
arrowSize:SetScript("OnValueChanged", function()
|
|
if not BNP_DB then return end
|
|
local value = math.floor(this:GetValue() + 0.5)
|
|
BNP_DB.targetArrowSize = value
|
|
getglobal(this:GetName() .. "Text"):SetText("Target Arrow Size: " .. value)
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end)
|
|
frame.targetArrowSizeSlider = arrowSize
|
|
|
|
local thickArrows = CreateCheck(targetPage, "Thick Arrows", -276, function()
|
|
BNP_DB.targetArrowThick = this:GetChecked() and true or false
|
|
if BNP.RefreshTargetFocus then BNP:RefreshTargetFocus() end
|
|
end)
|
|
thickArrows:ClearAllPoints()
|
|
thickArrows:SetPoint("TOPLEFT", targetPage, "TOPLEFT", 204, -276)
|
|
frame.targetArrowThickCheck = thickArrows
|
|
|
|
-- TOOLS TAB --------------------------------------------------------------
|
|
local toolsPage = frame.pages.tools
|
|
CreateSection(toolsPage, "Tools", -4)
|
|
|
|
local auraRecorder = CreateFrame("Button", nil, toolsPage, "UIPanelButtonTemplate")
|
|
auraRecorder:SetPoint("TOPLEFT", toolsPage, "TOPLEFT", 28, -48)
|
|
auraRecorder:SetWidth(254)
|
|
auraRecorder:SetHeight(24)
|
|
auraRecorder:SetText("Missing Spell / Aura...")
|
|
auraRecorder:SetScript("OnClick", function() BNP:OpenAuraRecorder() end)
|
|
auraRecorder:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText("Missing Spell / Aura Recorder", 1, 0.82, 0)
|
|
GameTooltip:AddLine("Records target aura IDs, SuperWoW events and refresh signals in one copyable report.", 1, 1, 1, true)
|
|
GameTooltip:Show()
|
|
end)
|
|
auraRecorder:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
frame.auraRecorderButton = auraRecorder
|
|
|
|
local note = toolsPage:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
note:SetPoint("TOPLEFT", toolsPage, "TOPLEFT", 28, -88)
|
|
note:SetWidth(330)
|
|
note:SetJustifyH("LEFT")
|
|
note:SetText("Diagnostic tools for testing missing spells and aura refresh behavior.")
|
|
|
|
function frame:UpdateDependentControls()
|
|
local ccEnabled = BNP:AreCrowdControlEnabled()
|
|
local debuffsEnabled = BNP:AreDebuffsEnabled()
|
|
local debuffPosition = BNP.GetDebuffPosition and BNP:GetDebuffPosition() or "top"
|
|
local ccPosition = BNP.GetCCPosition and BNP:GetCCPosition() or debuffPosition
|
|
local separateRowAvailable = ccEnabled and debuffsEnabled and (debuffPosition == "top" or debuffPosition == "top_left" or debuffPosition == "top_right") and ccPosition == "top"
|
|
|
|
SetCheckEnabled(self.separateCCRowCheck, separateRowAvailable)
|
|
if self.separateCCRowCheck then
|
|
self.separateCCRowCheck:SetChecked(separateRowAvailable and BNP:IsSeparateCCRowEnabled() or false)
|
|
end
|
|
SetCheckEnabled(self.showOtherCCsCheck, ccEnabled)
|
|
if self.debuffYOffsetSlider then
|
|
self.debuffYOffsetSlider:SetAlpha(debuffsEnabled and 1.0 or 0.45)
|
|
if self.debuffYOffsetSlider.EnableMouse then self.debuffYOffsetSlider:EnableMouse(debuffsEnabled) end
|
|
end
|
|
if self.ccYOffsetSlider then
|
|
self.ccYOffsetSlider:SetAlpha(ccEnabled and 1.0 or 0.45)
|
|
if self.ccYOffsetSlider.EnableMouse then self.ccYOffsetSlider:EnableMouse(ccEnabled) end
|
|
end
|
|
|
|
local comboEnabled = BNP.AreComboPointsEnabled and BNP:AreComboPointsEnabled() or false
|
|
if self.comboPointsYOffsetSlider then
|
|
self.comboPointsYOffsetSlider:SetAlpha(comboEnabled and 1.0 or 0.45)
|
|
if self.comboPointsYOffsetSlider.EnableMouse then self.comboPointsYOffsetSlider:EnableMouse(comboEnabled) end
|
|
end
|
|
|
|
local immunitiesEnabled = BNP.ArePvPImmunitiesEnabled and BNP:ArePvPImmunitiesEnabled() or false
|
|
if self.immunityIconSlider then
|
|
self.immunityIconSlider:SetAlpha(immunitiesEnabled and 1.0 or 0.45)
|
|
if self.immunityIconSlider.EnableMouse then self.immunityIconSlider:EnableMouse(immunitiesEnabled) end
|
|
end
|
|
if self.immunityYOffsetSlider then
|
|
self.immunityYOffsetSlider:SetAlpha(immunitiesEnabled and 1.0 or 0.45)
|
|
if self.immunityYOffsetSlider.EnableMouse then self.immunityYOffsetSlider:EnableMouse(immunitiesEnabled) end
|
|
end
|
|
if self.immunityPositionLabel then
|
|
self.immunityPositionLabel:SetTextColor(immunitiesEnabled and 1 or 0.5, immunitiesEnabled and 1 or 0.5, immunitiesEnabled and 1 or 0.5)
|
|
end
|
|
if self.immunityPositionDropdown then
|
|
self.immunityPositionDropdown:SetAlpha(immunitiesEnabled and 1.0 or 0.45)
|
|
if immunitiesEnabled then
|
|
if UIDropDownMenu_EnableDropDown then UIDropDownMenu_EnableDropDown(self.immunityPositionDropdown) end
|
|
else
|
|
if UIDropDownMenu_DisableDropDown then UIDropDownMenu_DisableDropDown(self.immunityPositionDropdown) end
|
|
end
|
|
end
|
|
|
|
local totemsEnabled = BNP.AreTotemIndicatorsEnabled and BNP:AreTotemIndicatorsEnabled() or false
|
|
if self.totemIconSlider then
|
|
self.totemIconSlider:SetAlpha(totemsEnabled and 1.0 or 0.45)
|
|
if self.totemIconSlider.EnableMouse then self.totemIconSlider:EnableMouse(totemsEnabled) end
|
|
end
|
|
|
|
local glowEnabled = BNP:IsTargetFocusEnabled()
|
|
local arrowsEnabled = BNP.AreTargetArrowsEnabled and BNP:AreTargetArrowsEnabled() or false
|
|
local targetColorEnabled = glowEnabled or arrowsEnabled
|
|
if self.glowColorLabel then
|
|
self.glowColorLabel:SetTextColor(targetColorEnabled and 1 or 0.5, targetColorEnabled and 0.82 or 0.5, targetColorEnabled and 0 or 0.5)
|
|
end
|
|
if self.glowColorDropdown then
|
|
self.glowColorDropdown:SetAlpha(targetColorEnabled and 1.0 or 0.45)
|
|
if targetColorEnabled then
|
|
if UIDropDownMenu_EnableDropDown then UIDropDownMenu_EnableDropDown(self.glowColorDropdown) end
|
|
else
|
|
if UIDropDownMenu_DisableDropDown then UIDropDownMenu_DisableDropDown(self.glowColorDropdown) end
|
|
end
|
|
end
|
|
if self.targetGlowSizeSlider then
|
|
self.targetGlowSizeSlider:SetAlpha(glowEnabled and 1.0 or 0.45)
|
|
if self.targetGlowSizeSlider.EnableMouse then self.targetGlowSizeSlider:EnableMouse(glowEnabled) end
|
|
end
|
|
if self.targetGlowOpacitySlider then
|
|
self.targetGlowOpacitySlider:SetAlpha(glowEnabled and 1.0 or 0.45)
|
|
if self.targetGlowOpacitySlider.EnableMouse then self.targetGlowOpacitySlider:EnableMouse(glowEnabled) end
|
|
end
|
|
if self.arrowColorLabel then
|
|
self.arrowColorLabel:SetTextColor(arrowsEnabled and 1 or 0.5, arrowsEnabled and 0.82 or 0.5, arrowsEnabled and 0 or 0.5)
|
|
end
|
|
if self.arrowColorDropdown then
|
|
self.arrowColorDropdown:SetAlpha(arrowsEnabled and 1.0 or 0.45)
|
|
if arrowsEnabled then
|
|
if UIDropDownMenu_EnableDropDown then UIDropDownMenu_EnableDropDown(self.arrowColorDropdown) end
|
|
else
|
|
if UIDropDownMenu_DisableDropDown then UIDropDownMenu_DisableDropDown(self.arrowColorDropdown) end
|
|
end
|
|
end
|
|
if self.arrowStyleLabel then
|
|
self.arrowStyleLabel:SetTextColor(arrowsEnabled and 1 or 0.5, arrowsEnabled and 0.82 or 0.5, arrowsEnabled and 0 or 0.5)
|
|
end
|
|
if self.arrowStyleDropdown then
|
|
self.arrowStyleDropdown:SetAlpha(arrowsEnabled and 1.0 or 0.45)
|
|
if arrowsEnabled then
|
|
if UIDropDownMenu_EnableDropDown then UIDropDownMenu_EnableDropDown(self.arrowStyleDropdown) end
|
|
else
|
|
if UIDropDownMenu_DisableDropDown then UIDropDownMenu_DisableDropDown(self.arrowStyleDropdown) end
|
|
end
|
|
end
|
|
if self.targetArrowSizeSlider then
|
|
self.targetArrowSizeSlider:SetAlpha(arrowsEnabled and 1.0 or 0.45)
|
|
if self.targetArrowSizeSlider.EnableMouse then self.targetArrowSizeSlider:EnableMouse(arrowsEnabled) end
|
|
end
|
|
SetCheckEnabled(self.targetArrowThickCheck, arrowsEnabled)
|
|
end
|
|
|
|
frame:ShowTab("nameplates")
|
|
self.optionsFrame = frame
|
|
end
|
|
|
|
function BNP:SyncOptions()
|
|
self:CreateOptions()
|
|
local frame = self.optionsFrame
|
|
frame.scaleSlider:SetValue(self:GetNameplateScale())
|
|
if frame.yOffsetSlider then
|
|
local yOffset = self:GetNameplateYOffset()
|
|
frame.yOffsetSlider:SetValue(yOffset)
|
|
getglobal(frame.yOffsetSlider:GetName() .. "Text"):SetText("Nameplate Y Offset: +" .. yOffset)
|
|
end
|
|
if frame.nameFontSizeSlider or frame.nameFontYOffsetSlider then
|
|
frame.BNPSyncingNameControls = true
|
|
if frame.nameFontSizeSlider then
|
|
local value = self:GetNameFontSize()
|
|
frame.nameFontSizeSlider:SetValue(value)
|
|
getglobal(frame.nameFontSizeSlider:GetName() .. "Text"):SetText("Name Font Size: " .. value)
|
|
end
|
|
if frame.nameFontYOffsetSlider then
|
|
local value = self:GetNameFontYOffset()
|
|
frame.nameFontYOffsetSlider:SetValue(value)
|
|
getglobal(frame.nameFontYOffsetSlider:GetName() .. "Text"):SetText("Name Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
end
|
|
frame.BNPSyncingNameControls = nil
|
|
end
|
|
if frame.comboPointsYOffsetSlider then
|
|
local value = self:GetComboPointsYOffset()
|
|
frame.comboPointsYOffsetSlider:SetValue(value)
|
|
getglobal(frame.comboPointsYOffsetSlider:GetName() .. "Text"):SetText("Combo Point Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
end
|
|
if frame.debuffYOffsetSlider then
|
|
local value = self:GetDebuffYOffset()
|
|
frame.debuffYOffsetSlider:SetValue(value)
|
|
getglobal(frame.debuffYOffsetSlider:GetName() .. "Text"):SetText("Debuff Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
end
|
|
if frame.ccYOffsetSlider then
|
|
local value = self:GetCCYOffset()
|
|
frame.ccYOffsetSlider:SetValue(value)
|
|
getglobal(frame.ccYOffsetSlider:GetName() .. "Text"):SetText("CC Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
end
|
|
if frame.immunityYOffsetSlider then
|
|
local value = self:GetImmunityYOffset()
|
|
frame.immunityYOffsetSlider:SetValue(value)
|
|
getglobal(frame.immunityYOffsetSlider:GetName() .. "Text"):SetText("Immunity Y Offset: " .. (value > 0 and "+" or "") .. value)
|
|
end
|
|
if frame.nonTargetAlphaSlider then
|
|
local alphaPercent = math.floor((self:GetNonTargetAlpha() * 100) + 0.5)
|
|
frame.nonTargetAlphaSlider:SetValue(alphaPercent)
|
|
getglobal(frame.nonTargetAlphaSlider:GetName() .. "Text"):SetText("Non-Target Alpha: " .. alphaPercent .. "%")
|
|
end
|
|
frame.iconSlider:SetValue(self:GetIconSize())
|
|
if frame.ccIconSlider then
|
|
local ccSize = self:GetCCIconSize()
|
|
frame.ccIconSlider:SetValue(ccSize)
|
|
getglobal(frame.ccIconSlider:GetName() .. "Text"):SetText("CC Icon Size: " .. ccSize)
|
|
end
|
|
if frame.immunityIconSlider then
|
|
local immunitySize = self:GetImmunityIconSize()
|
|
frame.immunityIconSlider:SetValue(immunitySize)
|
|
getglobal(frame.immunityIconSlider:GetName() .. "Text"):SetText("Immunity Icon Size: " .. immunitySize)
|
|
end
|
|
if frame.totemIconSlider then
|
|
local totemSize = self:GetTotemIconSize()
|
|
frame.totemIconSlider:SetValue(totemSize)
|
|
getglobal(frame.totemIconSlider:GetName() .. "Text"):SetText("Totem Icon Size: " .. totemSize)
|
|
end
|
|
frame.castbarHeightSlider:SetValue(self:GetCastbarHeight())
|
|
if frame.castbarSpacingSlider then
|
|
local spacing = self:GetCastbarSpacing()
|
|
frame.castbarSpacingSlider:SetValue(spacing)
|
|
getglobal(frame.castbarSpacingSlider:GetName() .. "Text"):SetText("Castbar Spacing: " .. spacing .. " px")
|
|
end
|
|
frame.classColorsCheck:SetChecked(self:AreClassColorsEnabled())
|
|
if frame.hidePlayerNamesCheck then frame.hidePlayerNamesCheck:SetChecked(self:HidePlayerNamesEnabled()) end
|
|
if frame.hideNPCNamesCheck then frame.hideNPCNamesCheck:SetChecked(self:HideNPCNamesEnabled()) end
|
|
if frame.debuffsCheck then frame.debuffsCheck:SetChecked(self:AreDebuffsEnabled()) end
|
|
if frame.debuffPositionDropdown then
|
|
local position = self:GetDebuffPosition()
|
|
local labels = { top = "Top Mid", top_left = "Top Left", top_right = "Top Right", left = "Left", right = "Right", bottom_mid = "Bottom Mid", bottom_left = "Bottom Left", bottom_right = "Bottom Right" }
|
|
UIDropDownMenu_SetSelectedValue(frame.debuffPositionDropdown, position)
|
|
UIDropDownMenu_SetText(labels[position] or "Top Mid", frame.debuffPositionDropdown)
|
|
end
|
|
if frame.ccPositionDropdown then
|
|
local position = self:GetCCPosition()
|
|
local labels = { top = "Top", left = "Left", right = "Right" }
|
|
UIDropDownMenu_SetSelectedValue(frame.ccPositionDropdown, position)
|
|
UIDropDownMenu_SetText(labels[position] or "Top", frame.ccPositionDropdown)
|
|
end
|
|
if frame.crowdControlCheck then frame.crowdControlCheck:SetChecked(self:AreCrowdControlEnabled()) end
|
|
if frame.separateCCRowCheck then frame.separateCCRowCheck:SetChecked(self:IsSeparateCCRowEnabled()) end
|
|
if frame.showOtherCCsCheck then frame.showOtherCCsCheck:SetChecked(self:ShowOtherPlayersCCs()) end
|
|
if frame.pvpImmunitiesCheck then frame.pvpImmunitiesCheck:SetChecked(self:ArePvPImmunitiesEnabled()) end
|
|
if frame.immunityPositionDropdown then
|
|
local position = self:GetImmunityPosition()
|
|
local labels = { top = "Top", left = "Left", right = "Right" }
|
|
UIDropDownMenu_SetSelectedValue(frame.immunityPositionDropdown, position)
|
|
UIDropDownMenu_SetText(labels[position] or "Top", frame.immunityPositionDropdown)
|
|
end
|
|
if frame.totemIndicatorsCheck then frame.totemIndicatorsCheck:SetChecked(self:AreTotemIndicatorsEnabled()) end
|
|
frame.castbarsCheck:SetChecked(self:AreCastbarsEnabled())
|
|
if frame.castbarTestCheck then
|
|
frame.castbarTestCheck:SetChecked(self.IsCastbarTestMode and self:IsCastbarTestMode() or false)
|
|
end
|
|
frame.tankCheck:SetChecked(self:IsTankModeEnabled())
|
|
if frame.comboPointsCheck and comboOptionsClass then
|
|
frame.comboPointsCheck:SetChecked(self:AreComboPointsEnabled())
|
|
end
|
|
if frame.healthTextDropdown then
|
|
local mode = self:GetHealthTextMode()
|
|
UIDropDownMenu_SetSelectedValue(frame.healthTextDropdown, mode)
|
|
local labels = { off = "Off", percent = "Percent", hp = "HP", both = "HP + Percent" }
|
|
UIDropDownMenu_SetText(labels[mode] or "Off", frame.healthTextDropdown)
|
|
end
|
|
if frame.healthTextFontSizeSlider then
|
|
frame.BNPSyncingHealthTextControls = true
|
|
local size = self:GetHealthTextFontSize()
|
|
frame.healthTextFontSizeSlider:SetValue(size)
|
|
getglobal(frame.healthTextFontSizeSlider:GetName() .. "Text"):SetText("Health Font Size: " .. size)
|
|
frame.BNPSyncingHealthTextControls = nil
|
|
end
|
|
if frame.healthTextOutlineDropdown then
|
|
local outline = self:GetHealthTextOutline()
|
|
local labels = { none = "None", outline = "Outline", thick = "Thick Outline" }
|
|
UIDropDownMenu_SetSelectedValue(frame.healthTextOutlineDropdown, outline)
|
|
UIDropDownMenu_SetText(labels[outline] or "Outline", frame.healthTextOutlineDropdown)
|
|
end
|
|
frame.targetFocusCheck:SetChecked(self:IsTargetFocusEnabled())
|
|
if frame.targetArrowsCheck then
|
|
frame.targetArrowsCheck:SetChecked(self.AreTargetArrowsEnabled and self:AreTargetArrowsEnabled() or false)
|
|
end
|
|
if frame.arrowColorDropdown then
|
|
local _, _, _, color = self:GetTargetArrowColor()
|
|
local labels = {
|
|
match = "Match Target Color",
|
|
white = "White",
|
|
gold = "Gold",
|
|
blue = "Blue",
|
|
green = "Green",
|
|
red = "Red",
|
|
purple = "Purple",
|
|
}
|
|
UIDropDownMenu_SetSelectedValue(frame.arrowColorDropdown, color or "match")
|
|
UIDropDownMenu_SetText(labels[color] or "Match Target Color", frame.arrowColorDropdown)
|
|
end
|
|
if frame.arrowStyleDropdown then
|
|
local style = self:GetTargetArrowStyle()
|
|
local labels = {
|
|
chevron = "Chevron",
|
|
triangle = "Triangle",
|
|
slim_triangle = "Slim Triangle",
|
|
double_chevron = "Double Chevron",
|
|
diamond_tip = "Diamond Tip",
|
|
}
|
|
UIDropDownMenu_SetSelectedValue(frame.arrowStyleDropdown, style)
|
|
UIDropDownMenu_SetText(labels[style] or "Chevron", frame.arrowStyleDropdown)
|
|
end
|
|
if frame.targetArrowSizeSlider then
|
|
local arrowSize = self:GetTargetArrowSize()
|
|
frame.targetArrowSizeSlider:SetValue(arrowSize)
|
|
getglobal(frame.targetArrowSizeSlider:GetName() .. "Text"):SetText("Target Arrow Size: " .. arrowSize)
|
|
end
|
|
if frame.targetArrowThickCheck then
|
|
frame.targetArrowThickCheck:SetChecked(self.AreTargetArrowsThick and self:AreTargetArrowsThick() or false)
|
|
end
|
|
|
|
if frame.glowColorDropdown then
|
|
local _, _, _, color = self:GetTargetGlowColor()
|
|
local labels = {
|
|
white = "White",
|
|
gold = "Gold",
|
|
blue = "Blue",
|
|
green = "Green",
|
|
red = "Red",
|
|
purple = "Purple",
|
|
}
|
|
UIDropDownMenu_SetSelectedValue(frame.glowColorDropdown, color or "white")
|
|
UIDropDownMenu_SetText(labels[color] or "White", frame.glowColorDropdown)
|
|
end
|
|
if frame.targetGlowSizeSlider then
|
|
local glowSize = self:GetTargetGlowSize()
|
|
frame.targetGlowSizeSlider:SetValue(glowSize)
|
|
getglobal(frame.targetGlowSizeSlider:GetName() .. "Text"):SetText("Target Glow Size: +" .. glowSize .. " px")
|
|
end
|
|
if frame.targetGlowOpacitySlider then
|
|
local opacityPercent = math.floor((self:GetTargetGlowOpacity() * 100) + 0.5)
|
|
frame.targetGlowOpacitySlider:SetValue(opacityPercent)
|
|
getglobal(frame.targetGlowOpacitySlider:GetName() .. "Text"):SetText("Target Glow Opacity: " .. opacityPercent .. "%")
|
|
end
|
|
|
|
if frame.UpdateDependentControls then frame:UpdateDependentControls() end
|
|
frame.versionText:SetText("Version " .. tostring(self.version or "?"))
|
|
end
|
|
|
|
function BNP:ToggleOptions()
|
|
self:SyncOptions()
|
|
if self.optionsFrame:IsShown() then
|
|
self.optionsFrame:Hide()
|
|
else
|
|
self.optionsFrame:Show()
|
|
end
|
|
end
|
|
|
|
function BNP:CreateMinimapButton()
|
|
if self.minimapButton then return end
|
|
|
|
BNP_DB = BNP_DB or {}
|
|
if BNP_DB.minimapAngle == nil then BNP_DB.minimapAngle = 225 end
|
|
|
|
local button = CreateFrame("Button", "BNPMinimapButton", Minimap)
|
|
button:SetWidth(31)
|
|
button:SetHeight(31)
|
|
button:SetFrameStrata("MEDIUM")
|
|
button:SetFrameLevel((Minimap:GetFrameLevel() or 1) + 8)
|
|
button:RegisterForClicks("LeftButtonUp")
|
|
button:RegisterForDrag("LeftButton")
|
|
button:EnableMouse(true)
|
|
button:SetMovable(true)
|
|
|
|
-- Classic round minimap-button background.
|
|
local bg = button:CreateTexture(nil, "BACKGROUND")
|
|
bg:SetTexture("Interface\\Minimap\\UI-Minimap-Background")
|
|
bg:SetWidth(22)
|
|
bg:SetHeight(22)
|
|
bg:SetPoint("CENTER", button, "CENTER", 0, 0)
|
|
button.bg = bg
|
|
|
|
-- Addon identity: simple BN+ lettering instead of a spell/item icon.
|
|
-- Rendered directly by the client, so no external texture file is needed.
|
|
local iconBG = button:CreateTexture(nil, "ARTWORK")
|
|
iconBG:SetTexture(0.03, 0.03, 0.03, 1)
|
|
iconBG:SetWidth(20)
|
|
iconBG:SetHeight(20)
|
|
iconBG:SetPoint("CENTER", button, "CENTER", 0, 0)
|
|
button.iconBG = iconBG
|
|
|
|
local label = button:CreateFontString(nil, "OVERLAY")
|
|
label:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE")
|
|
label:SetPoint("CENTER", button, "CENTER", 0, 0)
|
|
label:SetText("BN+")
|
|
label:SetTextColor(0.20, 0.60, 1.00)
|
|
button.label = label
|
|
|
|
-- Standard Blizzard circular minimap border.
|
|
local border = button:CreateTexture(nil, "OVERLAY")
|
|
border:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
|
|
border:SetWidth(54)
|
|
border:SetHeight(54)
|
|
border:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0)
|
|
button.border = border
|
|
|
|
local highlight = button:CreateTexture(nil, "HIGHLIGHT")
|
|
highlight:SetTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
|
|
highlight:SetBlendMode("ADD")
|
|
highlight:SetAllPoints(button)
|
|
button.highlight = highlight
|
|
|
|
local function UpdatePosition()
|
|
local angle = tonumber(BNP_DB.minimapAngle) or 225
|
|
local radius = 78
|
|
local rad = math.rad(angle)
|
|
|
|
button:ClearAllPoints()
|
|
button:SetPoint(
|
|
"CENTER",
|
|
Minimap,
|
|
"CENTER",
|
|
math.cos(rad) * radius,
|
|
math.sin(rad) * radius
|
|
)
|
|
end
|
|
|
|
local function UpdateAngleFromCursor()
|
|
local mx, my = Minimap:GetCenter()
|
|
local scale = 1
|
|
if UIParent.GetEffectiveScale then
|
|
scale = UIParent:GetEffectiveScale() or 1
|
|
elseif UIParent.GetScale then
|
|
scale = UIParent:GetScale() or 1
|
|
end
|
|
local cx, cy = GetCursorPosition()
|
|
cx = cx / scale
|
|
cy = cy / scale
|
|
|
|
local dx = cx - mx
|
|
local dy = cy - my
|
|
|
|
local angle
|
|
if math.atan2 then
|
|
angle = math.deg(math.atan2(dy, dx))
|
|
else
|
|
if dx == 0 then
|
|
angle = dy >= 0 and 90 or -90
|
|
else
|
|
angle = math.deg(math.atan(dy / dx))
|
|
if dx < 0 then angle = angle + 180 end
|
|
end
|
|
end
|
|
BNP_DB.minimapAngle = angle
|
|
UpdatePosition()
|
|
end
|
|
|
|
button:SetScript("OnDragStart", function()
|
|
this:SetScript("OnUpdate", UpdateAngleFromCursor)
|
|
end)
|
|
|
|
button:SetScript("OnDragStop", function()
|
|
this:SetScript("OnUpdate", nil)
|
|
UpdateAngleFromCursor()
|
|
end)
|
|
|
|
button:SetScript("OnClick", function()
|
|
BNP:ToggleOptions()
|
|
end)
|
|
|
|
button:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
|
|
GameTooltip:SetText("Blizz Nameplates+")
|
|
GameTooltip:AddLine("Left-click: Open settings", 1, 1, 1)
|
|
GameTooltip:AddLine("Drag: Move minimap button", 0.8, 0.8, 0.8)
|
|
GameTooltip:Show()
|
|
end)
|
|
|
|
button:SetScript("OnLeave", function()
|
|
GameTooltip:Hide()
|
|
end)
|
|
|
|
UpdatePosition()
|
|
self.minimapButton = button
|
|
end
|