Nenue@6: --- LibFog-1.0 Nenue@6: -- In-house solution to processing frame configuration data. Nenue@6: --[[ Nenue@6: -- Nenue@6: Config Table fields: Nenue@6: Nenue@6: background .. _color, _texture, _blend properties of the texture referenced by frame.background Nenue@6: foregound .. " " " properties of the texture referenced by frame.foreground Nenue@6: backdrop arguments for SetBackdrop Nenue@6: border_color sets the border color on an existing frame backdrop Nenue@6: alpha, alpha_ooc uiobject alpha for in and out of combat Nenue@6: combat_fade true to change alpha levels based on combat Nenue@6: fade_time, fade_in, fade_out fade_time = fade_in or fade_out Nenue@6: Nenue@6: anchor, parent, anchorTo, x, y args for UIObject:SetPoint() Nenue@6: height, width args for Region:SetSize() Nenue@6: strata, layer, level override the strata, draw layer, and draw level where they apply Nenue@6: Nenue@6: padding space between frame and background edge Nenue@6: foreground_inset space between background and foreground edge Nenue@6: spacing space between segmented foreground elements (e.g. combo points) Nenue@6: Nenue@6: font, size, outline args for FontString:SetFont() respectively Nenue@6: justifyV, justifyH LEFT/CENTER/RIGHT, TOP/MIDDLE/BOTTOM Nenue@6: Nenue@6: SetFrameLayout(): Nenue@6: Applies: Nenue@6: anchor, parent, anchorTo, x, y Nenue@6: width, height, Nenue@6: padding, spacing, foreground_inset Nenue@6: backdrop, border_color, background_color Nenue@6: alpha, alpha_ooc Nenue@6: Nenue@6: SetStatusTextures(): Nenue@6: Applies: Nenue@6: foreground_texture, foreground_color, foreground_blend Nenue@6: background_texture, background_color, background_blend Nenue@6: Nenue@6: Defines: Nenue@6: fill_direction, fill_width, fill_height, fill_inset Nenue@6: :TranslateX(progress) Nenue@6: :TranslateY(progress) Nenue@6: :SetFillPoints() Nenue@6: Nenue@6: SetFontLayout(): Nenue@6: Applies: Nenue@6: anchor, parent, anchorTo, x, y Nenue@6: width, height Nenue@6: font, size, outline Nenue@6: justifyH, justifyV Nenue@6: Nenue@6: - Nenue@6: ]] Nenue@6: local MAJOR, MINOR = "LibFog-1.0", 1 Nenue@6: local F, oldminor = LibStub:NewLibrary(MAJOR, MINOR) Nenue@6: if not F then return end Nenue@6: Nenue@6: local _G, UIParent, type, unpack, pairs, ipairs, min, abs, tostring, print = _G, UIParent, type, unpack, pairs, ipairs, math.min, math.abs, tostring, print Nenue@6: local InCombatLockdown, GetTime, PlaySoundKitID, CreateFrame = InCombatLockdown, GetTime, PlaySoundKitID, CreateFrame Nenue@6: local tinsert, wipe, concat = table.insert, table.wipe, table.concat Nenue@6: local FADE_OUT_TIME, FADE_IN_TIME = 1, 0.4 Nenue@6: Nenue@6: --@debug@ Nenue@6: local cType, cText, cNum, cWord, cKey, cPink, cBool = cType, cText, cNum, cWord, cKey, cPink, cBool Nenue@6: local ADDON, scriptargs = ... Nenue@6: scriptargs.LibFog = F Nenue@6: local print = function(...) Nenue@6: if _G.Devian and _G.DevianDB.workspace ~= 1 then Nenue@6: _G.print('Layout', ...) Nenue@6: end Nenue@6: end Nenue@6: --- debug highlighters Nenue@6: local namef = function(s) return '|cFFFFFF00' ..tostring(s).. '|r' end -- uiobject targeted function Nenue@6: local namet = function(s) return '|cFFFF4400 '..tostring(s).. '|r' end -- region targeted function Nenue@6: local valuef = function(s) return '|cFF88FF88'..(s ~= nil and ('"'..tostring(s)..'"') or ('nil'))..'|r' end -- uiobject name Nenue@6: local valuet = function(s) return '|cFFAACCAA'..(s ~= nil and ('"'..tostring(s)..'"') or ('nil'))..'|r' end -- string value Nenue@6: local valuen = function(s) return '|cFFAADD77' ..(s ~= nil and ('"'..tostring(s)..'"') or ('nil')).. '|r' end -- string enumeration Nenue@6: local valued = function(s) return '|cFFFFFFFF' ..(s ~= nil and ('"'..tostring(s)..'"') or ('nil')).. '|r' end -- number Nenue@6: --@end-debug@ Nenue@6: local GetPrint = function(trace) Nenue@6: if trace then Nenue@6: return print Nenue@6: else Nenue@6: return function() end Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: --- Layout control metadata Nenue@6: local lastdb -- fallback if a table isn't found mid-operation Nenue@6: local ui_meta = { Nenue@6: beepkit = 15263, -- something to play when debugging Nenue@6: } Nenue@6: local ui_embeds = { Nenue@6: ['Frame'] = 'SetFrameLayout', Nenue@6: ['Texture'] = 'SetTextureLayout', Nenue@6: ['Font'] = 'SetFontLayout', Nenue@6: } Nenue@6: Nenue@6: --- Resolve a parent object from varying depths Nenue@6: -- @param self target object Nenue@6: -- @parent string/number name of global frame or number of GetParent() hops to make Nenue@6: -- @childKey index key to retrieve from the resolved parent object Nenue@6: local function ParentValue(self, parent, childKey) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: local relativeTo = parent Nenue@6: if type(parent) == 'number' then Nenue@6: print(cWord('* Parent Trace:'), cNum(parent), cKey(self:GetName())) Nenue@6: relativeTo = self:GetParent() Nenue@6: for i = 2, parent do Nenue@6: if relativeTo.GetParent and relativeTo:GetParent() ~= UIParent then Nenue@6: --@debug@ Nenue@6: print(' ', 'parent =', relativeTo:GetName()) Nenue@6: --@end-debug Nenue@6: local next = relativeTo:GetParent() Nenue@6: relativeTo = next Nenue@6: else Nenue@6: --@debug@ Nenue@6: print(' ',cWord(self:GetName()), 'parent =', cWord(parent)) Nenue@6: --@debug-end@ Nenue@6: end Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: -- This allows us to call for an immediate sub-frame and still get a usable value if it's not there Nenue@6: if childKey and relativeTo[childKey] then Nenue@6: return relativeTo[childKey] Nenue@6: end Nenue@6: return relativeTo Nenue@6: end Nenue@6: Nenue@6: --- Animations Nenue@6: F.animate_regions = {} Nenue@6: setmetatable(F.animate_regions, { Nenue@6: __newindex = function (t,k,v) Nenue@6: rawset(t,k,v) Nenue@6: v.animationID = k Nenue@6: F.SetAnimationGroup(v) Nenue@6: end Nenue@6: }) Nenue@6: Nenue@6: --- Constructs the generic status frame Nenue@6: function F:SetFrameLayout(c) Nenue@6: local print = GetPrint(c.trace) Nenue@6: self.trace = c.trace or self.trace Nenue@6: Nenue@6: self.db = c Nenue@6: self.labels = {} Nenue@6: Nenue@6: self.name = self:GetName() Nenue@6: self.combat = InCombatLockdown() Nenue@6: self:SetPoint(c.anchor, c.parent, c.anchorTo, c.x, c.y) Nenue@6: self:SetSize(c.width, c.height) Nenue@6: self:SetFrameStrata(c.strata) Nenue@6: self.throttle_rate = 0.010 Nenue@6: self.throttle_point = GetTime() Nenue@6: Nenue@6: if c.backdrop then Nenue@6: c.backdrop.edgeSize = c.padding*4 Nenue@6: self:SetBackdrop(c.backdrop) Nenue@6: end Nenue@6: if c.background_color and c.border_color then Nenue@6: self:SetBackdropColor(unpack(c.background_color)) Nenue@6: self:SetBackdropBorderColor(unpack(c.border_color)) Nenue@6: end Nenue@6: Nenue@6: --@debug@ Nenue@6: print(namef('SetFrameLayout'),'(', valuet(self:GetName()),')') Nenue@6: print(cText(' dimensions:'), cNum(c.width), 'by', cNum(c.height), '::', c.x, c.y, c.anchor, c.anchorTo, c.parent) Nenue@6: --@end-debug@ Nenue@6: Nenue@6: self.width = c.width Nenue@6: self.height = c.height Nenue@6: self.foreground_inset = c.foreground_inset Nenue@6: self.padding = c.padding Nenue@6: self.spacing = c.spacing Nenue@6: self.alpha = c.alpha Nenue@6: Nenue@6: self.combatFade = c.combatFade Nenue@6: self.alpha_fade_in = c.alpha_fade_in or c.alpha_fade Nenue@6: self.alpha_fade_out = c.alpha_fade_out or c.alpha_fade Nenue@6: print(' fade on combat =', self.combatFade) Nenue@6: for _, type in ipairs({'alpha', 'alpha_ooc'}) do Nenue@6: self[type] = c[type] Nenue@6: _G.print('DB', self:GetName(), type, self[type]) Nenue@6: for _, subtype in ipairs({'_passive', '_active'}) do Nenue@6: self[type..subtype] = c[type..subtype] or self[type] Nenue@6: _G.print('DB', self:GetName(), type..subtype, self[type..subtype]) Nenue@6: for _, subsubtype in ipairs({'_empty', '_half', '_full'}) do Nenue@6: self[type..subtype..subsubtype] = c[type..subtype..subsubtype] or self[type..subtype] Nenue@6: _G.print('DB', self:GetName(), type..subtype..subsubtype, self[type..subtype..subsubtype]) Nenue@6: self[type..subsubtype] = c[type..subsubtype] or self[type..subtype] Nenue@6: _G.print('DB', self:GetName(), type..subsubtype, self[type..subsubtype]) Nenue@6: end Nenue@6: end Nenue@6: end Nenue@6: self.UpdateAlpha = F.UpdateAlpha Nenue@6: --if c.combatFade then Nenue@6: self.faderID = #F.animate_regions+1 Nenue@6: F.animate_regions[#F.animate_regions+1] = self Nenue@6: print(cText(' animation target ID #'), cNum(self.faderID)) Nenue@6: --end Nenue@6: Nenue@6: self:UpdateAlpha(InCombatLockdown()) Nenue@6: Nenue@6: if self.lefttext then Nenue@6: print(' auto-lefttext') Nenue@6: F.SetFontLayout(self.lefttext, c.lefttext or c) Nenue@6: end Nenue@6: if self.righttext then Nenue@6: print(' auto-righttext') Nenue@6: F.SetFontLayout(self.righttext, c.righttext or c) Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: --- Seeds basic animations, else a template can be specified by the frame data Nenue@6: function F:SetAnimationGroup(group) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: group = group or self.animationClass or nil Nenue@6: --@debug@ Nenue@6: if not group then Nenue@6: print(' |cFFFF44AAseeding debug animations', self:GetName()) Nenue@6: self.__flash = self:CreateAnimationGroup(self:GetName()..'Flasher') Nenue@6: self.__flash:SetToFinalAlpha(true) Nenue@6: local fade1 = self.__flash:CreateAnimation('Alpha') Nenue@6: fade1:SetChange(-1) Nenue@6: fade1:SetDuration(.6) Nenue@6: fade1:SetOrder(1) Nenue@6: local fade2 = self.__flash:CreateAnimation('Alpha') Nenue@6: fade2:SetChange(1) Nenue@6: fade2:SetDuration(.6) Nenue@6: fade2:SetOrder(2) Nenue@6: fade2:SetEndDelay(.6) Nenue@6: --@debug@ Nenue@6: self.__flash.fade1 = fade1 Nenue@6: self.__flash.fade2 = fade2 Nenue@6: self.__flash:SetLooping('NONE') Nenue@6: self.__flash:SetScript('OnFinished', function() Nenue@6: print(self:GetName(), '[>>>] Done animating flash.') Nenue@6: self.flashing = nil Nenue@6: end)--@end-debug@ Nenue@6: self.Flash = F.Flash Nenue@6: Nenue@6: self.__fade = self:CreateAnimationGroup(self:GetName()..'Fader') Nenue@6: self.__fade:SetToFinalAlpha(true) Nenue@6: self.__fade:SetScript('OnFinished', function() Nenue@6: print(self:GetName(), '[>>>] Done animating fade.') Nenue@6: self.fading = nil Nenue@6: local a = self.__flash.fade1:GetToAlpha() Nenue@6: --self:SetAlpha(a) Nenue@6: if a == 0 and not self.__fade.noHide then Nenue@6: self:Hide() Nenue@6: end Nenue@6: if self.__fade.queuedFade then Nenue@6: print('[>>>] ', cWord(self:GetName())..'.'..cKey('__fade:'), 'starting queued fade') Nenue@6: local fadeTo, fadeDuration, noHide = unpack(self.__fade.queuedFade) Nenue@6: self.__fade.queuedFade = nil Nenue@6: self:Fade(fadeTo, fadeDuration, noHide) Nenue@6: end Nenue@6: end) Nenue@6: self.Fade = F.Fade Nenue@6: end Nenue@6: --@end-debug@ Nenue@6: if not self.animationID then Nenue@6: tinsert(F.animate_regions, self) -- uses rawset, so won't death loop Nenue@6: self.animationID = #F.animate_regions Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: function F:Flash(duration, peak, valley, holdUp, holdDown) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: local fl = self.__flash Nenue@6: print('[>>>]', self:GetName(), duration, peak, valley, holdUp, holdDown) Nenue@6: fl.fade1:SetFromAlpha(valley) Nenue@6: fl.fade1:SetToAlpha(peak) Nenue@6: fl.fade1:SetDuration(duration) Nenue@6: fl.fade1:SetEndDelay(holdUp) Nenue@6: fl.fade2:SetFromAlpha(peak) Nenue@6: fl.fade2:SetToAlpha(valley) Nenue@6: fl.fade2:SetDuration(duration) Nenue@6: fl.fade2:SetEndDelay(2) Nenue@6: self.flashing = true Nenue@6: fl:Play() Nenue@6: end Nenue@6: Nenue@6: --- Fade to a value; fading to 0 will hide the frame Nenue@6: function F:Fade(duration, fadeTo, noHide) Nenue@6: Nenue@6: print('|cFFFF6600[>>>]', cText('Fade('), self:GetName(), cText(')')) Nenue@6: local fader = self.__fade Nenue@6: local fade1 = self.__flash.fade1 Nenue@6: if fader:IsPlaying() then Nenue@6: self.__fade.queuedFade = {duration, fadeTo, noHide } Nenue@6: print(' ', cText('playing:'), cNum(fader:GetDuration())..'s', cNum(fade1:GetToAlpha())) Nenue@6: print(' ', cPink('queued {'), cNum(duration)..'s', cNum(self:GetAlpha()), 'to', cNum(fadeTo), '}') Nenue@6: return Nenue@6: else Nenue@6: print(' ', cNum('starting {'), cNum(duration), cNum(self:GetAlpha()), 'to', cNum(fadeTo), '}') Nenue@6: end Nenue@6: fade1:SetParent(fader) Nenue@6: fade1:SetFromAlpha(self:GetAlpha()) Nenue@6: fade1:SetToAlpha(fadeTo) Nenue@6: fade1:SetDuration(duration) Nenue@6: fade1:SetOrder(1) Nenue@6: self.__fade.noHide = noHide Nenue@6: self.fading = true Nenue@6: fader:Play() Nenue@6: end Nenue@6: Nenue@6: function F:Beep() Nenue@6: if self.quiet then Nenue@6: return Nenue@6: end Nenue@6: PlaySoundKitID(F.beepkit) -- random anub'rhekan sounds Nenue@6: end Nenue@6: Nenue@6: Nenue@6: --- Defines the corners used in filling operations Nenue@6: local directionBase = { Nenue@6: ['LEFT'] = 'TOPRIGHT', Nenue@6: ['RIGHT'] = 'TOPLEFT', Nenue@6: ['UP'] = 'BOTTOMLEFT', Nenue@6: ['DOWN'] = 'TOPLEFT' Nenue@6: } Nenue@6: local directionPeak ={ Nenue@6: ['LEFT'] = 'BOTTOMLEFT', Nenue@6: ['RIGHT'] = 'BOTTOMRIGHT', Nenue@6: ['UP'] = 'TOPRIGHT', Nenue@6: ['DOWN'] = 'BOTTOMRIGHT', Nenue@6: } Nenue@6: local directionPeakTo = { Nenue@6: ['LEFT'] = 'BOTTOMRIGHT', Nenue@6: ['RIGHT'] = 'BOTTOMLEFT', Nenue@6: ['UP'] = 'BOTTOMRIGHT', Nenue@6: ['DOWN'] = 'TOPRIGHT' Nenue@6: } Nenue@6: local anchorInverse = {['LEFT'] = 'RIGHT', ['RIGHT'] = 'LEFT', ['TOP'] = 'BOTTOM', ['BOTTOM'] = 'TOP' } Nenue@6: --- Directional coefficients for corner positions Nenue@6: -- [1] = end X, [2] = end Y, [3] = base X, [4] = base Y Nenue@6: local directionCoord = { Nenue@6: ['LEFT'] = {-1, 0, -1, -1}, Nenue@6: ['RIGHT'] = { 1, 0, 1, -1}, Nenue@6: ['UP'] = { 0, 1, 1, 1}, Nenue@6: ['DOWN'] = { 0, -1, 1, -1}, Nenue@6: ['CENTER'] = {.5, .5, 1, 1} Nenue@6: } Nenue@6: local paddingScale = { Nenue@6: ['UP'] = 1, Nenue@6: ['DOWN'] = -1, Nenue@6: ['LEFT'] = -1, Nenue@6: ['RIGHT'] = 1, Nenue@6: } Nenue@6: local embedScale = { Nenue@6: ['LEFT'] = {1, false}, Nenue@6: ['RIGHT'] = {-1, false}, Nenue@6: ['TOP'] = {false, -1}, Nenue@6: ['BOTTOM'] = {false, 1} Nenue@6: } Nenue@6: Nenue@6: --- Determines the correct relative X offset for a given progress ratio Nenue@6: --- x = 0 + padding + spacing + i, where i = {embedded | icon_size +spacing} Nenue@6: -- Factors padding and spacing parameters, including icon embedding dimensions. Nenue@6: -- @param self frame on which the foreground/background textures and config data exist Nenue@6: -- @param ratio progess from 0 to 1; 0 returns the starting corner coordinate, 1 returns end corner Nenue@6: -- @param scale overrides the pixel fill length, with starting corner used as scaling origin Nenue@6: local TranslateX = function(self, ratio, scale) Nenue@6: if not scale then Nenue@6: scale = self.fill_width Nenue@6: end Nenue@6: if self.fill_inverse then Nenue@6: ratio = 1 - ratio Nenue@6: end Nenue@6: _G.print('Update', 'dx', self.fill_x) Nenue@6: local x = Nenue@6: scale * ratio * directionCoord[self.fill_direction][1] Nenue@6: return min(x, scale) + self.fill_x Nenue@6: end Nenue@6: Nenue@6: --- Determines the correct relative Y offset for a given progress ratio Nenue@6: -- Factors padding and spacing parameters, including icon embedding dimensions. Nenue@6: -- @param self frame on which the foreground/background textures and config data exist Nenue@6: -- @param ratio progess from 0 to 1; 0 returns the starting corner coordinate, 1 returns end corner Nenue@6: -- @param scale overrides the pixel fill length, with starting corner used as scaling origin Nenue@6: local TranslateY = function(self, ratio, scale) Nenue@6: if not scale then Nenue@6: scale = self.fill_height Nenue@6: end Nenue@6: if self.fill_inverse then Nenue@6: ratio = 1 - ratio Nenue@6: end Nenue@6: Nenue@6: _G.print('Update', 'dy', self.fill_y) Nenue@6: -- (height of bar offset by the size of any overlapping element) * progress ratio, offset by the size of any overlapping embed + inset Nenue@6: local y = Nenue@6: scale * ratio * directionCoord[self.fill_direction][2] - self.foreground_inset Nenue@6: return min(y, scale) + self.fill_y Nenue@6: end Nenue@6: local SetProgress = function(self, progress, scaleX, scaleY) Nenue@6: _G.print('Update', cText(self:GetName()), Nenue@6: "\n d:", progress, 'dX:', directionCoord[self.fill_direction][1], 'dY:', directionCoord[self.fill_direction][2], 'dI:', self.fill_inverse, Nenue@6: "\n peak:", self.fill_anchor, self.fill_anchorTo, TranslateX(self, progress), TranslateY(self,progress)) Nenue@6: Nenue@6: self.foreground:SetPoint(self.fill_anchor, self.background, self.fill_anchorTo, TranslateX(self, progress, scaleX), TranslateY(self, progress, scaleY)) Nenue@6: end Nenue@6: Nenue@6: --- Assigns textures to the generic foreground background bar regions Nenue@6: -- Called as F.SetStatusTextures(MyFrame, config pointer) Nenue@6: -- foreground_inset - number of pixels by which the foreground edges occlude the background (basically always negative) Nenue@6: -- padding - number of pixels between the background edge and frame edge (basically always positive) Nenue@6: function F:SetStatusTextures(c) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: if c == nil then Nenue@6: c = self.db or lastdb Nenue@6: if not c then Nenue@6: error('No config table found') Nenue@6: end Nenue@6: end Nenue@6: local relativeTo = ParentValue(self, c.parent, c.parentKey) Nenue@6: Nenue@6: Nenue@6: self.fill_direction = c.fill_direction or 'RIGHT' Nenue@6: self.fill_inset = c.padding - c.foreground_inset -- foreground edge / frame edge Nenue@6: self.fill_width = self.width - self.fill_inset*2 -- foreground left / right edges Nenue@6: self.fill_height = self.height - self.fill_inset*2 -- " top / bottom " Nenue@6: self.fill_inverse = c.fill_inverse Nenue@6: self.fill_x, self.fill_y = 0, 0 Nenue@6: self.fill_insets = { Nenue@6: LEFT = self.fill_inset, Nenue@6: TOP = self.fill_inset, Nenue@6: BOTTOM = self.fill_inset, Nenue@6: RIGHT = self.fill_inset Nenue@6: } Nenue@6: Nenue@6: Nenue@6: -- create filling points Nenue@6: self.fill_base = directionBase[self.fill_direction] Nenue@6: self.fill_anchor = directionPeak[self.fill_direction] Nenue@6: self.fill_anchorTo = directionPeakTo[self.fill_direction] Nenue@6: print(" foreground:", self.fill_base, self.fill_base, TranslateX(self, 0), TranslateY(self, 0)) Nenue@6: print(" foreground fill:", self.fill_anchor, self.fill_anchorTo) Nenue@6: Nenue@6: -- calculate icon embed Nenue@6: if self.icon and self.icon.embedded then Nenue@6: print(cText('#### EMBED ####')) Nenue@6: -- change anchor point so the icon is inside Nenue@6: self.icon.anchor = self.icon.anchorTo Nenue@6: print(' * Icon anchor:' , cText(self.icon.anchor), 'to', cText(self.icon.anchorTo)) Nenue@6: print(' * Fill start:', cText(self.fill_base)) Nenue@6: Nenue@6: Nenue@6: local coordSet = {nil, nil} Nenue@6: local baseSet = {nil, nil } Nenue@6: local endSet = {nil, nil} Nenue@6: for dir, coords in pairs(embedScale) do Nenue@6: if self.icon.anchor:match(dir) then Nenue@6: print(' xtrans { matches', dir, 'include {', coords[1], coords[2], '}') Nenue@6: if not coordSet[1] then coordSet[1] = coords[1] end Nenue@6: if not coordSet[2] then coordSet[2] = coords[2] end Nenue@6: Nenue@6: -- the embedding position can overlap either corner Nenue@6: if self.fill_base:match(dir) then Nenue@6: print(' base corner also matches') Nenue@6: if not baseSet[1] then baseSet[1] = coords[1] end Nenue@6: if not baseSet[2] then baseSet[2] = coords[2] end Nenue@6: else Nenue@6: Nenue@6: if not endSet[1] then endSet[1] = coords[1] end Nenue@6: if not endSet[2] then endSet[2] = coords[2] end Nenue@6: end Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: -- make sure there are values if none of them matched at all for some reason Nenue@6: coordSet = {coordSet[1] or 0, coordSet[2] or 0} Nenue@6: baseSet = {baseSet[1] or 0, baseSet[2] or 0 } Nenue@6: -- needs to produce a negative number Nenue@6: endSet = {endSet[1] or 0, endSet[2] or 0 } Nenue@6: Nenue@6: Nenue@6: print(' == xtrans push =', unpack(coordSet)) Nenue@6: print(' == fbase delta =', unpack(baseSet)) Nenue@6: print(' == ftail delta =', unpack(endSet)) Nenue@6: Nenue@6: -- determine the foreground displacement Nenue@6: Nenue@6: self.icon_dx = (min(self.fill_width, self.fill_height) + self.spacing) Nenue@6: self.icon_dy = (min(self.fill_width, self.fill_height) + self.spacing) Nenue@6: print(' * Foreground compression:', cNum(self.icon_dx)) Nenue@6: Nenue@6: self.icon_size = self.icon.size Nenue@6: self.icon_x = self.padding * baseSet[1] - (self.icon.size - self.icon_dx) Nenue@6: self.icon_y = self.padding * baseSet[2] - (self.icon.size - self.icon_dy) Nenue@6: print(' * Icon dims:' , cNum(self.icon_size), ' offset:', cNum(self.icon_dx)) Nenue@6: Nenue@6: Nenue@6: local ofi = self.fill_insets[self.fill_direction] Nenue@6: print(' * Fill inset('..cWord(self.fill_direction)..') from', cNum(ofi), 'to', cNum(self.fill_insets[self.fill_direction])) Nenue@6: Nenue@6: -- used to place the starting corner Nenue@6: self.fill_x = (self.icon_dx) * baseSet[1] Nenue@6: self.fill_y = (self.icon_dy) * baseSet[2] Nenue@6: print(' * fill offset dX:', self.fill_x) Nenue@6: print(' * fill offset dY:', self.fill_y) Nenue@6: Nenue@6: -- amount taken off of fill scale, subtract spacing Nenue@6: self.icon_dx_cut = abs(self.icon_dx * -baseSet[1]) Nenue@6: self.icon_dy_cut = abs(self.icon_dy * -baseSet[2]) Nenue@6: Nenue@6: local ofw, ofh = self.fill_width, self.fill_height Nenue@6: self.fill_width = self.fill_width - self.icon_dx_cut Nenue@6: self.fill_height = self.fill_height - self.icon_dy_cut Nenue@6: print(' * Scale dX:', self.icon_dx_cut, cNum(ofw), 'to', cNum(self.fill_width)) Nenue@6: print(' * Scale dY:', self.icon_dy_cut, cNum(ofh), 'to', cNum(self.fill_height)) Nenue@6: Nenue@6: self.icon:ClearAllPoints() Nenue@6: self.icon:SetPoint(self.icon.anchor, self, self.icon.anchorTo, self.icon_x, self.padding * coordSet[2]) Nenue@6: self.icon:SetSize(self.icon_size, self.icon_size) Nenue@6: end Nenue@6: Nenue@6: --@debug@ Nenue@6: print(namet('SetStatusTextures'),'(', valuef(self:GetName()), ')') Nenue@6: print(' form:', self.padding,'-', self.foreground_inset, '+', self.fill_width, self.padding,'-', self.foreground_inset, '+','x', self.padding,'-', self.foreground_inset, '+', self.fill_height, self.padding,'-', self.foreground_inset, '+') Nenue@6: print(' ', valuen(concat(c.background_color,', ')),valuet(c.background_texture), valuen(concat(c.foreground_color,', ')), valuet(c.foreground_texture)) Nenue@6: print(' background:', self.padding, self.padding, 'BOTTOMLEFT', 'BOTTOMLEFT' , '::', -self.padding, -self.padding, 'TOPRIGHT', 'TOPRIGHT') Nenue@6: --@end-debug@ Nenue@6: Nenue@6: self.background:ClearAllPoints() Nenue@6: self.background:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', self.padding, self.padding) Nenue@6: self.background:SetPoint('TOPRIGHT', self, 'TOPRIGHT', -self.padding, -self.padding) Nenue@6: if c.background_texture ~= '' and c.background_texture ~= nil then Nenue@6: self.background:SetTexture(c.background_texture) Nenue@6: self.background:SetVertexColor(unpack(c.background_color)) Nenue@6: else Nenue@6: self.background:SetTexture(unpack(c.background_color)) Nenue@6: end Nenue@6: self.background:SetBlendMode(c.background_blend) Nenue@6: Nenue@6: if c.foreground_texture ~= '' and c.foreground_texture ~= nil then Nenue@6: self.foreground:SetTexture(c.foreground_texture) Nenue@6: self.foreground:SetVertexColor(unpack(c.foreground_color)) Nenue@6: else Nenue@6: self.foreground:SetTexture(unpack(c.foreground_color)) Nenue@6: end Nenue@6: self.foreground:SetBlendMode(c.foreground_blend) Nenue@6: Nenue@6: self.foreground:ClearAllPoints() Nenue@6: local dx = (directionCoord[self.fill_direction][3] * -self.foreground_inset) + self.fill_x Nenue@6: local dy = (directionCoord[self.fill_direction][4] * -self.foreground_inset) + self.fill_y Nenue@6: print(' foreground base:', cNum(dx), cNum(dy)) Nenue@6: self.foreground:SetPoint(self.fill_base, self.background, self.fill_base, dx, dy) Nenue@6: Nenue@6: SetProgress(self, 1) Nenue@6: Nenue@6: self.TranslateX = TranslateX Nenue@6: self.TranslateY = TranslateY Nenue@6: self.SetFillPoints = SetFillPoints Nenue@6: self.SetProgress = SetProgress Nenue@6: end Nenue@6: --- Sets properties for a generated FontString Nenue@6: -- Takes the FontString object as a self, and applies config values. Nenue@6: -- In particalur, the anchor parent is derived from either a fixed number of GetParent() or global name Nenue@6: -- @usage Region:SetFontLayout([table]) Nenue@6: function F:SetFontLayout (c) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: if c == nil then Nenue@6: c = lastdb Nenue@6: if not c then Nenue@6: error('No config table found') Nenue@6: end Nenue@6: end Nenue@6: local relativeTo = ParentValue(self, c.parent, c.parentKey) Nenue@6: Nenue@6: --@debug@ Nenue@6: print(namet('FontLayout'),'(', valuet(self:GetName()), ')', valuet(c.font), valuet(c.size), valuet(c.outline)) Nenue@6: print(' ', valuen(c.anchor or 'CENTER'), relativeTo:GetName(), valuen(c.anchorTo or 'CENTER'), valued(c.x or 0), Nenue@6: valued(c.y or 0)) Nenue@6: --@end-debug@ Nenue@6: self:SetPoint( Nenue@6: c.anchor or 'CENTER', Nenue@6: relativeTo, Nenue@6: c.anchorTo or 'CENTER', Nenue@6: c.x or 0, Nenue@6: c.y or 0) Nenue@6: self:SetSize( Nenue@6: c.width or relativeTo:GetWidth(), Nenue@6: c.height or relativeTo:GetHeight()) Nenue@6: self:SetFont( Nenue@6: c.font, Nenue@6: c.size, Nenue@6: c.outline) Nenue@6: self:SetJustifyH(c.justifyH or 'CENTER') Nenue@6: self:SetJustifyV(c.justifyV or 'MIDDLE') Nenue@6: self:SetTextColor(unpack(c.text_color or {1,1,1,1})) Nenue@6: end Nenue@6: Nenue@6: --- For setting up widget pieces Nenue@6: function F:SetTextureLayout(c) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: if c == nil then Nenue@6: c = lastdb Nenue@6: if not c then Nenue@6: error('No config table found') Nenue@6: end Nenue@6: end Nenue@6: local relativeTo = ParentValue(self, c.parent, c.parentKey) Nenue@6: Nenue@6: self.size = c.size Nenue@6: self.width = c.width Nenue@6: self.height = c.height Nenue@6: self.x = c.x Nenue@6: self.y = c.y Nenue@6: self.embedded = c.embedded Nenue@6: self.anchor = c.anchor Nenue@6: self.anchorTo = c.anchorTo Nenue@6: Nenue@6: self:SetPoint(c.anchor, relativeTo, c.anchorTo, c.x, c.y) Nenue@6: self:SetSize(c.size or c.width, c.size or c.height) Nenue@6: self:SetAlpha(c.alpha) Nenue@6: self:SetDesaturated(c.desaturated or false) Nenue@6: print('|cFF00FFFFSetTextureLayout(|r', self:GetName(), '|cFF00FFFF)|r') Nenue@6: print(' ', c.anchor, relativeTo, c.anchorT, c.x, c.v) Nenue@6: if c.combatFade and not (relativeTo.faderID and F.animate_regions[relativeTo.faderID]) then Nenue@6: tinsert(F.animate_regions, self) Nenue@6: self.faderID = #F.animate_regions Nenue@6: --@debug@ Nenue@6: print('register fadeable texture #'..self.faderID) Nenue@6: --@end-debug@ Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: local alphaSubType = { Nenue@6: [1] = '_passive', Nenue@6: [2] = '_active' Nenue@6: } Nenue@6: local alphaFillType = { Nenue@6: [1] = '_empty', Nenue@6: [2] = '_half', Nenue@6: [3] = '_full', Nenue@6: } Nenue@6: function F:UpdateAlpha(inCombat, displayState, fillState) Nenue@6: local print = function() end Nenue@6: print(cWord('UpdateAlpha(')..self:GetName()..cWord(')')) Nenue@6: local alphaType = inCombat and 'alpha' or 'alpha_ooc' Nenue@6: local alphaDuration = inCombat and 'alpha_fade_in' or 'alpha_fade_out' Nenue@6: local displayState = displayState or self.displayState or nil Nenue@6: local fillState = fillState or self.fillState or nil Nenue@6: Nenue@6: local alphaSubType = '' Nenue@6: if displayState then Nenue@6: alphaSubType = (displayState == 1) and '_passive' or ((displayState == 2) and '_active' or '' ) Nenue@6: end Nenue@6: Nenue@6: local alphaFillType = '' Nenue@6: if fillState then Nenue@6: alphaFillType = (fillState == 1) and '_half' or ((fillState == 2) and '_full' or '_empty') Nenue@6: end Nenue@6: Nenue@6: local fadeTo = self[alphaType..alphaSubType..alphaFillType] Nenue@6: local fadeDuration = self[alphaDuration] or 0 Nenue@6: print(' alphaKey:', cWord(alphaType..alphaSubType..alphaFillType)) Nenue@6: print(' alphaTo:', cNum(fadeTo), 'duration:', cNum(fadeDuration)) Nenue@6: if self:IsVisible() and fadeDuration ~= 0 then Nenue@6: self:Fade(fadeDuration, fadeTo or (inCombat and 1 or 0.5), true) Nenue@6: print(' |cFFFFFF00 :Fade()|r', 'dur='..cNum(fadeDuration), cNum(fadeTo), cWord(self:GetName())) Nenue@6: else Nenue@6: self:SetAlpha(fadeTo) Nenue@6: print(' |cFF00FF00 :SetAlpha('..fadeTo..')|r', cText(self:GetName())) Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: --- Sets an OnUpdate within a time-throttled wrapper Nenue@6: -- throttle rate should be slightly smaller than 1/average frame rate Nenue@6: function F:SetFrameScript(updateFunc, showFunc, hideFunc, ...) Nenue@6: local print = GetPrint(self.trace) Nenue@6: Nenue@6: if not self.__oldscripts then Nenue@6: self.__oldscripts = {} Nenue@6: end Nenue@6: Nenue@6: self:SetScript('OnUpdate', nil) -- clear any scripts Nenue@6: self:SetSCript('OnUpdate', function(self) Nenue@6: if GetTime() < self.throttle_time then Nenue@6: return Nenue@6: end Nenue@6: self.throttle_time = self.throttle_time + self.throttle_rate Nenue@6: updateFunc(self) Nenue@6: end) -- put the new function in its place Nenue@6: local changeSet = { Nenue@6: { self.__oldscripts,onUpdate = self:GetScript('OnUpdate') }, Nenue@6: } Nenue@6: Nenue@6: if showFunc then Nenue@6: tinsert(changeSet, Nenue@6: {onShow = self:GetScript('OnShow')}) Nenue@6: self:SetScript('OnShow', showFunc) Nenue@6: end Nenue@6: Nenue@6: if hideFunc then Nenue@6: tinsert(changeSet, Nenue@6: {onHide = self:GetScript('OnShow')}) Nenue@6: self:SetScript('OnHide', hideFunc) Nenue@6: end Nenue@6: end Nenue@6: Nenue@6: --- Embed Nenue@6: function F:Embed(object) Nenue@6: print('Doing embed') Nenue@6: for k, v in pairs(ui_embeds) do Nenue@6: print('embedding Set'..k..'Layout') Nenue@6: object['Set'..k..'Layout'] = self[v] Nenue@6: end Nenue@6: object.SetStatusTextures = self.SetStatusTextures Nenue@6: Nenue@6: --- map a generic layout method if embedded into a frame object Nenue@6: if object.GetObjectType and ui_embeds[object.GetObjectType()] then Nenue@6: if ui_embeds[object.GetObjectType()] then Nenue@6: object.SetLayout = ui_embeds[object.GetObjectType()] Nenue@6: end Nenue@6: end Nenue@6: end