WoWInterface SVN RaidWatch2

[/] [trunk/] [RaidWatch_Plugins/] [Direction.lua] - Rev 22

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

Compare with Previous | Blame