Code:
--[[
Name: RangeDisplay
Revision: $Revision: 332 $
Author(s): mitch0
Website: http://www.wowace.com/projects/range-display/
SVN: svn://svn.wowace.com/wow/range-display/mainline/trunk
Description: RangeDisplay displays the estimated range to the current target based on spell ranges and
other measurable ranges
License: Public Domain
]]
local AppName, RangeDisplay = ...
local OptionsAppName = AppName .. "_Options"
local VERSION = AppName .. "-v3.9.8"
--[===[@debug@
local VERSION = AppName .. "-r" .. ("$Revision: 332 $"):match("%d+")
--@end-debug@]===]
local rc = LibStub("LibRangeCheck-2.0")
local LSM = LibStub:GetLibrary("LibSharedMedia-3.0", true)
local LibDualSpec = LibStub("LibDualSpec-1.0", true)
local L = LibStub("AceLocale-3.0"):GetLocale(AppName)
-- internal vars
local uiScale = 1.0 -- just to be safe...
local _ -- throwaway
local mute = nil
-- cached stuff
local _G = _G
local UnitExists = _G.UnitExists
local UnitIsDeadOrGhost = _G.UnitIsDeadOrGhost
local UnitCanAttack = _G.UnitCanAttack
local UnitCanAssist = _G.UnitCanAssist
local UnitIsUnit = _G.UnitIsUnit
local GetCursorPosition = _G.GetCursorPosition
local UIParent = _G.UIParent
local PlaySoundFile = _G.PlaySoundFile
local ipairs = _G.ipairs
local pairs = _G.pairs
-- hard-coded config stuff
local UpdateDelay = .1 -- update frequency == 1/UpdateDelay
local DefaultBGTexture = "Blizzard Tooltip"
local DefaultBGFile = [[Interface\Tooltips\UI-Tooltip-Background]]
local DefaultEdgeTexture = "Blizzard Tooltip"
local DefaultEdgeFile = [[Interface\Tooltips\UI-Tooltip-Border]]
local DefaultFontName = "Friz Quadrata TT"
local DefaultFontPath = GameFontNormal:GetFont()
local DefaultFrameWidth = 112
local DefaultFrameHeight = 36
local FakeCursorImage = [[Interface\CURSOR\Point]]
local Icon = [[Interface\Icons\INV_Misc_Spyglass_02]]
local Sections = {
"crSection",
"srSection",
"mrSection",
"lrSection",
"defaultSection",
"oorSection",
}
-- all sounds are slightly edited samples from freesound.org
local Sounds = {
["DoubleSwoosh"] = [[Interface\AddOns\]] .. AppName .. [[\sounds\19312.ogg]],
["Goblet F Medium"] = [[Interface\AddOns\]] .. AppName .. [[\sounds\30600.ogg]],
["SwordUnsheathed"] = [[Interface\AddOns\]] .. AppName .. [[\sounds\74833.ogg]],
}
local DefaultSoundNames = {
["crSection"] = "SwordUnsheathed",
["srSection"] = "DoubleSwoosh",
["mrSection"] = "DoubleSwoosh",
["lrSection"] = "DoubleSwoosh",
["defaultSection"] = "DoubleSwoosh",
["oorSection"] = "Goblet F Medium",
}
---------------------------------
RangeDisplay = LibStub("AceAddon-3.0"):NewAddon(RangeDisplay, AppName, "AceEvent-3.0")
_G.RangeDisplay = RangeDisplay
RangeDisplay:SetDefaultModuleState(false)
RangeDisplay.version = VERSION
RangeDisplay.AppName = AppName
RangeDisplay.Sections = Sections
-- Default DB stuff
local function makeColor(r, g, b, a)
a = a or 1.0
return { ["r"] = r, ["g"] = g, ["b"] = b, ["a"] = a }
end
local Transparent = makeColor(0, 0, 0, 0)
local DefaultText = "%d - %d"
local defaults = {
profile = {
locked = false,
mute = false,
minimap = {},
units = {
["**"] = {
enabled = true,
point = "CENTER",
relPoint = "CENTER",
x = 0,
y = -100,
font = DefaultFontName,
fontSize = 24,
fontOutline = "",
strata = "HIGH",
enemyOnly = false,
warnEnemyOnly = true,
reverse = false,
rangeLimit = 100,
overLimitDisplay = false,
overLimitText = "%d +",
frameWidth = DefaultFrameWidth,
frameHeight = DefaultFrameHeight,
bgEnabled = false,
bgTexture = DefaultBGTexture,
bgBorderTexture = DefaultEdgeTexture,
bgTile = false,
bgTileSize = 32,
bgEdgeSize = 16,
bgColor = makeColor(0, 0, 0),
bgBorderColor = makeColor(0.8, 0.6, 0.0),
oorSection = {
enabled = true,
color = makeColor(0.9, 0.055, 0.075),
range = 40,
text = DefaultText,
warnSoundName = DefaultSoundNames["oorSection"],
},
defaultSection = {
enabled = true,
color = makeColor(1.0, 0.82, 0),
text = DefaultText,
warnSoundName = DefaultSoundNames["defaultSection"],
},
lrSection = {
enabled = false,
color = makeColor(1.0, 0.82, 0),
range = 35,
text = DefaultText,
warnSoundName = DefaultSoundNames["lrSection"],
},
mrSection = {
enabled = true,
color = makeColor(0.035, 0.865, 0.0),
range = 30,
text = DefaultText,
warnSoundName = DefaultSoundNames["mrSection"],
},
srSection = {
enabled = true,
color = makeColor(0.055, 0.875, 0.825),
range = 20,
text = DefaultText,
warnSoundName = DefaultSoundNames["srSection"],
},
crSection = {
enabled = true,
color = makeColor(0.9, 0.9, 0.9),
range = 5,
text = DefaultText,
warnSoundName = DefaultSoundNames["crSection"],
},
},
-- ["playertarget"] = {
-- crSection = {
-- warnSound = true,
-- },
-- },
["focus"] = {
x = -(DefaultFrameWidth + 10),
},
["pet"] = {
enabled = false,
x = (DefaultFrameWidth + 10),
},
["mouseover"] = {
enabled = true,
x = -12,
y = 40,
frameWidth = 70,
frameHeight = 26,
fontSize = 16,
mouseAnchor = true,
bg = {
bgAutoHide = true,
},
},
},
},
}
-- FIXME: profile data migration from pre 3.9.0 version, remove later
local function updateUdDb_3_9_0(db)
if db.maxRangeOnly then
db.reverse = true
end
if db.overLimitSuffix then
db.overLimitText = "%d" .. db.overLimitSuffix
end
for _, section in pairs(Sections) do
local sdb = db[section]
if sdb.useText then
if not sdb.text or sdb.text == DefaultText then
sdb.text = ""
end
elseif db.suffix then
if db.maxRangeOnly then
sdb.text = "%d" .. db.suffix
else
sdb.text = "%d - %d" .. db.suffix
end
elseif db.maxRangeOnly then
sdb.text = "%d"
end
sdb.useText = nil
end
db.maxRangeOnly = nil
db.overLimitSuffix = nil
db.suffix = nil
end
-- Per unit data
local function setDisplayColor_Text(ud, color)
ud.rangeFrameText:SetTextColor(color.r, color.g, color.b, color.a)
end
local function setDisplayColor_Backdrop(ud, color)
ud.bgFrame:SetBackdropColor(color.r, color.g, color.b, color.a)
end
local function checkTarget(ud)
local unit = ud.unit
if not UnitExists(unit) or UnitIsUnit(unit, "player") then
return nil
end
if UnitIsDeadOrGhost(unit) then
ud.useSound = false
return not ud.db.enemyOnly
end
if UnitCanAttack("player", unit) then
ud.useSound = not mute
return true
elseif UnitCanAssist("player", unit) then
ud.useSound = not mute and not ud.db.warnEnemyOnly
return not ud.db.enemyOnly
else
ud.useSound = false
return not ud.db.enemyOnly
end
end
local function targetChanged(ud)
if ud:checkTarget() then
ud.rangeFrame:Show()
ud.lastUpdate = UpdateDelay -- to force update in next onUpdate()
if not ud.db.targetChangeKeepsSound then
ud.lastSound = nil -- to force playing sound
ud.lastMinRange, ud.lastMaxRange = false, false -- to force update
end
else
ud:setDisplayColor(Transparent)
ud.rangeFrame:Hide()
end
end
local function profileChanged(ud, db)
updateUdDb_3_9_0(db) -- FIXME: migration from pre 3_9_0 version, remove later
ud.db = db
end
local function mediaUpdate(ud, event, mediaType, key)
if mediaType == 'font' then
if key == ud.db.font then
ud:applyFontSettings()
end
elseif mediaType == 'background' then
if key == ud.db.bgTexture then
ud:applyBGSettings()
end
elseif mediaType == 'border' then
if key == ud.db.bgBorderTexture then
ud:applyBGSettings()
end
elseif mediaType == 'sound' then
for _, section in pairs(Sections) do
if ud.db[section].warnSound and key == ud.db[section].warnSoundName then
ud.sounds[section] = LSM:Fetch("sound", ud.db[section].warnSoundName)
end
end
end
end
local function applyBGSettings(ud)
if not ud.db.bgEnabled then
ud.mainFrame:SetBackdrop(nil)
ud.rangeFrame:SetBackdrop(nil)
ud.bgFrame = nil
ud.setDisplayColor = setDisplayColor_Text
return
end
ud.bg = ud.bg or { insets = {} }
local bg = ud.bg
if LSM then
bg.bgFile = LSM:Fetch("background", ud.db.bgTexture, true)
if not bg.bgFile then
bg.bgFile = DefaultBGFile
LSM.RegisterCallback(ud, "LibSharedMedia_Registered", "mediaUpdate")
end
bg.edgeFile = LSM:Fetch("border", ud.db.bgBorderTexture, true)
if not bg.edgeFile then
bg.edgeFile = DefaultEdgeFile
LSM.RegisterCallback(ud, "LibSharedMedia_Registered", "mediaUpdate")
end
else
bg.bgFile = DefaultBGFile
bg.edgeFile = DefaultEdgeFile
end
bg.tile = ud.db.bgTile
bg.tileSize = ud.db.bgTileSize
bg.edgeSize = ud.db.bgEdgeSize
local inset = math.floor(ud.db.bgEdgeSize / 4)
bg.insets.left = inset
bg.insets.right = inset
bg.insets.top = inset
bg.insets.bottom = inset
if ud.db.bgAutoHide or ud.db.mouseAnchor then
ud.bgFrame = ud.rangeFrame
ud.mainFrame:SetBackdrop(nil)
else
ud.bgFrame = ud.mainFrame
ud.rangeFrame:SetBackdrop(nil)
end
ud.bgFrame:SetBackdrop(bg)
ud.bgFrame:SetBackdropBorderColor(ud.db.bgBorderColor.r, ud.db.bgBorderColor.g, ud.db.bgBorderColor.b,
ud.db.bgBorderColor.a)
if ud.db.bgUseSectionColors then
ud.setDisplayColor = setDisplayColor_Backdrop
setDisplayColor_Text(ud, ud.db.bgColor)
else
ud.setDisplayColor = setDisplayColor_Text
setDisplayColor_Backdrop(ud, ud.db.bgColor)
end
-- ud:setDisplayColor(ud.db.defaultSection.color)
end
local function applyFontSettings(ud)
local dbFontPath
if LSM then
dbFontPath = LSM:Fetch("font", ud.db.font, true)
if not dbFontPath then
dbFontPath = DefaultFontPath
LSM.RegisterCallback(ud, "LibSharedMedia_Registered", "mediaUpdate")
end
else
dbFontPath = DefaultFontPath
end
local fontPath, fontSize, fontOutline = ud.rangeFrameText:GetFont()
fontOutline = fontOutline or ""
if dbFontPath ~= fontPath or ud.db.fontSize ~= fontSize or ud.db.fontOutline ~= fontOutline then
ud.rangeFrameText:SetFont(dbFontPath, ud.db.fontSize, ud.db.fontOutline)
end
end
local function applySettings(ud, whatChanged)
if ud.db.enabled then
ud:enable()
ud.mainFrame:ClearAllPoints()
ud.mainFrame:SetPoint(ud.db.point, UIParent, ud.db.relPoint, ud.db.x, ud.db.y)
ud.mainFrame:SetWidth(ud.db.frameWidth)
ud.mainFrame:SetHeight(ud.db.frameHeight)
ud.mainFrame:SetFrameStrata(ud.db.strata)
ud:applyFontSettings()
ud:applyBGSettings()
if LSM then
for _, section in pairs(Sections) do
if ud.db[section].warnSound then
ud.sounds[section] = LSM:Fetch("sound", ud.db[section].warnSoundName)
if not ud.sounds[section] then
if DefaultSoundNames[section] then
ud.sounds[section] = Sounds[DefaultSoundNames[section]]
end
LSM.RegisterCallback(ud, "LibSharedMedia_Registered", "mediaUpdate")
end
else
ud.sounds[section] = nil
end
end
end
if whatChanged == 'enemyOnly' or whatChanged == 'warnEnemyOnly' or whatChanged == 'enabled' then
ud:targetChanged()
end
ud.lastMinRange, ud.lastMaxRange = false, false -- to force update
ud:update()
else
ud:disable()
end
end
local function createOverlay(ud)
local unit = ud.unit
ud.overlay = ud.mainFrame:CreateTexture("RangeDisplayOverlay_" .. unit, "OVERLAY")
ud.overlay:SetTexture(0, 0.42, 0, 0.42)
ud.overlay:SetAllPoints()
ud.overlayText = ud.mainFrame:CreateFontString("RangeDisplayOverlayText_" .. unit, "OVERLAY",
"GameFontNormal")
ud.overlayText:SetFont(DefaultFontPath, 10, "")
ud.overlayText:SetJustifyH("CENTER")
ud.overlayText:SetPoint("BOTTOM", ud.mainFrame, "BOTTOM", 0, 0)
ud.overlayText:SetText(L[unit])
end
local function update(ud)
local minRange, maxRange = rc:GetRange(ud.unit)
if minRange == ud.lastMinRange and maxRange == ud.lastMaxRange then return end
ud.lastMinRange, ud.lastMaxRange = minRange, maxRange
local fmt = ""
local section = nil
if minRange then
if minRange >= ud.db.rangeLimit then maxRange = nil end
if maxRange then
if ud.db.crSection.enabled and maxRange <= ud.db.crSection.range then
section = "crSection"
elseif ud.db.srSection.enabled and maxRange <= ud.db.srSection.range then
section = "srSection"
elseif ud.db.mrSection.enabled and maxRange <= ud.db.mrSection.range then
section = "mrSection"
elseif ud.db.lrSection.enabled and maxRange <= ud.db.lrSection.range then
section = "lrSection"
elseif ud.db.oorSection.enabled and minRange >= ud.db.oorSection.range then
section = "oorSection"
else
section = "defaultSection"
end
fmt = ud.db[section].text
elseif ud.db.overLimitDisplay then
if ud.db.oorSection.enabled and minRange >= ud.db.oorSection.range then
section = "oorSection"
else
section = "defaultSection"
end
fmt = ud.db.overLimitText
maxRange = minRange -- to handle ud.db.reverse
end
end
if ud.db.reverse then
ud.rangeFrameText:SetFormattedText(fmt, maxRange, minRange)
else
ud.rangeFrameText:SetFormattedText(fmt, minRange, maxRange)
end
if section then
ud:setDisplayColor(ud.db[section].color)
local sound = ud.sounds[section]
if sound and ud.useSound and sound ~= ud.lastSound then
PlaySoundFile(sound)
end
ud.lastSound = sound
else
ud:setDisplayColor(Transparent)
end
end
local function updateCheckValid(ud) -- needed for mouseover target
if not ud:checkTarget() then
ud.rangeFrame:Hide()
return
end
update(ud)
end
local function onUpdate(frame, elapsed)
local ud = frame.ud
ud.lastUpdate = ud.lastUpdate + elapsed
if ud.lastUpdate < UpdateDelay then return end
ud.lastUpdate = 0
ud:update()
end
local function onUpdateWithMousePos(frame, elapsed)
local ud = frame.ud
local x, y = GetCursorPosition()
ud.mainFrame:ClearAllPoints()
ud.mainFrame:SetPoint(ud.db.point, UIParent, "BOTTOMLEFT", (x / uiScale) + ud.db.x, (y / uiScale) +
ud.db.y)
ud.lastUpdate = ud.lastUpdate + elapsed
if ud.lastUpdate < UpdateDelay then return end
ud.lastUpdate = 0
ud:update()
end
local function updateUIScale()
uiScale = UIParent:GetEffectiveScale()
end
local function createFrame(ud)
local unit = ud.unit
ud.isMoving = false
ud.mainFrame = CreateFrame("Frame", "RangeDisplayMainFrame_" .. unit, UIParent)
ud.mainFrame:SetFrameStrata(ud.db.strata)
ud.mainFrame:EnableMouse(false)
ud.mainFrame:SetClampedToScreen()
ud.mainFrame:SetMovable(true)
ud.mainFrame:SetWidth(ud.db.frameWidth)
ud.mainFrame:SetHeight(ud.db.frameHeight)
ud.mainFrame:SetPoint(ud.db.point, UIParent, ud.db.relPoint, ud.db.x, ud.db.y)
ud.rangeFrame = CreateFrame("Frame", "RangeDisplayFrame_" .. unit, ud.mainFrame)
ud.rangeFrame:SetPoint("CENTER", ud.mainFrame, "CENTER", 0, 0)
ud.rangeFrame:SetAllPoints()
ud.rangeFrame:Hide()
ud.rangeFrameText = ud.rangeFrame:CreateFontString("RangeDisplayFrameText_" .. unit, "ARTWORK",
"GameFontNormal")
ud.rangeFrameText:SetFont(DefaultFontPath, ud.db.fontSize, ud.db.fontOutline)
ud.rangeFrameText:SetJustifyH("CENTER")
ud.rangeFrameText:SetPoint("CENTER", ud.rangeFrame, "CENTER", 0, 0)
ud.lastUpdate = 0
ud.mainFrame:SetScript("OnMouseDown", function(frame, button)
if button == "LeftButton" then
if IsControlKeyDown() then
RangeDisplay:toggleLocked(true)
return
end
ud.mainFrame:StartMoving()
ud.isMoving = true
GameTooltip:Hide()
elseif button == "RightButton" then
RangeDisplay:openConfigDialog(ud)
end
end)
ud.mainFrame:SetScript("OnMouseUp", function(frame, button)
if ud.isMoving and button == "LeftButton" then
ud.mainFrame:StopMovingOrSizing()
ud.isMoving = false
ud.db.point, _, ud.db.relPoint, ud.db.x, ud.db.y = ud.mainFrame:GetPoint()
end
end)
ud.mainFrame:SetScript("OnEnter", function(frame)
GameTooltip:SetOwner(frame)
GameTooltip:AddLine("RangeDisplay: " .. L[unit])
GameTooltip:AddLine(" ")
GameTooltip:AddLine(L["|cffeda55fControl + Left Click|r to lock frames"])
GameTooltip:AddLine(L["|cffeda55fRight Click|r to open the configuration window"])
GameTooltip:AddLine(L["|cffeda55fDrag|r to move the frame"])
GameTooltip:Show()
end)
ud.mainFrame:SetScript("OnLeave", function(frame)
GameTooltip:Hide()
end)
-- OnUpdate is set only on the rangeFrame
ud.rangeFrame.ud = ud
ud.rangeFrame:SetScript("OnUpdate", onUpdate)
end
local function enable(ud)
if not ud.mainFrame then
ud:createFrame()
end
if not ud.sounds then
ud.sounds = {}
end
if ud.locked then
ud:lock()
else
ud:unlock()
end
ud.mainFrame:Show()
RangeDisplay:registerTargetChangedEvent(ud)
end
local function disable(ud)
if ud.mainFrame then
ud.mainFrame:Hide()
RangeDisplay:unregisterTargetChangedEvent(ud)
end
end
local function lock(ud)
ud.locked = true
if ud.db.enabled then
ud.mainFrame:EnableMouse(false)
if ud.overlay then
ud.overlay:Hide()
ud.overlayText:Hide()
end
end
end
local function unlock(ud)
ud.locked = false
if ud.db.enabled then
if not ud.overlay then
createOverlay(ud)
end
ud.mainFrame:EnableMouse(true)
ud.overlay:Show()
ud.overlayText:Show()
end
end
local units = {
{
unit = "playertarget",
name = L["playertarget"], -- to make Babelfish happy
event = "PLAYER_TARGET_CHANGED",
},
{
unit = "focus",
name = L["focus"], -- to make Babelfish happy
event = "PLAYER_FOCUS_CHANGED",
},
{
unit = "pet",
name = L["pet"], -- to make Babelfish happy
event = "UNIT_PET",
targetChanged = function(ud, event, unitId, ...)
if event and unitId ~= "player" then return end
targetChanged(ud, event, unitId, ...)
end,
},
{
unit = "mouseover",
name = L["mouseover"], -- to make Babelfish happy
event = "UPDATE_MOUSEOVER_UNIT",
mouseAnchor = true,
applyMouseSettings = function(ud)
if ud.db.enabled then
if ud.locked and ud.db.mouseAnchor then
ud.rangeFrame:SetScript("OnUpdate", onUpdateWithMousePos)
ud.rangeFrame:SetScript("OnShow", updateUIScale)
else
ud.rangeFrame:SetScript("OnUpdate", onUpdate)
ud.rangeFrame:SetScript("OnShow", nil)
ud.mainFrame:ClearAllPoints()
ud.mainFrame:SetPoint(ud.db.point, UIParent, ud.db.relPoint, ud.db.x, ud.db.y)
end
if not ud.locked and ud.db.mouseAnchor then
if not ud.fakeCursor then
ud.fakeCursor = UIParent:CreateTexture("RangeDisplayFakeCursor", "OVERLAY")
ud.fakeCursor:SetTexture(FakeCursorImage)
ud.fakeCursor:ClearAllPoints()
ud.fakeCursor:SetPoint("TOPLEFT", UIParent, "CENTER", 0, 0)
ud.fakeCursor:SetVertexColor(0, .42, 0)
ud.fakeCursor:SetAlpha(0.42)
end
ud.fakeCursor:Show()
else
if ud.fakeCursor then
ud.fakeCursor:Hide()
end
end
else
if ud.fakeCursor then
ud.fakeCursor:Hide()
end
end
end,
lock = function(ud)
lock(ud)
ud:applyMouseSettings()
end,
unlock = function(ud)
unlock(ud)
ud:applyMouseSettings()
end,
disable = function(ud)
disable(ud)
if ud.fakeCursor then
ud.fakeCursor:Hide()
end
end,
update = updateCheckValid,
},
}
for _, ud in ipairs(units) do
ud.profileChanged = ud.profileChanged or profileChanged
ud.applySettings = ud.applySettings or applySettings
ud.applyFontSettings = ud.applyFontSettings or applyFontSettings
ud.applyBGSettings = ud.applyBGSettings or applyBGSettings
ud.mediaUpdate = ud.mediaUpdate or mediaUpdate
ud.targetChanged = ud.targetChanged or targetChanged
ud.checkTarget = ud.checkTarget or checkTarget
ud.lock = ud.lock or lock
ud.unlock = ud.unlock or unlock
ud.createFrame = ud.createFrame or createFrame
ud.update = ud.update or update
ud.autoAdjust = ud.autoAdjust or autoAdjust
ud.enable = ud.enable or enable
ud.disable = ud.disable or disable
end
RangeDisplay.units = units
-- AceAddon stuff
function RangeDisplay:OnInitialize()
if LSM then
for sound, fileName in pairs(Sounds) do
LSM:Register("sound", sound, fileName)
end
end
self.db = LibStub("AceDB-3.0"):New("RangeDisplayDB3", defaults, true)
if LibDualSpec then
LibDualSpec:EnhanceDatabase(self.db, AppName)
end
self.db.RegisterCallback(self, "OnProfileChanged", "profileChanged")
self.db.RegisterCallback(self, "OnProfileCopied", "profileChanged")
self.db.RegisterCallback(self, "OnProfileReset", "profileChanged")
self:profileChanged()
self:setupDummyOptions()
self:setupLDB()
if not self.db.profile.locked then
self:RegisterEvent("PLAYER_REGEN_DISABLED", function()
if not self.db.profile.locked then
self:toggleLocked(true)
end
end)
end
end
function RangeDisplay:OnEnable(first)
end
function RangeDisplay:OnDisable()
for _, ud in ipairs(units) do
ud:disable()
end
self:UnregisterAllEvents()
end
function RangeDisplay:applySettings()
if not self:IsEnabled() then
self:OnDisable()
return
end
for _, ud in ipairs(units) do
if ud.db.enabled then
ud:enable()
ud:applySettings()
else
ud:disable()
end
end
self:toggleLocked(self.db.profile.locked == true)
self:toggleMute(self.db.profile.mute == true)
end
-- for now we assume that each unitdata is using only 1 event, and there are no overlapping events, as
it's faster like this
function RangeDisplay:registerTargetChangedEvent(ud)
if ud.event then
ud.eventHandler = ud.eventHandler or function(...)
ud:targetChanged(...)
end
self:RegisterEvent(ud.event, ud.eventHandler)
end
end
function RangeDisplay:unregisterTargetChangedEvent(ud)
if ud.event then
self:UnregisterEvent(ud.event)
end
end
function RangeDisplay:profileChanged()
local locked = self.db.profile.locked
for _, ud in ipairs(units) do
ud.locked = locked
local db = self.db.profile.units[ud.unit]
ud:profileChanged(db)
end
self:applySettings()
end
function RangeDisplay:lock()
self.db.profile.locked = true
for _, ud in ipairs(units) do
ud:lock()
end
end
function RangeDisplay:unlock()
self.db.profile.locked = false
for _, ud in ipairs(units) do
ud:unlock()
end
end
function RangeDisplay:toggleLocked(flag)
if flag == nil then
flag = not self.db.profile.locked
end
if flag ~= self.db.profile.locked then
self:updateMainOptions()
end
if flag then
self:lock()
else
self:unlock()
end
end
function RangeDisplay:toggleMute(flag)
if flag == nil then
flag = not self.db.profile.mute
end
if flag ~= self.db.profile.mute then
self:updateMainOptions()
end
self.db.profile.mute = flag
mute = flag
for _, ud in ipairs(units) do
if ud.db.enabled then
ud:checkTarget() -- to update useSound
end
end
end
function RangeDisplay:setupLDB()
local LDB = LibStub:GetLibrary("LibDataBroker-1.1", true)
if not LDB then return end
local ldb = {
type = "launcher",
icon = Icon,
OnClick = function(frame, button)
if button == "LeftButton" then
if IsShiftKeyDown() then
self:toggleMute()
else
self:toggleLocked()
end
elseif button == "RightButton" then
self:openConfigDialog()
end
end,
OnTooltipShow = function(tt)
tt:AddLine(self.AppName)
tt:AddLine(L["|cffeda55fLeft Click|r to lock/unlock frames"])
tt:AddLine(L["|cffeda55fShift + Left Click|r to toggle sound"])
tt:AddLine(L["|cffeda55fRight Click|r to open the configuration window"])
end,
}
LDB:NewDataObject(self.AppName, ldb)
end
-- LoD Options muckery
function RangeDisplay:setupDummyOptions()
if self.optionsLoaded then
return
end
self.dummyOpts = CreateFrame("Frame", AppName .. "DummyOptions", UIParent)
self.dummyOpts.name = AppName
self.dummyOpts:SetScript("OnShow", function(frame)
if not self.optionsLoaded then
if not InterfaceOptionsFrame:IsVisible() then
return -- wtf... Happens if you open the game map and close it with ESC
end
self:openConfigDialog()
else
frame:Hide()
end
end)
InterfaceOptions_AddCategory(self.dummyOpts)
end
function RangeDisplay:loadOptions()
if not self.optionsLoaded then
self.optionsLoaded = true
local loaded, reason = LoadAddOn(OptionsAppName)
if not loaded then
print("Failed to load " .. tostring(OptionsAppName) .. ": " .. tostring(reason))
end
end
end
function RangeDisplay:openConfigDialog(ud)
-- this function will be overwritten by the Options module when loaded
if not self.optionsLoaded then
self:loadOptions()
return self:openConfigDialog(ud)
end
InterfaceOptionsFrame_OpenToCategory(self.dummyOpts)
end
-- Stubs for RangeDisplay_Options
function RangeDisplay:updateMainOptions()
end
-- register slash command
SLASH_RANGEDISPLAY1 = "/rangedisplay"
SlashCmdList["RANGEDISPLAY"] = function(msg)
msg = strtrim(msg or "")
if msg == "locked" then
RangeDisplay:toggleLocked()
else
RangeDisplay:openConfigDialog()
end
end
CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {}
CONFIGMODE_CALLBACKS[AppName] = function(action)
if action == "ON" then
RangeDisplay:toggleLocked(false)
elseif action == "OFF" then
RangeDisplay:toggleLocked(true)
end
end