Mercurial > wow > buffalo2
view Veneer.lua @ 57:3cecf50070ba
Added tag v1.0a-release for changeset dd9b5f59632c
author | Nenue |
---|---|
date | Fri, 10 Jun 2016 20:53:59 -0400 |
parents | dd9b5f59632c |
children | f253baf6022d |
line wrap: on
line source
-------------------------------------------- -- Veneer -- Core -- author: Krakyn -- @project-revision@ @project-hash@ -- @file-revision@ @file-hash@ -- Created: 4/27/2016 1:02 AM -------------------------------------------- --- Implemented methods -- OnInitialize -- OnUpdate -- OnEnable -- runs as soon as GetSpecialization() returns valid data local ADDON, A = ... 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 --- Establish presence Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent) local V = Veneer A.frame = V --- Work variables local modules = {} -- module collector local queuedModules = {} -- indicates modules that were encountered out of dependency order local checkForConfig = {} -- indicates frames created from XML that use their own namespace for position control local moduleStack = {} -- dictates the order in which module methods are fired local initOnced -- internal check for doing bottom-up SV retrieval --- Utilities V.wipeall = function (...) for i = 1, select('#', ...) do wipe(select(i, ...)) end end --- Various region categories V.displays = {} V.configLayers = {} V.configLayersRef = {} --- Returns a debug hook for adding generic module information to each message -- @usage func = V.print(sig) -- @param sig channel name or number local debugstack = _G.debugstack local Devian = _G.Devian local printfuncs = {} V.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 --@debug@ 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 = {} --- Attempts to generate a debug printer based on the local scope. Results vary by where the originator was invoked. V.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 = V.print(func) fprints[sig] = func return func end --@end-debug@ --[=[@non-debug@ V.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 = V.print('Bfl') --- Template for making perpendicular traversals of the displays structure; also makes sure the table is there local setmetatable = setmetatable V.Abstract = function(dest, key, table) if table then for _, v in pairs(dest) do v[key] = {} end end V[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 V[key] end --- internal 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 and 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 local layers, refs, displays = V.configLayers, V.configLayersRef, V.displays --- Things that happen immediately upon entering world local InitOnce = function() print('entering world first time') local defaults = {} 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 V.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] 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 --- Pull in any XML templates if #checkForConfig >= 1 then local queuedFrame = tremove(checkForConfig) while queuedFrame do V.SetConfigLayers(queuedFrame) V.UpdateXMLFrame(queuedFrame) queuedFrame = tremove(checkForConfig) end end end --- Fires an update to all modules local lastUpdate function V.UpdateAll(...) lastUpdate = GetTime() ModulesCall('OnUpdate') end V:RegisterEvent('PLAYER_ENTERING_WORLD') V: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') V:SetScript('OnUpdate', nil) end end) end end V.UpdateAll() if event == 'PLAYER_ENTERING_WORLD' then V.UpdateConfigLayers() end end) --- Modulizer method -- function V: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', V, 'VeneerHandlerTemplate') end modules[name] = module V[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 V.SetConfigLayers = function(frame) local print = V.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 V.RemoveConfigLayers = function(frame) local print = V.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 V.ToggleGuideLayers = function() local print = V.fprint() local func = V.Conf.GuidesMode and 'Show' or 'Hide' local numAnchors = 0 for id, region in pairs(layers) do --print(id, region:GetName(), func) region[func](region) end --print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames') end V.UpdateConfigLayers = function() print('|cFFFF0000', debugstack()) V.ToggleGuideLayers() end local XMLFrame_Enable = function(self, value) local name = self:GetName() local print = V.print('XML') if not V.Conf[name] then V.Conf[name] = { enabled = true } end print() local enabled if value == nil then if V.Conf[name].enabled == nil then print('toggle based on visibility') enabled = (not self:IsVisible()) and true or false else print('toggle a config value =', V.Conf[name].enabled) enabled = V.Conf[name].enabled end enabled = (enabled ~= true) and true or false else print('use argument value', value) enabled = value end print('arg =', value, 'conf =', V.Conf[name].enabled, 'result=', enabled) V.Conf[name].enabled = enabled local stateFunc = enabled and 'Show' or 'Hide' local eventFunc = enabled and 'OnToggle' or 'OnToggle' --- taggled layers if self.toggled then for i, region in pairs(self.toggled) do region[stateFunc](region) end end --- toggle action if self.OnToggle then self:OnToggle(V.Conf[name].enabled) end --- do enable if V.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 local print = V.print('XML') local prototypes = {} prototypes.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 prototypes.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() V.Conf[name].position = {self.anchorTo, self.relativePoint, self.x + xB, self.y + yB} V.UpdateXMLFrame(self) end V.RegisterModuleFrame = function(self, moduleName) local name = self:GetName() tinsert(checkForConfig, self) self.Enable = XMLFrame_Enable self.moduleName = moduleName print('|cFF00FF00XML stuff related to '.. tostring(moduleName) .. ':', self:GetName()) ------------------------------------------------------------------------------------------ if not V[name] then return end local scriptTypes = {'OnUpdate', 'OnEvent', 'OnDragStart', 'OnDragStop'} for script in next(scriptTypes) do if V[name][script] then self:SetScript(script, V[name][script]) end end end local XMLFrame_OnDragStart = function() end local XMLFrame_OnDragStop = function() end V.UpdateXMLFrame = function(self) local print = V.print('XML') local name = self:GetName() if self.drag then self:RegisterForDrag('LeftButton') self:SetScript('OnDragStart', prototypes.OnDragStart) if self.OnDragStop then self:SetScript('OnDragStop', function(self, ...) print('|cFFFF0088end of dragging'). self:OnDragStop(self, ...) prototypes.OnDragStop(self, ...) end) else self:SetScript('OnDragStop', prototypes.OnDragStop) end else self:EnableMouse(false) end -- establish internal storage if not V.Conf[name] then V.Conf[name] = { enabled = self.enabled, } end local c = V.Conf[name] -- establish position data; if undefined, round the API values if not c.position then local anchor, _, point, x, y = self:GetPoint(1) x = floor(x+.5) y = floor(y+.5) print('obtained frame position', name, anchor, point, x, y) c.position = {anchor, point, x, y} else print('restoring frame position', name, unpack(c.position)) self:ClearAllPoints() local anchorTo, relativePoint, x, y = unpack(c.position) self:SetPoint(anchorTo, UIParent, relativePoint, x, y) end self:Enable(c.enabled) end