Nenue@0: --- Modulizer framework Nenue@0: -- OnInitialize Nenue@0: -- OnUpdate Nenue@0: -- OnEnable -- run when GetSpecialization() returns true Nenue@0: Nenue@0: local ADDON, A = ... Nenue@0: Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent) Nenue@0: local B = Veneer Nenue@3: local wipe, min, max, random, tinsert, tremove = table.wipe, math.min, math.max, math.random, table.insert, table.remove Nenue@0: local pairs, ipairs, select, unpack, _G = pairs, ipairs, select, unpack, _G Nenue@0: local type, tostring, format = type, tostring, string.format Nenue@0: A.frame = B Nenue@0: Nenue@0: --- Cache tables Nenue@0: local initOnced Nenue@0: local modules = {} Nenue@0: local queuedModules = {} Nenue@3: local checkForConfig = {} Nenue@0: local moduleStack = { Nenue@0: } Nenue@0: Nenue@0: --- Various region categories Nenue@0: B.displays = {} Nenue@0: B.configLayers = {} Nenue@0: B.configLayersRef = {} Nenue@0: Nenue@0: --@debug@ Nenue@0: --- Generates a print handler pointing to a static channel signature Nenue@0: -- @usage func = B.print(sig) Nenue@0: -- @param sig channel name or number Nenue@0: local printfuncs = {} Nenue@0: B.print = function(pref, ...) Nenue@0: if Devian and Devian.InWorkspace() then Nenue@0: printfuncs[pref] = printfuncs[pref] or function(...) print(pref, ...) end Nenue@0: Nenue@0: return printfuncs[pref] Nenue@0: else Nenue@0: return function () end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: local rgb = {} Nenue@0: local getcolor = function() Nenue@0: local n, p = 0, 4 Nenue@0: for i = 1, 3 do Nenue@0: rgb[i] = min(random(n,p) * 64, 255) Nenue@0: if rgb[i] == 255 then Nenue@0: p = 4 Nenue@0: elseif rgb[i] > 0 then Nenue@0: n = 2 Nenue@0: end Nenue@0: end Nenue@0: return unpack(rgb) Nenue@0: end Nenue@0: Nenue@0: local color = {} Nenue@0: local fprints = {} Nenue@0: B.fprint = function() Nenue@0: if not (Devian and Devian.InWorkspace()) then Nenue@0: return function() end Nenue@0: end Nenue@0: Nenue@0: Nenue@0: local sig = debugstack(2,1) Nenue@0: if fprints[sig] then Nenue@0: return fprints[sig] Nenue@0: end Nenue@0: Nenue@0: local func = sig:match("%`(%a+)%'") Nenue@0: if not func then Nenue@0: func = sig:match("<(.-)>") Nenue@0: end Nenue@0: func = func:gsub('(%l+)(%u)', function(a, b) return a:sub(0,2) .. b end, 1) Nenue@0: func = func:gsub('^.+%\\', '') Nenue@0: if not func then Nenue@0: func = 'noname' Nenue@0: end Nenue@0: Nenue@0: local r, g, b = getcolor() Nenue@0: color[sig] = color[sig] or format('|cFF%02X%02X%02X%s|r', r, g, b, func) Nenue@0: Nenue@0: --print(color[func] .. ' ( ' .. table.concat(args, ', ')..' )' ) Nenue@0: func = B.print(func) Nenue@0: fprints[sig] = func Nenue@0: return func Nenue@0: end Nenue@0: Nenue@0: --@end-debug@ Nenue@0: --[=[@non-debug@ Nenue@0: B.print = function() end Nenue@0: --@end-non-debug@]=] Nenue@0: Nenue@0: -- for the Mikk script Nenue@0: -- GLOBALS: NUM_LE_RAID_BUFF_TYPES Nenue@0: -- GLOBALS: BUFF_FLASH_TIME_ON, BUFF_FLASH_TIME_OFF, BUFF_MIN_ALPHA, BUFF_WARNING_TIME, BUFF_DURATION_WARNING_TIME Nenue@0: -- GLOBALS: BUFFS_PER_ROW, BUFF_MAX_DISPLAY, BUFF_ACTUAL_DISPLAY, DEBUFF_MAX_DISPLAY, DEBUFF_ACTUAL_DISPLAY, BUFF_ROW_SPACING Nenue@0: -- GLOBALS: CONSOLIDATED_BUFFS_PER_ROW, CONSOLIDATED_BUFF_ROW_HEIGHT, NUM_TEMP_ENCHANT_FRAMES Nenue@0: -- GLOBALS: BUFF_BUTTON_HEIGHT, BUFF_FRAME_BASE_EXTENT, BUFF_HORIZ_SPACING Nenue@0: Nenue@0: local print = B.print('Bfl') Nenue@0: Nenue@0: --- Template for making perpendicular traversals of the displays structure; also makes sure the table is there Nenue@0: B.Abstract = function(dest, key, table) Nenue@0: if table then Nenue@0: for _, v in pairs(dest) do Nenue@0: v[key] = {} Nenue@0: end Nenue@0: end Nenue@0: B[key] = setmetatable({}, { Nenue@0: __index = function(t, k) Nenue@0: return dest[k][key] Nenue@0: end, Nenue@0: __newindex = function(_, k, v) Nenue@0: print('abstract write ('..key..'):', k) Nenue@0: dest[k][key] = v Nenue@0: end, Nenue@0: __tostring = function() return 'Abstract:'..key..'' end Nenue@0: }) Nenue@0: Nenue@0: Nenue@0: return B[key] Nenue@0: end Nenue@0: Nenue@0: Nenue@0: --- localize for speed Nenue@0: local layers, refs, displays = B.configLayers, B.configLayersRef, B.displays Nenue@0: Nenue@0: local ModulesCall = function(func) Nenue@0: Nenue@0: local n = 0 Nenue@0: for i = 1, #moduleStack do Nenue@0: print('calling level '..i) Nenue@0: local stackset = moduleStack[i] Nenue@0: Nenue@0: for name, module in pairs(stackset) do Nenue@0: n = n + 1 Nenue@0: print(n..' '..name..'.'..func..'()') Nenue@0: Nenue@0: Nenue@0: if module[func] then Nenue@0: module[func](module) Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: Nenue@0: local Enable = function() Nenue@0: end Nenue@0: Nenue@0: --- The things that happen repeatedly Nenue@0: local Init = function () Nenue@0: end Nenue@0: Nenue@0: Nenue@0: --- Things that happen immediately upon entering world Nenue@0: local InitOnce = function() Nenue@0: print('entering world first time') Nenue@0: local defaults = B.ConfDefaults Nenue@0: print('|cFFFFFF00Veneer|r') Nenue@0: if not VeneerData then Nenue@0: VeneerData = {} Nenue@0: for k,v in pairs(defaults) do Nenue@0: VeneerData[k] = v Nenue@0: end Nenue@0: print('Veneer defaults being used.') Nenue@0: end Nenue@0: Nenue@0: B.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] end}) Nenue@0: Nenue@0: -- suffix tables Nenue@0: for name, display in pairs(displays) do Nenue@0: display.conf = setmetatable({}, { Nenue@0: __index = function(_, k) Nenue@0: --print('config check '.. name .. k) Nenue@0: return B.Conf[name .. k] or B.Conf['BuffButton' .. k] Nenue@0: end, Nenue@0: __newindex = function(_, k , v) Nenue@0: B.Conf[name..k] = v Nenue@0: end, Nenue@0: }) Nenue@0: end Nenue@0: Nenue@0: -- To ensure that modules are run in controlled order, walk the dependency list; if the dep shows up Nenue@0: -- in the loaded manifest, remove the value. If the dep list isn't empty, move that module to the next Nenue@0: -- layer. Nenue@0: local loaded = {} Nenue@0: local stackLevels = #moduleStack Nenue@0: local i = 1 Nenue@0: moduleStack[1] = modules Nenue@0: repeat Nenue@0: print('setting init level '.. i) Nenue@0: local queue = moduleStack[i] Nenue@0: for name, module in pairs(queue) do Nenue@0: Nenue@0: if queuedModules[name] and #queuedModules[name] > 0 then Nenue@0: local p = #queuedModules[name] Nenue@0: for j = 1, p do Nenue@0: local dep = queuedModules[name][j] Nenue@0: Nenue@0: if loaded[dep] then Nenue@0: print( ' ' .. dep .. ' OK') Nenue@0: queuedModules[name][j] = nil Nenue@0: for k = j, p do Nenue@0: print(' shift ' .. (k+1) .. ' ('..tostring(queuedModules[name][k+1])..') to ' .. k ..'') Nenue@0: queuedModules[name][k] = queuedModules[name][k+1] Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: if #queuedModules[name] == 0 then Nenue@0: queuedModules[name] = nil Nenue@0: print(' |cFF00FFFF'.. name ..'|r deps OK') Nenue@0: loaded[name] = true Nenue@0: else Nenue@0: Nenue@0: print(' |cFFFF8800' .. name ..'|r pending') Nenue@0: local next = i+1 Nenue@0: if not moduleStack[next] then Nenue@0: moduleStack[next] = {} Nenue@0: end Nenue@0: stackLevels = next Nenue@0: moduleStack[next][name] = module Nenue@0: queue[name] = nil Nenue@0: end Nenue@0: Nenue@0: else Nenue@0: print(' |cFF00FF00'.. name ..'|r no deps') Nenue@0: loaded[name] = true Nenue@0: end Nenue@0: end Nenue@0: i = i + 1 Nenue@0: until i > stackLevels Nenue@0: Nenue@0: Nenue@0: for level, batch in ipairs(moduleStack) do Nenue@0: print('config level', level) Nenue@0: for name, module in pairs(batch) do Nenue@0: print('integrity check', name) Nenue@0: Nenue@0: --[===[@non-debug@ Nenue@0: if module.defaults and not VeneerData[name] then Nenue@0: --@end-non-debug@]===] Nenue@0: print('Adding defaults from module ', name) Nenue@0: VeneerData[name] = module.default Nenue@0: --[===[@non-debug@ Nenue@0: end Nenue@0: --@end-non-debug@]===] Nenue@0: end Nenue@0: end Nenue@3: Nenue@3: Nenue@3: if #checkForConfig >= 1 then Nenue@3: local queuedFrame = tremove(checkForConfig) Nenue@3: while queuedFrame do Nenue@3: B.SetConfigLayers(queuedFrame) Nenue@3: B.InitXMLFrame(queuedFrame) Nenue@3: queuedFrame = tremove(checkForConfig) Nenue@3: end Nenue@3: end Nenue@0: -- remove from existing Nenue@0: end Nenue@0: Nenue@0: --- Fires an update to all modules Nenue@0: local lastUpdate Nenue@0: function B.UpdateAll(...) Nenue@0: lastUpdate = GetTime() Nenue@0: ModulesCall('OnUpdate', lastUpdate) Nenue@0: end Nenue@0: Nenue@0: B:RegisterEvent('PLAYER_ENTERING_WORLD') Nenue@0: B:SetScript('OnEvent', function(self, event) Nenue@0: if event == 'PLAYER_ENTERING_WORLD' then Nenue@0: if not initOnced then Nenue@0: InitOnce() Nenue@0: ModulesCall('OnInitialize') Nenue@0: initOnced = true Nenue@0: C_Timer.After(1, function() Nenue@0: if GetSpecialization() then Nenue@0: print(GetSpecialization(), 'enabling') Nenue@0: ModulesCall('OnEnable') Nenue@0: B:SetScript('OnUpdate', nil) Nenue@0: end Nenue@0: Nenue@0: end) Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: Nenue@0: B.UpdateAll() Nenue@0: end) Nenue@0: Nenue@0: --- Modulizer method Nenue@0: -- Nenue@0: function B:RegisterModule (name, module, ...) Nenue@0: if modules[name] then Nenue@0: print('pulling modules[|cFFFF8800'.. tostring(name) ..'|r]') Nenue@0: return modules[name] Nenue@0: end Nenue@0: Nenue@0: print('new module |cFF00BBFF'.. tostring(name) ..'|r') Nenue@0: if module then Nenue@0: if modules[name] then Nenue@0: error("Module table for '"..tostring(name).."' already exists.") Nenue@0: end Nenue@0: else Nenue@0: module = CreateFrame('Frame', 'Veneer' .. tostring(name) .. 'Handler', B, 'VeneerHandlerTemplate') Nenue@0: end Nenue@0: modules[name] = module Nenue@3: B[name] = module Nenue@0: if select('#', ...) >= 1 then Nenue@0: local numDeps = select('#', ...) Nenue@0: print(' '..numDeps..' deps detected') Nenue@0: for i = 1, numDeps do Nenue@0: local dep = select(i, ...) Nenue@0: -- means that init/enable funcs are ordered to run after deps do their things Nenue@0: queuedModules[name] = queuedModules[name] or {} Nenue@0: tinsert(queuedModules[name], dep) Nenue@0: print(' needs '..dep) Nenue@0: end Nenue@0: end Nenue@0: return module Nenue@0: end Nenue@0: Nenue@0: Nenue@0: B.SetConfigLayers = function(frame) Nenue@0: local print = B.fprint() Nenue@0: if not frame.config then Nenue@0: print(frame:GetName(), 'has no config layers') Nenue@0: return Nenue@0: end Nenue@0: print('Registering config layers from', frame:GetName()) Nenue@0: Nenue@0: for i, subframe in ipairs(frame.config) do Nenue@0: -- make sure there are no duplicates Nenue@0: if not refs[subframe] then Nenue@0: local key = #layers+1 Nenue@0: layers[key] = subframe Nenue@0: refs[subframe] = key Nenue@0: end Nenue@0: print(' ', i, subframe:GetName()) Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: B.RemoveConfigLayers = function(frame) Nenue@3: Nenue@0: local print = B.fprint() Nenue@0: print('|cFFFF0000RemoveConfigLayers', frame:GetName()) Nenue@0: for i, subframe in pairs(layers) do Nenue@0: if subframe:GetParent() == frame then Nenue@0: print('|cFFFF8800 ', subframe:GetParent():GetName(), '|cFFFFFF00', subframe:GetName()) Nenue@0: layers[i]:Hide() Nenue@0: layers[i] = nil Nenue@0: refs[subframe] = nil Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: B.UpdateConfigLayers = function() Nenue@0: local print = B.fprint() Nenue@0: local func = B.Conf.GuidesMode and 'Show' or 'Hide' Nenue@0: local numAnchors = 0 Nenue@0: for name, display in pairs(displays) do Nenue@0: numAnchors = numAnchors + 1 Nenue@0: display.anchor:EnableMouse(B.Conf.GuidesMode) Nenue@0: if B.Conf.GuidesMode then Nenue@0: display.anchor:SetScript('OnUpdate', display.anchor.OnUpdate) Nenue@0: else Nenue@0: display.anchor:SetScript('OnUpdate', nil) Nenue@0: Nenue@0: for i, anchorButton in ipairs(display.anchor.anchorButton) do Nenue@0: anchorButton:Hide() Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: for id, region in pairs(layers) do Nenue@0: print(id, region:GetName(), func) Nenue@0: region[func](region) Nenue@0: end Nenue@0: Nenue@0: print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames') Nenue@3: end Nenue@3: Nenue@3: --- Generic handlers for keeping track of XML-defined frames Nenue@3: B.OnLoad = function(self) Nenue@3: tinsert(checkForConfig, self) Nenue@3: end Nenue@3: Nenue@3: B.InitXMLFrame = function(self) Nenue@3: print('|cFF00FF00hello from '..self:GetName()) Nenue@3: Nenue@3: self:RegisterForDrag('LeftButton') Nenue@3: if not B.Conf.FramePosition then Nenue@3: B.Conf.FramePosition = {} Nenue@3: end Nenue@3: if B.Conf.FramePosition[self:GetName()] then Nenue@3: print('restoring frame position', unpack(B.Conf.FramePosition[self:GetName()])) Nenue@3: self:ClearAllPoints() Nenue@3: local anchorTo, relativePoint, x, y = unpack(B.Conf.FramePosition[self:GetName()]) Nenue@3: self:SetPoint(anchorTo, UIParent, relativePoint, x, y) Nenue@3: end Nenue@3: end Nenue@3: Nenue@3: B.OnDragStart = function(self) Nenue@3: self.xA = self:GetLeft() Nenue@3: self.yA = self:GetBottom() Nenue@3: self.anchorTo, self.relativeTo, self.relativePoint, self.x, self.y = self:GetPoint(1) Nenue@3: print('acquire anchor', self:GetPoint(1)) Nenue@3: print(self:GetName(), 'start moving ('..self.x..', '..self.y..')') Nenue@3: self:StartMoving() Nenue@3: end Nenue@3: Nenue@3: B.OnDragStop = function(self) Nenue@3: print(self:GetName(), 'stop moving ('..self:GetLeft()..', '..self:GetBottom()..')') Nenue@3: local xB = self:GetLeft() - self.xA Nenue@3: local yB = self:GetBottom() - self.yA Nenue@3: print('storing anchor point', self.anchorTo, self.relativePoint, self.x + xB, self.y + yB) Nenue@3: Nenue@3: self:StopMovingOrSizing() Nenue@3: B.Conf.FramePosition[self:GetName()] = {self.anchorTo, self.relativePoint, self.x + xB, self.y + yB} Nenue@3: B.InitXMLFrame(self) Nenue@3: Nenue@0: end