Compare with Previous | Blame | View Log
local RW = LibStub("AceAddon-3.0"):GetAddon("Raid Watch") local plugin = RW:Plugin("Direction", "AceConsole-3.0") ---------------------------- -- Locals local L = LibStub("AceLocale-3.0"):GetLocale("RW2-Plugin-Direction") local LB = LibStub("AceLocale-3.0"):GetLocale("RW2-Plugin-Base") local LSM = LibStub("LibSharedMedia-3.0") local Party local db local Utils = RW.Utils local anchor local AllArrows = {} local UnusedArrows = {} local UsedArrows = {} local UsedArrowsI = {} local arrowCount = 0 local iconCoords = { {0, 0.25, 0, 0.25}, {0.25, 0.5, 0, 0.25}, {0.5, 0.75, 0, 0.25}, {0.75, 1, 0, 0.25}, {0, 0.25, 0.25, 0.5}, {0.25, 0.5, 0.25, 0.5}, {0.5, 0.75, 0.25, 0.5}, {0.75, 1, 0.25, 0.5}, } local iconTexture = "Interface\\TargetingFrame\\UI-RaidTargetingIcons.blp" local ExpandList = { {value=1, text=LB.LEFT, icon = [[Interface\MoneyFrame\Arrow-Left-Up]]}, {value=2, text=LB.RIGHT, icon = [[Interface\MoneyFrame\Arrow-Right-Up]]}, {value=3, text=LB.UP, icon = [[Interface\Vehicles\UI-Vehicles-Button-Pitch-Up]]}, {value=4, text=LB.DOWN, icon = [[Interface\Vehicles\UI-Vehicles-Button-PitchDown-Up]]}, {value=5, text=LB.CENTER_HOR, icon = [[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]]}, {value=6, text=LB.CENTER_VERT, icon = [[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]]}, } ------ --Math local PI = math.pi local PI2 = math.pi * 2 local defaults = { profile = { PluginEnabled = true, x = 0, y = 0, ExpandDir = 5, Width = 160, Height = 160, Color = {1, 1, 1}, ColorClose = {0, 1, 0}, ColorFar = {1, 0, 0}, Font = "accid", FontSize = 18, FontColor = {0.47, 0.75, 1, 1}, ArrowTexture = [[Interface\AddOns\RaidWatch\Media\Arrow.tga]], } } ---------------------------- -- Init function plugin:OnRegister() self.db = RW.db:RegisterNamespace("Direction", defaults) db = self.db.profile self.db.RegisterCallback(self, "OnProfileChanged", "Reset") self.db.RegisterCallback(self, "OnProfileCopied", "Reset") self.db.RegisterCallback(self, "OnProfileReset", "Reset") end function plugin:PluginEnable() if not db.PluginEnabled then self:Disable() return end self:RegisterCallback("DirectionToNameOrUnit") self:RegisterCallback("DirectionToPosition") self:RegisterCallback("DirectionHideAll") self:RegisterCallback("DirectionHide") self:RegisterCallback("ConfigMode") self:CreateAnchor("Direction Guides") self:RegisterChatCommand("dir", "SlashHandler") self:Reset() Party = RW.Party end function plugin:PluginDisable() if self.frame then self.frame:Hide() end self:UnregisterAllCallbacks() end function plugin:Reset() db = self.db.profile local scale = anchor:GetEffectiveScale() / UIParent:GetEffectiveScale() anchor:ClearAllPoints() anchor:SetPoint("CENTER", UIParent, "CENTER", db.x / scale, db.y / scale) anchor:SetWidth(db.Width) for i, arrow in pairs(AllArrows) do arrow.t:SetVertexColor(unpack(db.Color)) arrow.name:SetFont(LSM:Fetch("font", db.Font), db.FontSize, "OUTLINE") arrow.name:SetTextColor(unpack(db.FontColor)) arrow.extrainfo:SetFont(LSM:Fetch("font", db.Font), db.FontSize, "OUTLINE") arrow.extrainfo:SetTextColor(unpack(db.FontColor)) arrow:SetHeight(db.Height) arrow:SetWidth(db.Width) arrow.t:SetTexture(db.ArrowTexture) if (db.Height - 60) < db.Width then arrow.t:SetWidth(db.Height - 60) arrow.t:SetHeight(db.Height - 60) else arrow.t:SetWidth(db.Width) arrow.t:SetHeight(db.Width) end end self:ArrangeArrows() end local function dragStart(self) self:StartMoving() end local function dragStop(self) self:StopMovingOrSizing() local scale = self:GetEffectiveScale() / UIParent:GetEffectiveScale() local x, y = self:GetCenter() x, y = x * scale, y * scale x = x - GetScreenWidth()/2 y = y - GetScreenHeight()/2 db.x = x db.y = y RW.Callbacks:Fire("RefreshOptions") end function plugin:CreateAnchor(name) local nanchor = Utils:CreateAnchor(name, UIParent, name) nanchor:SetScript("OnDragStart", dragStart) nanchor:SetScript("OnDragStop", dragStop) nanchor.name = name nanchor.arrows = {} anchor = nanchor end local function Click(self, button) if button == "RightButton" and IsShiftKeyDown() then plugin:HideArrow(self) Utils:TRemove(UsedArrowsI, self) plugin:ArrangeArrows() end end function plugin:GetArrow() local arrow = table.remove(UnusedArrows) if arrow then return arrow end arrow = CreateFrame("Frame", "RWDirectionArrow"..(#AllArrows + 1), UIParent) arrow:SetHeight(db.Height) arrow:SetWidth(db.Width) arrow:SetScript("OnMouseDown", Click) arrow:RegisterEvent("MODIFIER_STATE_CHANGED") arrow:SetScript("OnEvent", function(self, event, arg1, arg2) if arg1 == "LSHIFT" or arg1 == "RSHIFT" then if arg2 == 1 then self:EnableMouse(true) self:SetScript("OnMouseDown", Click) else self:EnableMouse(false) self:SetScript("OnMouseDown", nil) end end end) local icon = arrow:CreateTexture() icon:SetTexture(iconTexture) icon:SetPoint("BOTTOMLEFT") icon:SetHeight(30) icon:SetWidth(30) icon:Hide() arrow.icon = icon local namestring = arrow:CreateFontString("RWDirectionArrowName"..(#AllArrows + 1), "ARTWORK") namestring:SetPoint("BOTTOMLEFT", icon, "BOTTOMRIGHT", 5, 0) namestring:SetPoint("BOTTOMRIGHT") namestring:SetJustifyH("LEFT") namestring:SetHeight(30) namestring:SetFont(LSM:Fetch("font", db.Font), db.FontSize, "OUTLINE") namestring:SetTextColor(unpack(db.FontColor)) arrow.name = namestring local extraicon = arrow:CreateTexture() extraicon:SetPoint("TOPLEFT") extraicon:SetHeight(30) extraicon:SetWidth(30) extraicon:Hide() arrow.extraicon = extraicon local extrainfo = arrow:CreateFontString("RWDirectionArrowInfo"..(#AllArrows + 1), "ARTWORK") extrainfo:SetPoint("TOPLEFT", extraicon, "TOPRIGHT", 5, 0) extrainfo:SetPoint("TOPRIGHT") extrainfo:SetJustifyH("LEFT") extrainfo:SetHeight(30) extrainfo:SetFont(LSM:Fetch("font", db.Font), db.FontSize, "OUTLINE") extrainfo:SetTextColor(unpack(db.FontColor)) arrow.extrainfo = extrainfo local texture = arrow:CreateTexture() texture:SetTexture(db.ArrowTexture) texture:SetPoint("CENTER") texture:SetWidth(db.Height - 60) texture:SetVertexColor(unpack(db.Color)) arrow.t = texture local AnimGroup = texture:CreateAnimationGroup() local Rotation = AnimGroup:CreateAnimation("Rotation") local AnimHolder = AnimGroup:CreateAnimation("Rotation") Rotation:SetDegrees(0.0) Rotation:SetDuration(0) AnimHolder:SetDegrees(0) AnimHolder:SetDuration(999999999) arrow.AnimGroup = AnimGroup arrow.Rotation = Rotation arrow.AnimHolder = AnimHolder tinsert(AllArrows, arrow) if (db.Height - 60) < db.Width then arrow.t:SetWidth(db.Height - 60) arrow.t:SetHeight(db.Height - 60) else arrow.t:SetWidth(db.Width) arrow.t:SetHeight(db.Width) end return arrow end function plugin:ArrangeArrows() for i, arrow in pairs(UsedArrowsI) do arrow:ClearAllPoints() if i == 1 then if db.ExpandDir == 1 then arrow:SetPoint("BOTTOMRIGHT", anchor, "TOPRIGHT") elseif db.ExpandDir == 4 then arrow:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT") else arrow:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT") end else if db.ExpandDir == 2 then arrow:SetPoint("BOTTOMLEFT", UsedArrowsI[i-1], "BOTTOMRIGHT") elseif db.ExpandDir == 1 then arrow:SetPoint("BOTTOMRIGHT", UsedArrowsI[i-1], "BOTTOMLEFT") elseif db.ExpandDir == 3 then arrow:SetPoint("BOTTOMLEFT", UsedArrowsI[i-1], "TOPLEFT") elseif db.ExpandDir == 4 then arrow:SetPoint("TOPLEFT", UsedArrowsI[i-1], "BOTTOMLEFT") elseif db.ExpandDir == 5 then arrow:SetPoint("BOTTOMLEFT", UsedArrowsI[i-1], "BOTTOMRIGHT") UsedArrowsI[1]:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", -(#UsedArrowsI * db.Width / 2) + db.Width / 2, 0) elseif db.ExpandDir == 6 then arrow:SetPoint("BOTTOMLEFT", UsedArrowsI[i-1], "TOPLEFT") local diff = -(anchor:GetHeight() / 2) - (#UsedArrowsI) * (db.Height / 2) UsedArrowsI[1]:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, diff) end end end end function plugin:HideArrow(arrow) arrow:Hide() UsedArrows[arrow.UserData.id] = nil wipe(arrow.UserData) tinsert(UnusedArrows, arrow) end function plugin:SetArrowAngle(arrow, angle) local pf = GetPlayerFacing() local px, py = math.sin(pf), math.cos(pf) local angle = angle - math.atan2(px, py) if arrow.UserData.away then angle = angle + PI end arrow.Rotation:SetRadians(angle) arrow.AnimGroup:Play() end local function ArrowUpdate(self, elapsed) local d, angle if self.UserData.trackType == "UNIT" then d, angle = Utils:GetDistanceAndAngleToUnit(self.UserData.unit) if d then local c = self.UserData.classcolor self.name:SetText(("|cff%2x%2x%2x%s|r (%dy)"):format(c.r * 255, c.g * 255, c.b * 255, self.UserData.name, d)) end local raidtarget = GetRaidTargetIndex(self.UserData.unit) if raidtarget then self.icon:SetTexCoord(unpack(iconCoords[raidtarget])) self.icon:Show() else self.icon:Hide() end if self.UserData.extraicon then self.extraicon:SetTexture(self.UserData.extraicon) self.extraicon:SetTexCoord(0.02, 0.98, 0.02, 0.98) self.extraicon:Show() else self.extraicon:Hide() end elseif self.UserData.trackType == "POSITION" then local mx, my = self.UserData.x, self.UserData.y d, angle = Utils:GetDistanceAndAngle(mx, my) mx, my = Utils:GetPointInYards(mx, my) if d then self.name:SetText(("[%.0f, %.0f] (%dy)"):format(mx, my, d)) end if self.UserData.extraicon then self.extraicon:SetTexture(self.UserData.extraicon) self.extraicon:SetTexCoord(0.02, 0.98, 0.02, 0.98) self.extraicon:Show() else self.extraicon:Hide() end end if self.UserData.extra then self.extrainfo:SetText(self.UserData.extra..(self.UserData.away and " ("..self.UserData.away.."y)" or "")) self.extrainfo:Show() else self.extrainfo:Hide() end local r1, g1, b1 = unpack(db.ColorClose) local r2, g2, b2 = unpack(db.ColorFar) local p = 0.5 if self.UserData.away then if d then p = d/self.UserData.away end self.t:SetVertexColor(Utils:ColorGradientSimple(p, r2, g2, b2, r1, g1, b1)) else if d then p = d/40 end self.t:SetVertexColor(Utils:ColorGradientSimple(p, r1, g1, b1, r2, g2, b2)) end plugin:SetArrowAngle(self, angle) end function plugin:InitArrow(arrow, id, away, extra, icon) arrow.UserData = arrow.UserData or {} local spellName, spellIcon if type(extra) == "number" then spellName, _, spellIcon = GetSpellInfo(extra) end arrow.UserData.id = id arrow.UserData.away = away arrow.UserData.extra = spellName or extra arrow.UserData.extraicon = icon or spellIcon arrow:SetScript("OnUpdate", ArrowUpdate) arrow:Show() if arrow.UserData.extraicon and type(arrow.UserData.extraicon) == "number" then arrow.UserData.extraicon = select(3, GetSpellInfo(arrow.UserData.extraicon)) end UsedArrows[id] = arrow tinsert(UsedArrowsI, arrow) self:ArrangeArrows() end function plugin:DirectionToNameOrUnit(message, id, uID, tName, away, extra, icon) if UsedArrows[id] then return end --[===[@debug@ if away and type(away) ~= "number" then error("Away number must be of type number") end --@end-debug@]===] local unit if uID and UnitExists(uID) then unit = uID else for n, data in Party:PartyIterator() do if n == tName then unit = data.id end end end if not unit then return end if UnitIsUnit(unit, "player") then return end local arrow = self:GetArrow() if not arrow then return end self:InitArrow(arrow, id, away, extra, icon) arrow.UserData.classcolor = RAID_CLASS_COLORS[select(2, UnitClass(unit))] arrow.UserData.name = UnitName(unit) arrow.UserData.trackType = "UNIT" arrow.UserData.unit = unit end function plugin:DirectionToPosition(event, id, x, y, away, extra, icon) if UsedArrows[id] then return end local arrow = self:GetArrow() if not arrow then return end self:InitArrow(arrow, id, away, extra, icon) arrow.UserData.x = x arrow.UserData.y = y arrow.UserData.trackType = "POSITION" end function plugin:DirectionHide(event, id) local arrow = UsedArrows[id] if arrow then self:HideArrow(arrow) end Utils:TRemove(UsedArrowsI, arrow) self:ArrangeArrows() end function plugin:DirectionHideAll(event) for id, arrow in pairs(UsedArrowsI) do self:HideArrow(arrow) end wipe(UsedArrowsI) self:ArrangeArrows() end function plugin:ConfigMode(event, show) if show then anchor:Show() RW.Callbacks:Fire("DirectionToPosition", "test1", 0.5, 0.5, 40, "Test1", [[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]]) RW.Callbacks:Fire("DirectionToPosition", "test2", 0.1, 0.2, nil, "Test2", [[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]]) RW.Callbacks:Fire("DirectionToPosition", "test3", 0.5, 0.1, nil, "Test3", [[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]]) else anchor:Hide() RW.Callbacks:Fire("DirectionHide", "test1") RW.Callbacks:Fire("DirectionHide", "test2") RW.Callbacks:Fire("DirectionHide", "test3") end end function plugin:SlashHandler(msg) RW.Callbacks:Fire("DirectionToNameOrUnit", "personal", nil, msg) end function plugin:GetOptions() return LB.PLUGINS, LB.ALERT_PLUGINS, L.NAME, self.GetGUI, [[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]] end function plugin.ChangeCallback() plugin:Reset() end local arrowTextureList = { ["Interface\\AddOns\\RaidWatch\\Media\\Arrow.tga"] = "Arrow 1", ["Interface\\AddOns\\RaidWatch\\Media\\Arrow2.tga"] = "Arrow 2", } function plugin:GetGUI() local self = self or plugin local UIF = LibStub("LibGUIFactory-1.0"):GetFactory("RW") local AceGUI = LibStub("AceGUI-3.0") local group, label, slider, check, igroup, igroup2, button, color, select group = AceGUI:Create("ScrollFrame") group:SetLayout("Flow") label = UIF:MainTitleLabel(L.NAME) group:AddChild(label) igroup = UIF:InlineGroup("") group:AddChild(igroup) label = UIF:NormalText(L.DESC) label:SetImage([[Interface\PAPERDOLLINFOFRAME\UI-GearManager-Undo]]) igroup:AddChild(label) igroup = UIF:InlineGroup("") group:AddChild(igroup) check = UIF:CheckBox(LB.ENABLED, db, "PluginEnabled", function() if not db.PluginEnabled then self:Disable() else self:Enable() end end) igroup:AddChild(check) local drop = UIF:Dropdown(L.EXPAND_DIR, db, "ExpandDir", plugin.ChangeCallback) drop:SetList(ExpandList) drop:SetFullWidth(true) igroup:AddChild(drop) color = UIF:ColorSelect(L.COLOR_NEAR, db, "ColorClose", plugin.ChangeCallback) color:SetRelativeWidth(0.32) igroup:AddChild(color) color = UIF:ColorSelect(L.COLOR_FAR, db, "ColorFar", plugin.ChangeCallback) color:SetRelativeWidth(0.32) igroup:AddChild(color) color = UIF:ColorSelect(LB.FONT_COLOR, db, "FontColor", plugin.ChangeCallback, nil, 0.3) igroup:AddChild(color) slider = UIF:Slider(LB.FONT_SIZE, db, "FontSize", 1, 40, 1, plugin.ChangeCallback, 0.5) igroup:AddChild(slider) igroup:AddChild(UIF:Dropdown("Texture", db, "ArrowTexture", plugin.ChangeCallback, arrowTextureList, 0.5)) igroup2 = UIF:InlineGroup(LB.SIZE) igroup:AddChild(igroup2) slider = UIF:Slider(LB.WIDTH, db, "Width", 10, 300, 1, plugin.ChangeCallback) igroup2:AddChild(slider) slider = UIF:Slider(LB.HEIGHT, db, "Height", 10, 300, 1, plugin.ChangeCallback) igroup2:AddChild(slider) igroup2 = UIF:InlineGroup(LB.POSITION) igroup:AddChild(igroup2) slider = UIF:Slider("X", db, "x", -floor(GetScreenWidth() * UIParent:GetEffectiveScale()), floor(GetScreenWidth() * UIParent:GetEffectiveScale()), 1, plugin.ChangeCallback) igroup2:AddChild(slider) slider = UIF:Slider("Y", db, "y", -floor(GetScreenHeight() * UIParent:GetEffectiveScale()), floor(GetScreenHeight() * UIParent:GetEffectiveScale()), 1, plugin.ChangeCallback) igroup2:AddChild(slider) button = UIF:Button(LB.RESET, function() plugin.db:ResetProfile() end) button:SetUserData("confirm", true) button:SetUserData("TriggerGlobalUpdate", true) group:AddChild(button) button = UIF:Button(LB.HIDE_ALL, function() RW.Callbacks:Fire("DirectionHideAll") end) group:AddChild(button) return group end