Mercurial > wow > buffalo2
view Init.lua @ 37:e84d645c8ab8
- revised the tracker update function to build its complete data list up front and use the values as points of comparison for determining possible out of place blocks, which will be iterated over afterward to remove what wasn't re-used
- also entailed revising the exact role of global event handlers and function hooks, limiting their directions of communication so one doesn't end up calling the other multiple or inifinity times
- schema handling polish
author | Nenue |
---|---|
date | Mon, 18 Apr 2016 07:56:23 -0400 |
parents | 66b927b46776 |
children | 1f8f9cc3d956 |
line wrap: on
line source
--- Modulizer framework -- OnInitialize -- OnUpdate -- OnEnable -- run when GetSpecialization() returns true local ADDON, A = ... Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent) local B = Veneer local wipe, min, max, random, tinsert, tremove = table.wipe, math.min, math.max, math.random, table.insert, table.remove local pairs, ipairs, select, unpack, _G = pairs, ipairs, select, unpack, _G local type, tostring, format = type, tostring, string.format A.frame = B --- Cache tables local initOnced local modules = {} local queuedModules = {} local checkForConfig = {} local moduleStack = { } --- Utilities B.wipeall = function (...) for i = 1, select('#', ...) do wipe(select(i, ...)) end end --- Various region categories B.displays = {} B.configLayers = {} B.configLayersRef = {} --@debug@ --- Generates a print handler pointing to a static channel signature -- @usage func = B.print(sig) -- @param sig channel name or number local printfuncs = {} B.print = function(pref, ...) if Devian and Devian.InWorkspace() then printfuncs[pref] = printfuncs[pref] or function(...) print(pref, ...) end return printfuncs[pref] else return function () end end end local rgb = {} local getcolor = function() local n, p = 0, 4 for i = 1, 3 do rgb[i] = min(random(n,p) * 64, 255) if rgb[i] == 255 then p = 4 elseif rgb[i] > 0 then n = 2 end end return unpack(rgb) end local color = {} local fprints = {} B.fprint = function() if not (Devian and Devian.InWorkspace()) then return function() end end local sig = debugstack(2,1) if fprints[sig] then return fprints[sig] end local func = sig:match("%`(%a+)%'") if not func then func = sig:match("<(.-)>") end func = func:gsub('(%l+)(%u)', function(a, b) return a:sub(0,2) .. b end, 1) func = func:gsub('^.+%\\', '') if not func then func = 'noname' end local r, g, b = getcolor() color[sig] = color[sig] or format('|cFF%02X%02X%02X%s|r', r, g, b, func) --print(color[func] .. ' ( ' .. table.concat(args, ', ')..' )' ) func = B.print(func) fprints[sig] = func return func end --@end-debug@ --[=[@non-debug@ B.print = function() end --@end-non-debug@]=] -- for the Mikk script -- GLOBALS: NUM_LE_RAID_BUFF_TYPES -- GLOBALS: BUFF_FLASH_TIME_ON, BUFF_FLASH_TIME_OFF, BUFF_MIN_ALPHA, BUFF_WARNING_TIME, BUFF_DURATION_WARNING_TIME -- GLOBALS: BUFFS_PER_ROW, BUFF_MAX_DISPLAY, BUFF_ACTUAL_DISPLAY, DEBUFF_MAX_DISPLAY, DEBUFF_ACTUAL_DISPLAY, BUFF_ROW_SPACING -- GLOBALS: CONSOLIDATED_BUFFS_PER_ROW, CONSOLIDATED_BUFF_ROW_HEIGHT, NUM_TEMP_ENCHANT_FRAMES -- GLOBALS: BUFF_BUTTON_HEIGHT, BUFF_FRAME_BASE_EXTENT, BUFF_HORIZ_SPACING local print = B.print('Bfl') --- Template for making perpendicular traversals of the displays structure; also makes sure the table is there B.Abstract = function(dest, key, table) if table then for _, v in pairs(dest) do v[key] = {} end end B[key] = setmetatable({}, { __index = function(t, k) return dest[k][key] end, __newindex = function(_, k, v) print('abstract write ('..key..'):', k) dest[k][key] = v end, __tostring = function() return 'Abstract:'..key..'' end }) return B[key] end --- localize for speed local layers, refs, displays = B.configLayers, B.configLayersRef, B.displays local ModulesCall = function(func, flag) local n = 0 for i = 1, #moduleStack do print('calling level '..i) local stackset = moduleStack[i] for name, module in pairs(stackset) do n = n + 1 if module[func] then -- nil = pass if not flag or module.Conf[flag] then if (flag) then print(' check', flag, '=', module.Conf[flag]) end print(' ',n..' '..name..'.'..func..'()') module[func](module, module.Conf) end end end end end local Enable = function() end --- The things that happen repeatedly local Init = function () end --- Things that happen immediately upon entering world local InitOnce = function() print('entering world first time') local defaults = B.ConfDefaults print('|cFFFFFF00Veneer|r') if not VeneerData then VeneerData = {} for k,v in pairs(defaults) do VeneerData[k] = v end print('Veneer defaults being used.') end B.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] end}) -- suffix tables for name, display in pairs(displays) do display.conf = setmetatable({}, { __index = function(_, k) --print('config check '.. name .. k) return B.Conf[name .. k] or B.Conf['BuffButton' .. k] end, __newindex = function(_, k , v) B.Conf[name..k] = v end, }) end -- To ensure that modules are run in controlled order, walk the dependency list; if the dep shows up -- in the loaded manifest, remove the value. If the dep list isn't empty, move that module to the next -- layer. local loaded = {} local stackLevels = #moduleStack local i = 1 moduleStack[1] = modules repeat print('setting init level '.. i) local queue = moduleStack[i] for name, module in pairs(queue) do if queuedModules[name] and #queuedModules[name] > 0 then local p = #queuedModules[name] for j = 1, p do local dep = queuedModules[name][j] if loaded[dep] then print( ' ' .. dep .. ' OK') queuedModules[name][j] = nil for k = j, p do print(' shift ' .. (k+1) .. ' ('..tostring(queuedModules[name][k+1])..') to ' .. k ..'') queuedModules[name][k] = queuedModules[name][k+1] end end end if #queuedModules[name] == 0 then queuedModules[name] = nil print(' |cFF00FFFF'.. name ..'|r deps OK') loaded[name] = true else print(' |cFFFF8800' .. name ..'|r pending') local next = i+1 if not moduleStack[next] then moduleStack[next] = {} end stackLevels = next moduleStack[next][name] = module queue[name] = nil end else print(' |cFF00FF00'.. name ..'|r no deps') loaded[name] = true end end i = i + 1 until i > stackLevels for level, batch in ipairs(moduleStack) do print('config level', level) for name, module in pairs(batch) do if not VeneerData[name] then VeneerData[name] = {} end if module.defaults then print('setting defaults for module', name) --[===[@non-debug@ if not VeneerData[name] then --@end-non-debug@]===] VeneerData[name] = {} --[===[@non-debug@ end --@end-non-debug@]===] for k,v in pairs(module.defaults) do VeneerData[name][k] = v end module.Conf = VeneerData[name] end if VeneerData[name].enabled == nil then VeneerData[name].enabled = true end end end if #checkForConfig >= 1 then local queuedFrame = tremove(checkForConfig) while queuedFrame do B.SetConfigLayers(queuedFrame) B.InitXMLFrame(queuedFrame) queuedFrame = tremove(checkForConfig) end end -- remove from existing end --- Fires an update to all modules local lastUpdate function B.UpdateAll(...) lastUpdate = GetTime() ModulesCall('OnUpdate') end B:RegisterEvent('PLAYER_ENTERING_WORLD') B:SetScript('OnEvent', function(self, event) if event == 'PLAYER_ENTERING_WORLD' then if not initOnced then InitOnce() ModulesCall('OnInitialize') initOnced = true C_Timer.After(1, function() if GetSpecialization() then print(GetSpecialization(), 'enabling') ModulesCall('OnEnable', 'enabled') B:SetScript('OnUpdate', nil) end end) end end B.UpdateAll() if event == 'PLAYER_ENTERING_WORLD' then B.UpdateConfigLayers() end end) --- Modulizer method -- function B:RegisterModule (name, module, ...) if modules[name] then print('pulling modules[|cFFFF8800'.. tostring(name) ..'|r]') return modules[name] end print('new module |cFF00BBFF'.. tostring(name) ..'|r') if module then if modules[name] then error("Module table for '"..tostring(name).."' already exists.") end else module = CreateFrame('Frame', 'Veneer' .. tostring(name) .. 'Handler', B, 'VeneerHandlerTemplate') end modules[name] = module B[name] = module if select('#', ...) >= 1 then local numDeps = select('#', ...) print(' '..numDeps..' deps detected') for i = 1, numDeps do local dep = select(i, ...) -- means that init/enable funcs are ordered to run after deps do their things queuedModules[name] = queuedModules[name] or {} tinsert(queuedModules[name], dep) print(' needs '..dep) end end return module end B.SetConfigLayers = function(frame) local print = B.fprint() if not frame.config then --print(frame:GetName(), 'has no config layers') return end --print('Registering config layers from', frame:GetName()) for i, subframe in ipairs(frame.config) do -- make sure there are no duplicates if not refs[subframe] then local key = #layers+1 layers[key] = subframe refs[subframe] = key end --print(' ', i, subframe:GetName()) end end B.RemoveConfigLayers = function(frame) local print = B.fprint() print('|cFFFF0000RemoveConfigLayers', frame:GetName()) for i, subframe in pairs(layers) do if subframe:GetParent() == frame then print('|cFFFF8800 ', subframe:GetParent():GetName(), '|cFFFFFF00', subframe:GetName()) layers[i]:Hide() layers[i] = nil refs[subframe] = nil end end end B.UpdateConfigLayers = function() local print = B.fprint() local func = B.Conf.GuidesMode and 'Show' or 'Hide' local numAnchors = 0 for name, display in pairs(displays) do numAnchors = numAnchors + 1 display.anchor:EnableMouse(B.Conf.GuidesMode) if B.Conf.GuidesMode then display.anchor:SetScript('OnUpdate', display.anchor.OnUpdate) else display.anchor:SetScript('OnUpdate', nil) for i, anchorButton in ipairs(display.anchor.anchorButton) do anchorButton:Hide() end end print(B.Conf.ConfigMode) display.anchor:EnableMouse(B.Conf.ConfigMode) end for id, region in pairs(layers) do print(id, region:GetName(), func) region[func](region) end print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames') end local XMLFrame_SetEnabled = function(self, value) local name = self:GetName() if not B.Conf[name] then B.Conf[name] = { enabled = true } end print() local enabled if value == nil then if B.Conf[name].enabled == nil then print('toggle based on visibility') enabled = (not self:IsVisible()) and true or false else print('toggle a config value =', B.Conf[name].enabled) enabled = B.Conf[name].enabled end enabled = (enabled ~= true) and true or false else print('use argument value', value) enabled = value end print('arg =', value, 'conf =', B.Conf[name].enabled, 'result=', enabled) B.Conf[name].enabled = enabled local stateFunc = enabled and 'Show' or 'Hide' local eventFunc = enabled and 'OnToggle' or 'OnToggle' for i, region in pairs(self.toggled) do region[stateFunc](region) end if self.OnToggle then self:OnToggle(B.Conf[name].enabled) end if B.Conf[name].enabled then if self.OnEnable then self:OnEnable() end else if self.OnDisable then self:OnDisable() end end end --- Generic handlers for keeping track of XML-defined frames B.OnLoad = function(self) tinsert(checkForConfig, self) self.SetEnabled = XMLFrame_SetEnabled end B.InitXMLFrame = function(self) local name = self:GetName() print('|cFF00FF00hello from '.. name) if self.drag then self:RegisterForDrag('LeftButton') else self:EnableMouse(false) end if not B.Conf[name] then B.Conf[name] = { enabled = true, } end local c = B.Conf[name] if c.position then print('restoring frame position', unpack(c.position)) self:ClearAllPoints() local anchorTo, relativePoint, x, y = unpack(c.position) self:SetPoint(anchorTo, UIParent, relativePoint, x, y) else local a, _, b, c, d = self:GetPoint(1) print('seeding default position', a, b, c, d) c.position = {a, b, c, d} end local state = c.enabled self:SetEnabled(state) end B.OnDragStart = function(self) self.xA = self:GetLeft() self.yA = self:GetBottom() self.anchorTo, self.relativeTo, self.relativePoint, self.x, self.y = self:GetPoint(1) print('acquire anchor', self:GetPoint(1)) print(self:GetName(), 'start moving ('..self.x..', '..self.y..')') self:StartMoving() end B.OnDragStop = function(self) local name = self:GetName() print(name, 'stop moving ('..self:GetLeft()..', '..self:GetBottom()..')') local xB = self:GetLeft() - self.xA local yB = self:GetBottom() - self.yA print('storing anchor point', self.anchorTo, self.relativePoint, self.x + xB, self.y + yB) self:StopMovingOrSizing() B.Conf[name].position = {self.anchorTo, self.relativePoint, self.x + xB, self.y + yB} B.InitXMLFrame(self) end