WoWInterface SVN mRunes

[/] [trunk/] [mRunes/] [Modules/] [Runes.lua] - Rev 8

Compare with Previous | Blame | View Log

local _, class = UnitClass("player")
if class ~= "DEATHKNIGHT" then
        return
end

local plugin = mRunes:NewModule("Runes", "AceEvent-3.0")
plugin.mRunesPlugin = true

local AceGUI    = LibStub("AceGUI-3.0")
local LSM               = LibStub("LibSharedMedia-3.0")
local BD                = LibStub("LibBackdrop-1.0")
local FA                = LibStub("LibFrameAnchorRegistry-1.0")
local UIF
local db

-- Rune Types
local RUNETYPE_BLOOD = 1;
local RUNETYPE_UNHOLY = 2;
local RUNETYPE_FROST = 3;
local RUNETYPE_DEATH = 4;

local RuneNames = {
        "Blood 1",
        "Blood 2",
        "Unholy 1",
        "Unholy 2",
        "Frost 1",
        "Frost 2",
}

local NrRunes = 6
local InCombat = false
local RuneOnCD = true
local ConfigMode = false

local Update

local backdrop = {
        tile = true, 
        tileSize = 16,
        insets = {},
}

plugin.DisplayName = "Runes"
plugin.DisplayIcon = [[Interface\Icons\INV_Glyph_MajorDeathKnight]]
plugin.DisplayOrder = 1

function plugin:OnInitialize()
        local defaults = {
                profile = {
                        Enabled = true,
                        HideBlizz = true,
                        
                        Attached = {
                                f = "mRunesCenter",
                                x = 0,
                                y = 0,
                                Point = "CENTER",
                                RelPoint = "CENTER",
                        },
                        
                        Rune = {
                                ["**"] = {
                                        Order = 1,
                                }
                        },
                        
                        InternalSpacing = 2,
                        FrameColor = {0, 0, 0, 0.5},
                        
                        RuneSpacing = 1.12,
                        Width = 330,
                        Height = 22,
                        
                        RuneTexture = "HalD",
                        
                        RuneAlphaInCombat = 1,
                        RuneAlphaOutCombat = 0.2,
                        RuneAlphaActive = 0.5,
                        
                        RuneCooldownInset = 2,
                        RuneCooldownAlwaysShow = false,
                        RuneCooldownShow = true, 
                        RuneCooldownHorAlign = "LEFT",
                        
                        Font = "accid",
                        FontSize = 16,
                        FontFlags = "OUTLINE",
                        FontColor = {1, 1, 1, 1},
                        
                        BorderTexture = "None",
                        BorderWidth = 5,
                        BorderInsets = 0,
                        BorderPadding = 2,
                        BorderColor = {0, 0, 0, 1},
                
                        RuneColors = {
                                [RUNETYPE_BLOOD] = {1.0, 0.0, 0.0, 1},
                                [RUNETYPE_UNHOLY] ={0.0, 0.8, 0.0, 1},
                                [RUNETYPE_FROST] = {0.0, 1.0, 1.0, 1},
                                [RUNETYPE_DEATH] = {0.8, 0.1, 1.0, 1},
                        }
                }
        }
        
        self.db = mRunes.db:RegisterNamespace(self:GetName(), defaults)
        self.db.RegisterCallback(self, "OnProfileChanged", "ProfileChanged")
        self.db.RegisterCallback(self, "OnProfileCopied", "ProfileChanged")
        self.db.RegisterCallback(self, "OnProfileReset", "ProfileChanged")
        db = self.db.profile
        
        self:SetEnabledState(db.Enabled)
        
        UIF = LibStub("LibGUIFactory-1.0"):GetFactory("mRunes")
        
        if not mRuneFrame then
                self:CreateFuneFrame()
        end
end

function plugin:OnEnable()      
        self:ApplySettings()
        self.Frame:Show()
        
        self:RegisterEvent("RUNE_TYPE_UPDATE", "RuneTypeUpdate")
        self:RegisterEvent("RUNE_POWER_UPDATE", "RuneStateChange")
        self:RegisterEvent("PLAYER_ENTERING_WORLD", "EnterWorld") 
        
        mRunes.RegisterCallback(self, "EnteringCombat")
        mRunes.RegisterCallback(self, "LeavingCombat")
        mRunes.RegisterCallback(self, "ToggleConfigMode")
        
        FA.RegisterCallback(self, "FrameRegistered", "ApplySettings")
        
        if UnitAffectingCombat("player") then
                self:EnteringCombat("EnteringCombat")
        else
                self:LeavingCombat("LeavingCombat")
        end
        
end

function plugin:OnDisable()
        self.Frame:Hide()
end

function plugin:ProfileChanged()
        db = self.db.profile
        self:ApplySettings()
end

-- ~~~~~~~~~~~~~~~~~~~~
-- Callbacks ~~~~~~~~~~
-- ~~~~~~~~~~~~~~~~~~~~
function plugin:EnteringCombat(event)
        mRunes.FadeIn(self.Frame, false, db.RuneAlphaInCombat)
        InCombat = true
        RuneOnCD = false
end

function plugin:LeavingCombat(event)
        mRunes.FadeOut(self.Frame, db.RuneAlphaOutCombat)
        InCombat = false
end

function plugin:EnterWorld(...)
        if self.Runes then
                for i, rune in pairs(self.Runes) do
                        rune.Update = true
                        self:RuneTypeUpdate("RUNE_TYPE_UPDATE", i)
                end
        end
end

function plugin:ToggleConfigMode(event, enable)
        ConfigMode = enable
        if enable then
                self.Frame.ConfigText:Show()
                mRunes.FadeIn(self.Frame, false, 1)
        else
                self.Frame.ConfigText:Hide()
                if InCombat then
                        mRunes.FadeIn(self.Frame, true, db.RuneAlphaInCombat)
                elseif RuneOnCD then
                        mRunes.FadeIn(self.Frame, true, db.RuneAlphaActive)
                else
                        mRunes.FadeIn(self.Frame, true, db.RuneAlphaOutCombat)
                end
                Update(self.Frame, 0)
        end
end

-- ~~~~~~~~~~~~~~~~~~~~
-- Events ~~~~~~~~~~~~~
-- ~~~~~~~~~~~~~~~~~~~~



-- Rune type changed (unholy runes)
function plugin:RuneTypeUpdate(event, runeID)
        self.Runes[runeID]:SetStatusBarColor(unpack(db.RuneColors[GetRuneType(runeID)]))
end

-- Rune Ready/Not Ready event
function plugin:RuneStateChange(event, runeID, ready)
        if runeID == 8 or runeID == 7 then return end
        
        if ready then
                self.Runes[runeID]:SetValue(1)          
                self.Runes[runeID].Update = nil
                self.Runes[runeID].CDText:SetText(("%.1f"):format(0))
                if not db.RuneCooldownAlwaysShow then
                        self.Runes[runeID].CDText:Hide()
                end
        else
                self.Runes[runeID].Update = not ready   
                mRunes:RegisterOnUpdate(self, Update)   
        end     
end

Update = function(self, elapsed)
        self = plugin
        local haveCD = false
        local oldHaveCD = RuneOnCD
        for i, rune in pairs(self.Runes) do
                if rune.Update then
                        local StartTime, CooldownTime, Ready = GetRuneCooldown(i)
                        local diff = GetTime() - StartTime
                        local remaining = CooldownTime - diff
                        local t = diff / CooldownTime                                   
                        rune:SetValue(t)
                        if remaining < 0 and not db.RuneCooldownAlwaysShow then 
                                rune.CDText:Hide() 
                        elseif db.RuneCooldownShow then
                                rune.CDText:Show()      
                                rune.CDText:SetText(("%.1f"):format(Ready and 0 or (remaining < 0 and 0 or remaining))) 
                        end
                        
                        if Ready then rune.Update = nil else haveCD = true end
                end
        end

        if not InCombat then
                RuneOnCD = haveCD
                if RuneOnCD and (RuneOnCD ~= oldHaveCD) then
                        local currAlpha = self.Frame:GetAlpha()
                        if currAlpha < db.RuneAlphaActive then
                                mRunes.FadeIn(self.Frame, false, db.RuneAlphaActive)
                        else
                                mRunes.FadeOut(self.Frame, db.RuneAlphaActive)
                        end
                elseif not RuneOnCD and (RuneOnCD ~= oldHaveCD) then
                        mRunes:UnregisterOnUpdate(self, Update) 
                        mRunes.FadeOut(self.Frame, db.RuneAlphaOutCombat)
                end
        end
end

-- ~~~~~~~~~~~~~~~~~~~~
-- Settings     ~~~~~~~~~~~
-- ~~~~~~~~~~~~~~~~~~~~
local OrderedRunes = {}
local function SortRunes(a, b)
        local adb = db.Rune[a.id]
        local bdb = db.Rune[b.id]
        if adb.Order == bdb.Order then
                return a.id < b.id
        else
                return adb.Order < bdb.Order
        end
end

function plugin:ApplySettings()
        if self.Frame then
                local anchor = FA:GetAnchor(db.Attached.f)
                self.Frame:ClearAllPoints()
                self.Frame:SetPoint(db.Attached.Point, anchor, db.Attached.RelPoint, db.Attached.x, db.Attached.y)              
                
                self.Frame:SetWidth(db.Width)
                self.Frame:SetHeight(db.Height)
                
                backdrop.insets.left = db.BorderInsets
                backdrop.insets.right = db.BorderInsets
                backdrop.insets.top = db.BorderInsets
                backdrop.insets.bottom = db.BorderInsets
                backdrop.edgeFile = LSM:Fetch("border", db.BorderTexture)
                backdrop.edgeSize = db.BorderWidth
                backdrop.bgFile = LSM:Fetch("background", "Solid")
                self.Frame:SetBackdrop(backdrop)
                self.Frame:SetBackdropColor(unpack(db.FrameColor))
                self.Frame:SetBackdropBorderColor(unpack(db.BorderColor))
                
                wipe(OrderedRunes)
                for i, rune in pairs(self.Runes) do
                        rune:ClearAllPoints()
                        tinsert(OrderedRunes, rune)
                end
                table.sort(OrderedRunes, SortRunes)
                
                local RuneWidth = db.Width / 6
                for i, rune in pairs(OrderedRunes) do
                        rune:ClearAllPoints()
                        if i == 1 then
                                rune:SetPoint("LEFT", db.BorderPadding + db.RuneSpacing / 2, 0)
                                rune:SetWidth(RuneWidth - db.RuneSpacing - db.BorderPadding / 3)
                        else
                                rune:SetPoint("LEFT",  OrderedRunes[i-1], "RIGHT", db.RuneSpacing, 0)
                                rune:SetWidth(RuneWidth - db.RuneSpacing - db.BorderPadding / 3)
                        end                     
                        rune:SetHeight(db.Height - db.BorderPadding * 2)
                        rune:SetStatusBarTexture(LSM:Fetch("statusbar", db.RuneTexture))
                        rune:GetStatusBarTexture():SetHorizTile(false)
                        rune:SetStatusBarColor(unpack(db.RuneColors[GetRuneType(rune.id)]))
                        
                        local leftinset, rightinset = 0, 0
                        if db.RuneCooldownHorAlign == "LEFT" then
                                leftinset = db.RuneCooldownInset
                        elseif db.RuneCooldownHorAlign == "RIGHT" then
                                rightinset = -db.RuneCooldownInset
                        end                             
                        
                        rune.CDText:ClearAllPoints()            
                        rune.CDText:SetPoint("TOPLEFT", leftinset, 0)
                        rune.CDText:SetPoint("BOTTOMRIGHT", rightinset, 0)
                        rune.CDText:SetFont(LSM:Fetch("font", db.Font), db.FontSize, db.FontFlags)
                        rune.CDText:SetTextColor(unpack(db.FontColor))
                        rune.CDText:SetJustifyH(db.RuneCooldownHorAlign)
                        rune.CDText:SetJustifyV("MIDDLE")
                        
                        if db.RuneCooldownAlwaysShow and db.RuneCooldownShow then
                                rune.CDText:Show()
                        elseif not db.RuneCooldownShow then
                                rune.CDText:Hide()                              
                        end
                        rune.Update = true
                end
                
                if not ConfigMode then
                        self.Frame:SetAlpha(InCombat and db.RuneAlphaInCombat or (RuneOnCD and db.RuneAlphaActive or db.RuneAlphaOutCombat))
                end
                if self.Frame:GetAlpha() > 0 then self.Frame:Show() else self.Frame:Hide() end
        end
        
        if db.HideBlizz then RuneFrame:Hide()
        else RuneFrame:Show() end
        
        if not db.Enabled and self:IsEnabled() then self:Disable()
        elseif db.Enabled and not self:IsEnabled() then self:Enable() end
        
        FA:FrameModified("mRunes", "Runes")
end

-- ~~~~~~~~~~~~~~~~~~~~
-- Create Frames ~~~~~~
-- ~~~~~~~~~~~~~~~~~~~~
function plugin:CreateFuneFrame()
        local frame = CreateFrame("Frame", "mRunesRuneFrame", UIParent) 
        
        --BD:EnhanceBackdrop(frame)
        FA:RegisterAnchor("mRunes", "Runes", "mRunesRunes", frame)
        
        self.Runes = {}
        for i = 1, NrRunes do
                self.Runes[i] = self:CreateRune(i, frame)
        end
        
        local configFrame = CreateFrame("Frame", nil, frame)
        configFrame:SetAllPoints()
        configFrame:SetFrameLevel(self.Runes[1]:GetFrameLevel() + 10)
        local configText = configFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        configText:SetAllPoints()
        configText:SetText("Runes")
        configText:Hide()
        frame.ConfigText = configText
        
        frame:Show()
        
        self.Frame = frame
end

function plugin:CreateRune(runeID, parent)
        local rune = CreateFrame("StatusBar", "mRunesRune"..runeID, parent)
        rune:SetMinMaxValues(0,1)       
        rune:SetValue(1)
        
        local runeCooldown = rune:CreateFontString(nil, nil, "GameFontNormal")
        rune.CDText = runeCooldown
        
        rune.id = runeID
        
        rune.Update = true      
        rune:Show()
        
        return rune
end

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Options ~~~~~~~~~~~~~~~~~~~~
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function plugin:GetOptions()
        return plugin.GetGUI
end

do
        local function Callback()
                plugin:ApplySettings()
        end
        
        local FontFlagList = {
                ["NONE"] = "None",
                ["OUTLINE"] = "Outline",
                ["THICKOUTLINE"] = "Thick Outline",
                ["MONOCHROME"] = "Monochrome",
        }
        
        local HorizontalAlignList = {
                ["LEFT"] = "Left",
                ["CENTER"] = "Center",
                ["RIGHT"] = "Right",
        }

        local TabSelected
        local LastSelectedTab
        
        function plugin:GetGUI()
                self = plugin   
                
                local returnGroup = AceGUI:Create("SimpleGroup")
                returnGroup:SetFullWidth(true)
                returnGroup:SetLayout("Flow")
                
                returnGroup:AddChild(UIF:NewLine(10))
                
                returnGroup:AddChild(UIF:CheckBox("Enabled", db, "Enabled", Callback, nil, 0.2))
                returnGroup:AddChild(UIF:CheckBox("Hide default rune frame", db, "HideBlizz", Callback, "Hides the blizzard build in rune frame", 0.8))
                
                local tgroup = UIF:TabGroup()
                returnGroup:AddChild(tgroup)
                tgroup:SetTabs({
                        {text = "Position & Size", value = "PaS"},
                        {text = "Colors & Alpha", value = "CaA"},
                        {text = "Font", value = "Font"},
                        {text = "Ordering", value = "Ordering"},
                })
                
                tgroup:SetCallback("OnGroupSelected", TabSelected)
                tgroup:SelectTab(LastSelectedTab or "PaS")

                return returnGroup
        end
        
        TabSelected = function(self, event, tab)
                self:ReleaseChildren()
                LastSelectedTab = tab
                
                if tab == "PaS" then                            
                        self:AddChild(UIF:Text1("Select a frame to attach to. You can then adjust the relative positioning to that frame via X and Y as well as the anchor points."))                   
                        local t = AceGUI:Create("FrameAnchorDropdown")
                        t:SetRelativeWidth(0.5)
                        t:SetList(FA:GetAnchors(plugin.Frame))
                        t:SetLabel("Anchor")
                        t:SetValue(db.Attached.f)
                        t:SetCallback("OnValueChanged", function(self, event, cat, name, frame)
                                db.Attached.f = cat
                                Callback()
                        end)
                        self:AddChild(t)
                        self:AddChild(UIF:Spacer(10))
                        self:AddChild(UIF:Text2("Avoid creating circle references!", nil, nil, nil, nil, nil, 0.4))
                        self:AddChild(UIF:NewLine())                    
                        self:AddChild(UIF:Dropdown("Point", db.Attached, "Point", Callback, mRunes:GetAnchorList(), 0.5, true))
                        self:AddChild(UIF:Dropdown("Relative Point", db.Attached, "RelPoint", Callback, mRunes:GetAnchorList(), 0.5, true))
                        self:AddChild(UIF:Slider("X", db.Attached, "x", -300, 300, 0.1, Callback, 0.5))
                        self:AddChild(UIF:Slider("Y", db.Attached, "y", -300, 300, 0.1, Callback, 0.5))
                        self:AddChild(UIF:Slider("Width", db, "Width", 5, 1000, 0.1, Callback, 0.5))
                        self:AddChild(UIF:Slider("Height", db, "Height", 5, 200, 0.1, Callback, 0.5))
                        self:AddChild(UIF:Slider("Space between Runes", db, "RuneSpacing", 0, 100, 0.1, Callback, 0.5))                 
                
                elseif tab == "CaA" then                
                        local group = UIF:InlineGroup2("Rune Colors")
                        self:AddChild(group)
                        group:AddChild(UIF:ColorSelect("Blood", db.RuneColors, 1, Callback, true, 0.25))
                        group:AddChild(UIF:ColorSelect("Unholy", db.RuneColors, 2, Callback, true, 0.25))
                        group:AddChild(UIF:ColorSelect("Frost", db.RuneColors, 3, Callback, true, 0.25))
                        group:AddChild(UIF:ColorSelect("Death", db.RuneColors, 4, Callback, true, 0.25))                

                        group = UIF:InlineGroup2("Alpha")
                        self:AddChild(group)
                        group:AddChild(UIF:Slider("Combat", db, "RuneAlphaInCombat", 0, 1, 0.01, Callback, 0.33))
                        group:AddChild(UIF:Slider("OOC (Runes on cooldown)", db, "RuneAlphaActive", 0, 1, 0.01, Callback, 0.33))
                        group:AddChild(UIF:Slider("OOC (No runes on cooldown)", db, "RuneAlphaOutCombat", 0, 1, 0.01, Callback, 0.33))                  
                        
                        group = UIF:InlineGroup2("Border and Background")
                        self:AddChild(group)
                        group:AddChild(UIF:LSMDropdown("border", "Border texture", db, "BorderTexture", Callback, 0.5))
                        group:AddChild(UIF:LSMDropdown("statusbar", "Bar Texture", db, "RuneTexture", Callback, 0.5))                   
                        
                        group:AddChild(UIF:ColorSelect("Background Color", db, "FrameColor", Callback, true, 0.5))                      
                        group:AddChild(UIF:ColorSelect("Border color", db, "BorderColor", Callback, true, 0.5)) 
                        group:AddChild(UIF:Slider("Border Width", db, "BorderWidth", 0, 50, 1, Callback, 0.33))
                        group:AddChild(UIF:Slider("Border Padding", db, "BorderPadding", 0, 100, 0.1, Callback, 0.33))
                        group:AddChild(UIF:Slider("Border Insets", db, "BorderInsets", 0, 50, 1, Callback, 0.33))                       
                        
                elseif tab == "Font" then
                        self:AddChild(UIF:Text1("These settings are for the cooldown text on each rune"))
                        self:AddChild(UIF:CheckBox("Show", db, "RuneCooldownShow", Callback, "Toggle if the cooldown text should shown", 0.5))
                        self:AddChild(UIF:CheckBox("Always Show", db, "RuneCooldownAlwaysShow", Callback, "Toggle if the cooldown text should always be shown, even when it is not on cooldown", 0.5))                  
                        self:AddChild(UIF:LSMDropdown("font", "Font", db, "Font", Callback, 0.5))
                        self:AddChild(UIF:Dropdown("Font Flags", db, "FontFlags", Callback, FontFlagList, 0.5))         
                        self:AddChild(UIF:ColorSelect("Color", db, "FontColor", Callback, false, 0.2))
                        self:AddChild(UIF:Slider("Size", db, "FontSize", 2, 50, 1, Callback, 0.4))
                        self:AddChild(UIF:Slider("Margin", db, "RuneCooldownInset", 0, 50, 0.1, Callback, 0.4))
                        self:AddChild(UIF:Dropdown("Horizontal Alignment", db, "RuneCooldownHorAlign", Callback, HorizontalAlignList, 0.5))                     
                        
                elseif tab == "Ordering" then
                        self:AddChild(UIF:Text1("Runes are sorted first by the value you set here, second by their rune index. So by setting setting both unholy runes to the same sort order they will still be sorted so that unholy rune 1 comes before unholy rune 2."))
                        for i, rune in pairs(plugin.Runes) do
                                self:AddChild(UIF:Slider(RuneNames[rune.id], db.Rune[rune.id], "Order", 1, 6, 1, Callback, 0.5))
                        end
                end
                
                self:DoLayout()
                self.parent:DoLayout()
        end
end

Compare with Previous | Blame