WoWInterface SVN KuiNameplates

[/] [trunk/] [Kui_Nameplates/] [layout.lua] - Rev 158

Compare with Previous | Blame | View Log

--[[
        Kui Nameplates
        Kesava-Auchindoun

        TODO NEXT VERSION
        customisation for sizes/positions of auras & width of container frame, etc
        customisation for raid target icons
        test combo points
        fix cast time and spell name overlapping
]]

local addon, ns = ...
local kui = LibStub('Kui-1.0')
local LSM = LibStub('LibSharedMedia-3.0')
local kn = LibStub('AceAddon-3.0'):GetAddon('KuiNameplates')

--KuiNameplatesDebug=true
-- uncommenting this line will display a white box where the default UI's
-- nameplate is rendered, a black background where the pixel-perfect plate from
-- this addon is rendered (if "Fix aliasing" is enabled), the GUID/name
-- status of any visible plates and the detected reaction type of the plate.

kn.font = ''
kn.fontSizes = {}
kn.sizes = {}
kn.frameList = {}

-- Custom reaction colours
kn.r = {
    { .7, .2, .1 }, -- hated
    { 1, .8, 0 },   -- neutral
    { .2, .6, .1 }, -- friendly
        { .5, .5, .5 }, -- tapped
}

-- sizes of frame elements
kn.defaultSizes = {
        frame = {
                width    = 110,
                height   = 11,
                twidth   = 55,
                theight  = 7,
                bgOffset = 4  -- inset offset for the frame glow (frame.bg)
        },
        font = {
                combopoints = 13,
                large       = 10,
                spellname   = 9,
                name        = 9,
                small       = 8
        },
}

local loadedGUIDs, loadedNames = {}, {}
local targetExists, targetFound
local profile, uiscale

--------------------------------------------------------------------- globals --
local select, strfind, strsplit, pairs, ipairs, unpack, tinsert, type
    = select, strfind, strsplit, pairs, ipairs, unpack, tinsert, type

------------------------------------------------------------ helper functions --

local function SetFontSize(fs, size)
        if profile.fonts.options.onesize then
                size = kn.fontSizes['name']
        end

        if type(size) == 'string' and fs.size and kn.fontSizes[size] then
                fs.size = size
                size = kn.fontSizes[size]
        end

        local font, _, flags = fs:GetFont()
        fs:SetFont(font, size, flags)
end

local function CreateFontString(self, parent, obj)
        -- store size as a key of kn.fontSizes so that it can be recalled & scaled
        -- correctly. Used by SetFontSize.
        local sizeKey

        obj = obj or {} 
        obj.mono = profile.fonts.options.monochrome
        obj.outline = profile.fonts.options.outline
        obj.size = obj.size or 'name'

        if type(obj.size) == 'string' then
                sizeKey = obj.size
                obj.size = kn.fontSizes[sizeKey]
        end

        if profile.fonts.options.onesize then
                obj.size = kn.fontSizes['name']
        end

        if not obj.font then
                obj.font = kn.font
        end

        local fs = kui.CreateFontString(parent, obj)
        fs.size = sizeKey

        --fs.SetFontSize = SetFontSize
        --fs.SetFontStyle = SetFontStyle

        tinsert(self.fontObjects, fs)
        return fs
end

kn.SetFontSize = SetFontSize
kn.CreateFontString = CreateFontString

------------------------------------------------------------- Frame functions --
-- set colour of health bar according to reaction/threat
local function SetHealthColour(self)
        if self.hasThreat then
                self.health.reset = true
                self.health:SetStatusBarColor(unpack(profile.tank.barcolour))
                return
        end

        local r, g, b = self.oldHealth:GetStatusBarColor()
        if self.health.reset  or
           r ~= self.health.r or
           g ~= self.health.g or
           b ~= self.health.b
        then
                -- store the default colour
                self.health.r, self.health.g, self.health.b = r, g, b
                self.health.reset, self.friend, self.player = nil, nil, nil

                if g > .9 and r == 0 and b == 0 then
                        -- friendly NPC
                        self.friend = true
                        r, g, b = unpack(kn.r[3])
                elseif b > .9 and r == 0 and g == 0 then
                        -- friendly player
                        self.friend = true
                        self.player = true
                        r, g, b = 0, .3, .6
                elseif r > .9 and g == 0 and b == 0 then
                        -- enemy NPC
                        r, g, b = unpack(kn.r[1])
                elseif (r + g) > 1.8 and b == 0 then
                        -- neutral NPC
                        r, g, b = unpack(kn.r[2])
                elseif b > .9 and (r+g) > 1.06 and (r+g) < 1.1 then
                        -- tapped NPC
                        r, g, b = unpack(kn.r[4])
                else
                        -- enemy player, use default UI colour
                        self.player = true
                end

                self.health:SetStatusBarColor(r, g, b)
        end
end

local function SetNameColour(self)
        if self.friend then
                self.name:SetTextColor(unpack(profile.text.friendlyname))
        else
                self.name:SetTextColor(unpack(profile.text.enemyname))
        end
end

local function SetGlowColour(self, r, g, b, a)
        if not r then
                -- set default colour
                r, g, b = 0, 0, 0
        end

        if not a then
                a = .85
        end

    self.bg:SetVertexColor(r, g, b, a)
end

local function StoreFrameGUID(self, guid)
        if not guid then return end
        if self.guid and loadedGUIDs[self.guid] then
                if self.guid ~= guid then
                        -- the currently stored guid is incorrect
                        loadedGUIDs[self.guid] = nil
                else
                        return
                end
        end

        self.guid = guid
        loadedGUIDs[guid] = self

        if loadedNames[self.name.text] == self then
                loadedNames[self.name.text] = nil
        end
end

---------------------------------------------------- Update health bar & text --
local function OnHealthValueChanged(oldBar, curr)
        local frame     = oldBar:GetParent():GetParent()
        local min, max  = oldBar:GetMinMaxValues()
        local deficit,    big, sml, condition, display, pattern, rules
            = max - curr, '',  ''

        frame.health:SetMinMaxValues(min, max)
        frame.health:SetValue(curr)
        
        -- select correct health display pattern
        if frame.friend then
                pattern = profile.hp.friendly
        else
                pattern = profile.hp.hostile
        end

        -- parse pattern into big/sml
        rules = { strsplit(';', pattern) }

        for k, rule in ipairs(rules) do
                condition, display = strsplit(':', rule)

                if condition == '<' then
                        condition = curr < max
                elseif condition == '=' then
                        condition = curr == max
                elseif condition == '<=' or condition == '=<' then
                        condition = curr <= max
                else
                        condition = nil
                end

                if condition then
                        if display == 'd' then
                                big = '-'..kui.num(deficit)
                                sml = kui.num(curr)
                        elseif display == 'm' then
                                big = kui.num(max)
                        elseif display == 'c' then
                                big = kui.num(curr)
                                sml = curr ~= max and kui.num(max)
                        elseif display == 'p' then
                                big = floor(curr / max * 100)
                                sml = kui.num(curr)
                        end

                        break
                end
        end

        frame.health.p:SetText(big)

        if frame.health.mo then
                frame.health.mo:SetText(sml)
        end
end

------------------------------------------------------- Frame script handlers --
local function OnFrameShow(self)
        -- reset name
        self.name.text = self.oldName:GetText()
        self.name:SetText(self.name.text)

        if profile.hp.mouseover then
                -- force un-highlight
                self.highlighted = true
        end
        
        -- classifications
        if self.level.enabled then
                if self.boss:IsVisible() then
                        self.level:SetText('??b')
                        self.level:SetTextColor(1, 0, 0)
                        self.level:Show()
                elseif self.state:IsVisible() then
                        if self.state:GetTexture() == "Interface\\Tooltips\\EliteNameplateIcon"
                        then
                                self.level:SetText(self.level:GetText()..'+')
                        else
                                self.level:SetText(self.level:GetText()..'r')
                        end
                end
        else
                self.level:Hide()
        end
        
        if self.state:IsVisible() then
                -- hide the elite/rare dragon
                self.state:Hide()
        end

        if not loadedNames[self.name.text] and
           not self.guid
        then
                -- store this frame's name
                loadedNames[self.name.text] = self
        end
        
        ---------------------------------------------- Trivial sizing/positioning --
        if self.firstChild:GetScale() < 1 then
                if not self.trivial then
                        -- initialise trivial unit sizes
                        if uiscale then
                                self.parent:SetSize(self:GetWidth()/uiscale, self:GetHeight()/uiscale)
                        end
                        
                        local w,h = self.parent:GetSize()
                        local x,y = 
                                floor((w / 2) - (kn.sizes.twidth / 2)),
                                floor((h / 2) - (kn.sizes.theight / 2))
                
                        self.health:ClearAllPoints()
                        self.bg:ClearAllPoints()
                        self.bg.fill:ClearAllPoints()
                        self.name:ClearAllPoints()
                        
                        self.level:Hide()
                        self.health.p:Hide()
                        
                        if self.health.mo then
                                self.health.mo:Hide()
                        end
                        
                        --SetFontSize(self.name, 'small')
                        self.name:SetJustifyH('CENTER')
                        
                        self.name:SetPoint('BOTTOM', self.health, 'TOP', 0, -3)
                                                
                        self.bg.fill:SetSize(kn.sizes.twidth, kn.sizes.theight)
                        self.health:SetSize(kn.sizes.twidth-2, kn.sizes.theight-2)
                        
                        self.health:SetPoint('BOTTOMLEFT', x+1, y+1)
                        
                        self.bg.fill:SetPoint('BOTTOMLEFT', x, y)
                        
                        self.bg:SetPoint('BOTTOMLEFT', x-(kn.sizes.bgOffset-2), y-(kn.sizes.bgOffset-2))
                        self.bg:SetPoint('TOPRIGHT', self.parent, 'BOTTOMLEFT', x+kn.sizes.twidth+(kn.sizes.bgOffset-2), y+kn.sizes.theight+(kn.sizes.bgOffset-2))
                
                        self.trivial = true
                else
                        -- (performed each time a trivial frame is shown)
                        self.level:Hide()
                end
        elseif self.trivial then
                -- return to normal sizes
                if uiscale then
                        self.parent:SetSize(self:GetWidth()/uiscale, self:GetHeight()/uiscale)
                end
                
                local w,h = self.parent:GetSize()
                local x,y =
                        floor((w / 2) - (kn.sizes.width / 2)), 
                        floor((h / 2) - (kn.sizes.height / 2))
                
                self.health:ClearAllPoints()
                self.bg:ClearAllPoints()
                self.bg.fill:ClearAllPoints()
                self.name:ClearAllPoints()
                        
                self.health.p:Show()    
                
                if self.health.mo then
                        self.health.mo:Show()
                end
                
                --SetFontSize(self.name, 'name')
                self.name:SetJustifyH('LEFT')
                self.name:SetPoint('RIGHT', self.health.p, 'LEFT')
                
                if self.level.enabled then
                        self.name:SetPoint('LEFT', self.level, 'RIGHT', -2, 0)
                        self.level:Show()
                else
                        self.name:SetPoint('BOTTOMLEFT', self.health, 'TOPLEFT', 2, uiscale and -(2/uiscale) or -2)
                end
                
                self.bg.fill:SetSize(kn.sizes.width, kn.sizes.height)           
                self.health:SetSize(kn.sizes.width - 2, kn.sizes.height - 2)
                
                self.health:SetPoint('BOTTOMLEFT', x+1, y+1)
                
                self.bg.fill:SetPoint('BOTTOMLEFT', x, y)
                
                self.bg:SetPoint('BOTTOMLEFT', x-kn.sizes.bgOffset, y-kn.sizes.bgOffset)
                self.bg:SetPoint('TOPRIGHT', self.parent, 'BOTTOMLEFT', x+(kn.sizes.width)+kn.sizes.bgOffset, y+(kn.sizes.height)+kn.sizes.bgOffset)
                
                self.trivial = nil
        end

        self:UpdateFrame()
        self:UpdateFrameCritical()
        
        -- force health update
        OnHealthValueChanged(self.oldHealth, self.oldHealth:GetValue())
        self:SetGlowColour()

        if self.carrier then
                -- TODO TEST only show players
                --[[if self.friend and self.player then
                        self.carrier.DoShow = true
                else
                        self.carrier.DoShow = nil
                        self.carrier:Hide()
                end]]

                self.carrier.DoShow = true
        end

        kn:SendMessage('KuiNameplates_PostShow', self)
end

local function OnFrameHide(self)
        if self.carrier then
                self.carrier:Hide()
        end

        if self.guid and loadedGUIDs[self.guid] == self then
                -- remove guid from the store
                loadedGUIDs[self.guid] = nil    end

        self.guid = nil

        if loadedNames[self.name.text] == self then
                -- remove name from store
                -- if there are name duplicates, this will be recreated in an onupdate
                loadedNames[self.name.text] = nil
        end

        self.lastAlpha  = 0
        self.fadingTo   = nil
        self.hasThreat  = nil
        self.target             = nil

        -- unset stored health bar colours
        self.health.r, self.health.g, self.health.b, self.health.reset
                = nil, nil, nil, nil
        
        kn:SendMessage('KuiNameplates_PostHide', self)  
end

local function OnFrameEnter(self)
        self:StoreGUID(UnitGUID('mouseover'))

        if self.highlight then
                self.highlight:Show()
        end

        if profile.hp.mouseover then
                self.health.p:Show()
                if self.health.mo then self.health.mo:Show() end
        end
end

local function OnFrameLeave(self)
        if self.highlight then
                self.highlight:Hide()
        end

        if not self.target and profile.hp.mouseover then
                self.health.p:Hide()
                if self.health.mo then self.health.mo:Hide() end
        end
end

-- stuff that needs to be updated every frame
local function OnFrameUpdate(self, e)
        self.elapsed    = self.elapsed + e
        self.critElap   = self.critElap + e

        if self.carrier then
                ------------------------------------------------------------ Position --
                local scale = self.firstChild:GetScale()
                local x, y = select(4, self.firstChild:GetPoint())
                x = (x / uiscale) * scale
                y = (y / uiscale) * scale
                
                self.carrier:SetPoint('BOTTOMLEFT', UIParent, 'BOTTOMLEFT', floor(x-(self.carrier:GetWidth()/2)), floor(y))
                
                -- show the frame after it's been moved so it doesn't flash
                -- .DoShow is set OnFrameShow
                if self.carrier.DoShow then
                        self.carrier:Show()
                        self.carrier.DoShow = nil
                end
        end
        
        self.defaultAlpha = self:GetAlpha()
        ------------------------------------------------------------------- Alpha --
        if (self.defaultAlpha == 1 and
            targetExists)          or
           (profile.fade.fademouse and
            self.highlighted)
        then
                self.currentAlpha = 1
        elseif  targetExists or profile.fade.fadeall then
                self.currentAlpha = profile.fade.fadedalpha or .3
        else
                self.currentAlpha = 1
        end
        ------------------------------------------------------------------ Fading --
        if profile.fade.smooth then
                -- track changes in the alpha level and intercept them
                if self.currentAlpha ~= self.lastAlpha then
                        if not self.fadingTo or self.fadingTo ~= self.currentAlpha then
                                if kui.frameIsFading(self) then
                                        kui.frameFadeRemoveFrame(self)
                                end

                                -- fade to the new value
                                self.fadingTo     = self.currentAlpha
                                local alphaChange = (self.fadingTo - (self.lastAlpha or 0))

                                kui.frameFade(self.carrier and self.carrier or self, {
                                        mode            = alphaChange < 0 and 'OUT' or 'IN',
                                        timeToFade      = abs(alphaChange) * (profile.fade.fadespeed or .5),
                                        startAlpha      = self.lastAlpha or 0,
                                        endAlpha        = self.fadingTo,
                                        finishedFunc = function()
                                                self.fadingTo = nil
                                        end,
                                })
                        end

                        self.lastAlpha = self.currentAlpha
                end
        else
                (self.carrier and self.carrier or self):SetAlpha(self.currentAlpha)
        end
        
        -- call delayed updates
        if self.elapsed > 1 then
                self.elapsed = 0
                self:UpdateFrame()
        end

        if self.critElap > .1 then
                self.critElap = 0
                self:UpdateFrameCritical()
        end
end

-- stuff that can be updated less often
local function UpdateFrame(self)
        if not loadedNames[self.name.text] and
           not self.guid
        then
                -- ensure a frame is still stored for this name, as name conflicts cause
                -- it to be erased when another might still exist
                -- also ensure that if this frame is targeted, this is the stored frame
                -- for its name
                loadedNames[self.name.text] = self
        end

        -- Health bar colour
        self:SetHealthColour()
        
        -- Name text colour
        self:SetNameColour()
end

-- stuff that needs to be updated often
local function UpdateFrameCritical(self)
        ------------------------------------------------------------------ Threat --
        if self.glow:IsVisible() then
                self.glow.wasVisible = true

                -- set glow to the current default ui's colour
                self.glow.r, self.glow.g, self.glow.b = self.glow:GetVertexColor()
                self:SetGlowColour(self.glow.r, self.glow.g, self.glow.b)

                if not self.friend and profile.tank.enabled then
                        -- in tank mode; is the default glow red (are we tanking)?
                        self.hasThreat = (self.glow.g + self.glow.b) < .1

                        if self.hasThreat then
                                -- tanking; recolour bar & glow
                                local r, g, b, a = unpack(profile.tank.glowcolour)
                                self:SetGlowColour(r, g, b, a)
                                self:SetHealthColour()
                        end
                end
        elseif self.glow.wasVisible then
                self.glow.wasVisible = nil

                -- restore shadow glow colour
                self:SetGlowColour()

                if self.hasThreat then
                        -- lost threat
                        self.hasThreat = nil
                        self:SetHealthColour()
                end
        end
        ------------------------------------------------------------ Target stuff --
        if targetExists and
           self.defaultAlpha == 1 and
           self.name.text == UnitName('target')
        then
                -- this frame is probably targeted
                if not targetFound then
                        -- this frame is definitely targeted
                        targetFound = true

                        if not self.target then
                                -- just became targeted
                                self.target = true
                                self:StoreGUID(UnitGUID('target'))

                                if self.carrier then
                                        -- move this frame above others
                                        -- default UI uses a level of 10 by default & 20 on the target
                                        self.carrier:SetFrameLevel(10)
                                end

                                if profile.hp.mouseover then
                                        self.health.p:Show()
                                        if self.health.mo then self.health.mo:Show() end
                                end
                                
                                kn:SendMessage('KuiNameplates_PostTarget', self)
                        end
                end
        elseif self.target then
                self.target = nil

                if not self.highlighted and profile.hp.mouseover then
                        self.health.p:Hide()
                        if self.health.mo then self.health.mo:Hide() end
                end
        end

        if not self.target and self.carrier then
                self.carrier:SetFrameLevel(1)
        end
        --------------------------------------------------------------- Mouseover --
        if self.oldHighlight:IsShown() then
                if not self.highlighted then
                        self.highlighted = true
                        OnFrameEnter(self)
                end
        elseif self.highlighted then
                self.highlighted = false
                OnFrameLeave(self)
        end
        
        -- [debug]
        if _G['KuiNameplatesDebug'] then
                if self.guid then
                        self.guidtext:SetText(self.guid)

                        if loadedGUIDs[self.guid] ~= self then
                                self.guidtext:SetTextColor(1,0,0)
                        else
                                self.guidtext:SetTextColor(1,1,1)
                        end
                else
                        self.guidtext:SetText(nil)
                end

                if self.name.text and loadedNames[self.name.text] == self then
                        self.nametext:SetText('Has name')
                else
                        self.nametext:SetText(nil)
                end
                
                if self.friend then
                        self.isfriend:SetText('friendly')
                else
                        self.isfriend:SetText('not friendly')
                end
        end
end

--------------------------------------------------------------- KNP functions --
function kn:GetNameplate(guid, name)
        local gf, nf = loadedGUIDs[guid], loadedNames[name]

        if gf then
                return gf
        elseif nf then
                return nf
        else
                return nil
        end
end

function kn:IsNameplate(frame)
        if frame:GetName() and strfind(frame:GetName(), '^NamePlate%d') then
                local nameTextChild = select(2, frame:GetChildren())
                if nameTextChild then
                        local nameTextRegion = nameTextChild:GetRegions()
                        return (nameTextRegion and nameTextRegion:GetObjectType() == 'FontString')
                end
        end
end

function kn:InitFrame(frame)
        frame.init = true
        frame.fontObjects = {}
        
        local overlayChild, nameTextChild = frame:GetChildren()
        local healthBar, castBar = overlayChild:GetChildren()
        
        local _, castbarOverlay, shieldedRegion, spellIconRegion
                = castBar:GetRegions()

        local nameTextRegion = nameTextChild:GetRegions()
    local
                glowRegion, overlayRegion, highlightRegion, levelTextRegion,
                bossIconRegion, raidIconRegion, stateIconRegion
                = overlayChild:GetRegions()

        highlightRegion:SetTexture(nil)
        bossIconRegion:SetTexture(nil)
        shieldedRegion:SetTexture(nil)
        castbarOverlay:SetTexture(nil)
        glowRegion:SetTexture(nil)

        -- disable default cast bar
        castBar:SetParent(nil)
        castbarOverlay.Show = function() return end
        castBar:SetScript('OnShow', function() castBar:Hide() end)

        frame.firstChild = overlayChild
        
        frame.bg    = overlayRegion
        frame.glow  = glowRegion
        frame.boss  = bossIconRegion
        frame.state = stateIconRegion
        frame.level = levelTextRegion
        frame.icon  = raidIconRegion
        frame.spell = spellIconRegion

        frame.oldHealth = healthBar
        frame.oldHealth:Hide()

        frame.oldName = nameTextRegion
        frame.oldName:Hide()
        
        frame.oldHighlight = highlightRegion

    --------------------------------------------------------- Frame functions --
    frame.CreateFontString      = CreateFontString
    frame.UpdateFrame                   = UpdateFrame
    frame.UpdateFrameCritical   = UpdateFrameCritical
    frame.SetHealthColour       = SetHealthColour
    frame.SetNameColour             = SetNameColour
    frame.SetGlowColour         = SetGlowColour
        frame.StoreGUID                         = StoreFrameGUID

        --[[ TODO
                past this point a frame has been initialised but not "created"
                it should be possible to hide/reset anything created after this
                when a profile change or setting change is detected, cycle all frames
                and reset them
        ]]

    ------------------------------------------------------------------ Layout --
        local parent
        if profile.general.fixaa and uiscale then
                frame.carrier = CreateFrame('Frame', nil, WorldFrame)
                frame.carrier:SetFrameStrata('BACKGROUND')
                frame.carrier:SetSize(frame:GetWidth()/uiscale, frame:GetHeight()/uiscale)
                frame.carrier:SetScale(uiscale)
                
                frame.carrier:SetPoint('CENTER', UIParent)
                frame.carrier:Hide()
                
                -- [debug]
                if _G['KuiNameplatesDebug'] then
                        frame.carrier:SetBackdrop({ bgFile = kui.m.t.solid })
                        frame.carrier:SetBackdropColor(0,0,0,.5)
                end
                
                parent = frame.carrier
        else
                parent = frame
        end

        frame.parent = parent
        
        -- using CENTER breaks pixel-perfectness with oddly sized frames
        -- .. so we have to align frames manually.
        local w,h = parent:GetSize()
        frame.x = floor((w / 2) - (kn.sizes.width / 2))
        frame.y = floor((h / 2) - (kn.sizes.height / 2))

        self:CreateBackground(frame)
        self:CreateHealthBar(frame)

        -- overlay (text is parented to this) --------------------------------------
        frame.overlay = CreateFrame('Frame', nil, parent)
        frame.overlay:SetAllPoints(frame.health)
        frame.overlay:SetFrameLevel(frame.health:GetFrameLevel()+1)

        self:CreateHighlight(frame)
        self:CreateHealthText(frame)
        
        if profile.hp.showalt then
                self:CreateAltHealthText(frame)
        end

        if profile.text.level then
                self:CreateLevel(frame)
        else
                frame.level:Hide()
        end

        self:CreateName(frame)
        
        -- raid icon ---------------------------------------------------------------
        kn:RegisterSize('frame', 'raidicon', 18)

        frame.icon:SetParent(frame.overlay)
        frame.icon:SetSize(kn.sizes.raidicon, kn.sizes.raidicon)

        frame.icon:ClearAllPoints()
        frame.icon:SetPoint('LEFT', frame.health, 'RIGHT', 0, 0)
    ----------------------------------------------------------------- Scripts --
        frame:HookScript('OnShow', OnFrameShow)
        frame:HookScript('OnHide', OnFrameHide)
    frame:HookScript('OnUpdate', OnFrameUpdate)

        frame.oldHealth:HookScript('OnValueChanged', OnHealthValueChanged)

        -- [debug]
        if _G['KuiNameplatesDebug'] then
                frame:SetBackdrop({bgFile=kui.m.t.solid})
                frame:SetBackdropColor(1, 1, 1, .5)

                frame.isfriend = frame:CreateFontString(frame.overlay)
                frame.isfriend:SetPoint('BOTTOM', frame, 'TOP')
                
                frame.guidtext = frame:CreateFontString(frame.overlay)
                frame.guidtext:SetPoint('TOP', frame, 'BOTTOM')

                frame.nametext = frame:CreateFontString(frame.overlay)
                frame.nametext:SetPoint('TOP', frame.guidtext, 'BOTTOM')
        end

        ------------------------------------------------------------ Finishing up --
        --frame.UpdateScales = UpdateScales

    frame.elapsed       = 0
        frame.critElap  = 0

        kn:SendMessage('KuiNameplates_PostCreate', frame)
        
        -- force OnShow
        OnFrameShow(frame)
end

---------------------------------------------------------------------- Events --
function kn:PLAYER_TARGET_CHANGED()
        targetExists = UnitExists('target')
        targetFound = nil
end

-- automatic toggling of enemy frames
function kn:PLAYER_REGEN_ENABLED()
        SetCVar('nameplateShowEnemies', 0)
end
function kn:PLAYER_REGEN_DISABLED()
        SetCVar('nameplateShowEnemies', 1)
end

------------------------------------------------------------- Script handlers --
kn.numFrames = 0

do
        local WorldFrame, lastUpdate
                = WorldFrame, 1

        function kn:OnUpdate()
                local frames = select('#', WorldFrame:GetChildren())

                if frames ~= self.numFrames then
                        local i, f

                        for i = 1, frames do
                                f = select(i, WorldFrame:GetChildren())
                                if self:IsNameplate(f) and not f.init then
                                        self:InitFrame(f)
                                        tinsert(self.frameList, f)
                                end
                        end

                        self.numFrames = frames
                end
        end

        kn:ScheduleRepeatingTimer('OnUpdate', .1)
end

function kn:ToggleCombatEvents(io)
        if io then
                self:RegisterEvent('PLAYER_REGEN_ENABLED')
                self:RegisterEvent('PLAYER_REGEN_DISABLED')
        else
                self:UnregisterEvent('PLAYER_REGEN_ENABLED')
                self:UnregisterEvent('PLAYER_REGEN_DISABLED')
        end
end

-------------------------------------------------- Listen for profile changes --
function kn:ProfileChanged()
        profile = self.db.profile
end

---------------------------------------------------- Post db change functions --
-- n.b. this is absolutely terrible and horrible and i hate it
kn.configChangedFuncs.runOnce.fontscale = function(val)
        kn:ScaleFontSizes()
end
kn.configChangedFuncs.fontscale = function(frame, val)
        local _, fontObject
        for _, fontObject in pairs(frame.fontObjects) do
                if type(fontObject.size) == 'string' then
                        SetFontSize(fontObject, kn.fontSizes[fontObject.size])
                end
        end
end

kn.configChangedFuncs.outline = function(frame, val)
        local _, fontObject
        for _, fontObject in pairs(frame.fontObjects) do
                kui.ModifyFontFlags(fontObject, val, 'OUTLINE')
        end
end

kn.configChangedFuncs.monochrome = function(frame, val)
        local _, fontObject
        for _, fontObject in pairs(frame.fontObjects) do
                kui.ModifyFontFlags(fontObject, val, 'MONOCHROME')
        end
end

kn.configChangedFuncs.fontscale = function(frame, val)
        local _, fontObject
        for _, fontObject in pairs(frame.fontObjects) do
                if type(fontObject.size) == 'string' then
                        SetFontSize(fontObject, kn.fontSizes[fontObject.size])
                end
        end
end
kn.configChangedFuncs.onesize = kn.configChangedFuncs.fontscale

kn.configChangedFuncs.Health = function(frame)
        if frame:IsShown() then
                -- update health display
                OnHealthValueChanged(frame.oldHealth, frame.oldHealth:GetValue())
        end
end
kn.configChangedFuncs.friendly = kn.configChangedFuncs.Health
kn.configChangedFuncs.hostile = kn.configChangedFuncs.Health

kn.configChangedFuncs.runOnce.font = function(val)
        kn.font = LSM:Fetch(LSM.MediaType.FONT, val)
end
kn.configChangedFuncs.font = function(frame, val)
        local _, fontObject
        for _, fontObject in pairs(frame.fontObjects) do
                local _, size, flags = fontObject:GetFont()
                fontObject:SetFont(kn.font, size, flags)
        end
end

-------------------------------------------------------------------- Finalise --
-- scale a frame/font size to keep it relatively the same with any uiscale
function ScaleFrameSize(key)
        local size = kn.defaultSizes.frame[key]
        kn.sizes[key] = (uiscale and floor(size/uiscale) or size)
end

function ScaleFontSize(key)
        local size = kn.defaultSizes.font[key]
        kn.fontSizes[key] = size * profile.fonts.options.fontscale
                
        if uiscale then
                kn.fontSizes[key] = kn.fontSizes[key] / uiscale
        end
end

-- [initialise and] scale frame sizes
function kn:ScaleFrameSizes()
        local k,_
        for k,_ in pairs(kn.defaultSizes.frame) do
                ScaleFrameSize(k)
        end
end

-- [initialise and] scale font sizes
function kn:ScaleFontSizes()
        local k,_
        for k,_ in pairs(kn.defaultSizes.font) do
                ScaleFontSize(k)
        end
end

-- modules must use this to add correctly scaled sizes
-- font sizes can then be called as a key in kn.CreateFontString
function kn:RegisterSize(type, key, size)
        if type ~= 'frame' and type ~= 'font' then return end

        kn.defaultSizes[type][key] = size

        if type == 'frame' then
                ScaleFrameSize(key)
        else
                ScaleFontSize(key)
        end
end

function kn:OnEnable()
        profile = self.db.profile
    
        if profile.general.fixaa then
                uiscale = UIParent:GetEffectiveScale()
        end
                
        self:ScaleFrameSizes()
        self:ScaleFontSizes()
        
        -- fetch font path from lsm
        self.font = LSM:Fetch(LSM.MediaType.FONT, profile.fonts.options.font)
    
        -------------------------------------- Health bar smooth update functions --
        -- (spoon-fed by oUF_Smooth)
        if profile.hp.smooth then
                local f, smoothing, GetFramerate, min, max, abs
                        = CreateFrame('Frame'), {}, GetFramerate, math.min, math.max, math.abs

                function kn.SetValueSmooth(self, value)
                        local _, maxv = self:GetMinMaxValues()

                        if value == self:GetValue() or (self.prevMax and self.prevMax ~= maxv) then
                                -- finished smoothing/max health updated
                                smoothing[self] = nil
                                self:OrigSetValue(value)
                        else
                                smoothing[self] = value
                        end

                        self.prevMax = maxv
                end

                f:SetScript('OnUpdate', function()
                        local limit = 30/GetFramerate()
                        
                        for bar, value in pairs(smoothing) do
                                local cur = bar:GetValue()
                                local new = cur + min((value-cur)/3, max(value-cur, limit))

                                if new ~= new then
                                        new = value
                                end

                                bar:OrigSetValue(new)

                                if cur == value or abs(new - value) < 2 then
                                        bar:OrigSetValue(value)
                                        smoothing[bar] = nil
                                end
                        end
                end)
        end

        self:RegisterEvent('PLAYER_TARGET_CHANGED')
        self:ToggleCombatEvents(profile.general.combat)
end

Compare with Previous | Blame