Mercurial > wow > buffalo2
view Veneer.lua @ 108:a41f6b74709a
- Handler number and boolean cluster arguments as positioning priority layer and "always top" respectively
- Use SetShown and IsShown instead of IsVisible in doing full re-anchor checks
author | Nick@Zahhak |
---|---|
date | Sat, 25 Feb 2017 11:42:07 -0500 |
parents | ff00679a7817 |
children | 26938ae258b7 |
line wrap: on
line source
-- Veneer Custom Interface Framework -- 1. vn OnLoad -- 2. OnEvent where IsLoggedIn() == true -- 3. Setup() where (not self.initialized) -- 4. Update() -- 5. Reanchor() SLASH_VENEER1 = "/veneer" SLASH_VENEER2 = "/vn" local VENEER_VERSION = 703 local LE_FREE_FRAMES_GROUP = 1 local type, strrep, ipairs, tinsert, tostring, select = type, string.rep, ipairs, tinsert, tostring, select local pairs, tremove = pairs, tremove SlashCmdList.VENEER = function(cmd) if Veneer.ConfigMode then Veneer.ConfigMode = false else Veneer.ConfigMode = true end Veneer:UpdateConfigLayers() end VeneerCore = { Frames = {}, ConfigLayers = {}, FrameClusters = { [LE_FREE_FRAMES_GROUP] = {}, }, parserDepth = 0, pendingCalls = {}, AddOnCheck = {} } local print = DEVIAN_WORKSPACE and function(...) _G.print('Veneer', ...) end or nop local wipe = table.wipe local defaults = { enableAll = true, ConfigMode = true } local configMode local anonID = 0 local IsFrameHandle = IsFrameHandle local GetAnonymousName = function(key) if not key then anonID = anonID + 1 key = anonID end return 'VN' .. key end local GetTableName = function(table) return (IsFrameHandle(table) and table:GetName()) or tostring(table) end local OFFSET_PARALLELS = { TOP = {'LEFT', 'RIGHT', 'SetHeight'}, BOTTOM = {'LEFT', 'RIGHT', 'SetHeight'}, LEFT = {'TOP', 'BOTTOM', 'SetWidth'}, RIGHT = {'TOP', 'BOTTOM', 'SetWidth'}, } local ANCHOR_OFFSET_POINT = { TOP = 'BOTTOM', TOPLEFT = 'BOTTOMRIGHT', TOPRIGHT = 'BOTTOMLEFT', LEFT = 'RIGHT', RIGHT = 'LEFT', CENTER = 'CENTER', BOTTOM = 'TOP', BOTTOMRIGHT = 'TOPLEFT', BOTTOMLEFT = 'TOPRIGHT', } local ANCHOR_INSET_DELTA = { TOP = {0, -1}, TOPLEFT = {1, -1}, TOPRIGHT = {-1,-1}, LEFT = {1, 0}, BOTTOMLEFT = {1, 1}, BOTTOM = {0, 1}, BOTTOMRIGHT = {-1, 1}, RIGHT = {-1, 0}, CENTER = {0, 0}, } function VeneerCore:print(...) local txt = '|cFFFFFF00Veneer|r:' for i = 1, select('#', ...) do txt = txt .. ' '.. tostring(select(i, ...)) end DEFAULT_CHAT_FRAME:AddMessage(txt) end function VeneerCore:OnLoad() print('|cFFFFFF00Veneer!|r') self:RegisterEvent('ADDON_LOADED') self:RegisterEvent('PLAYER_LOGIN') self.DEVIAN_PNAME = 'Veneer' self:RegisterForDrag('LeftButton') end local select, IsAddOnLoaded, IsLoggedIn = select, IsAddOnLoaded, IsLoggedIn function VeneerCore:OnEvent(event, ...) print('|cFFFF0088OnEvent()|r',event, ...) if (event == 'PLAYER_LOGIN') or (event == 'ADDON_LOADED') then print(IsLoggedIn(), self.initialized) if IsLoggedIn() and not self.intialized then self:Setup() self.intialized = true print('popping init sequence', self.intialized) end if self.intialized then local addon = ... if self.AddOnCheck[addon] then print(' - setting up '..addon..' dependent modules:') local keepChecking = false for index, handler in ipairs(self.AddOnCheck[addon]) do print(' -', handler:GetName(), (not handler.initialized) and (handler.addonFrame and not _G[handler.addonFrame])) if not handler.initialized then print(' '..handler:GetName()..':Setup()') handler:Setup() handler.initialized = true end end if not keepChecking then self.AddOnCheck[addon] = nil end end end end end function VeneerCore:OnDragStart() self:StartMoving() end function VeneerCore:OnDragStop() self:StopMovingOrSizing() end local VeneerModule_Setup = function(frame) if not frame.initialized then local doSetup = (not frame.addonTrigger) or select(2, IsAddOnLoaded(frame.addonTrigger)) print(' '..frame:GetName()..'.doSetup =', doSetup) if doSetup then frame:Setup() frame.initialized = true else Veneer:RegisterEvent('ADDON_LOADED') end end end function VeneerCore:Setup () print('|cFFFF0088Setup()|r') local resetConfig = (not VeneerData) if (not VeneerData) then VeneerData = defaults VeneerData.version = VENEER_VERSION end self.data = VeneerData self:ExecuteOnClusters(nil, VeneerModule_Setup) self.ConfigMode = VeneerData.ConfigMode self:UpdateConfigLayers() self:Reanchor() self:Update() end function VeneerCore:UpdateConfigLayers() if VeneerData then VeneerData.ConfigMode = self.ConfigMode end self:print('Config mode '..(self.ConfigMode and '|cFF00FF00ON|r' or '|cFFFF0000OFF|r')..'.') self:ExecuteOnClusters(nil, function(frame) if frame.UpdateConfigLayers then frame:UpdateConfigLayers(self.ConfigMode) end if type(frame.ConfigLayer) == 'table' then for index, region in ipairs(frame.ConfigLayer) do print('setting', frame:GetName() .. '['.. index..']', 'to', self.ConfigMode) region:SetShown(self.ConfigMode) end end self.ConfigLayers[frame] = frame:IsShown() if self.ConfigMode then print(frame:GetName(), self.ConfigLayers[frame]) frame:SetShown(self.ConfigMode) else frame:SetShown(self.ConfigLayers[frame]) end end) end function VeneerCore:GetClusterFromArgs (...) local primaryAnchor local insertPosition local insertPriority local clusterTable = self.FrameClusters for i = 1, select('#', ...) do local arg = select(i, ...) local argType = type(arg) if argType == 'string' then if not primaryAnchor then primaryAnchor = arg end clusterTable[arg] = clusterTable[arg] or {} clusterTable = clusterTable[arg] print(strrep(' ', i)..'anchor cluster', i, arg) elseif argType == 'boolean' then if arg == true then print('force top position') insertPosition = 1 insertPriority = nil end elseif argType == 'number' then insertPriority = arg end end if insertPriority then for i = 1, #clusterTable do if clusterTable[i].anchorPriority and (clusterTable[i].anchorPriority > insertPriority) then print('prioritized insert position:', insertPriority, insertPosition) break else print('passing lower priority frame:', clusterTable[i]:GetName()) end insertPosition = i end end if not primaryAnchor then primaryAnchor = 'CENTER' clusterTable[primaryAnchor] = clusterTable[primaryAnchor] or {} clusterTable = clusterTable[primaryAnchor] print('using default anchor') end if not insertPosition then insertPosition = #clusterTable + 1 print('using default position') end return primaryAnchor, clusterTable, insertPosition end -- args: frame object, list of anchor groups, true for forced top, number for priority layer function VeneerCore:AddHandler(handler, ...) print('|cFFFFFF00*** Adding handler:', handler.moduleName or handler:GetName()) for k,v in pairs(VeneerHandlerMixin) do if not handler[k] then print(' * from mixin:', k) handler[k] = v end end if not handler.anchorFrame then local anchorGroup, clusterTable, clusterIndex, clusterPriority = self:GetClusterFromArgs(...) if clusterIndex == 1 then for i, frame in ipairs(clusterTable) do frame.clusterIndex = i + 1 end end tinsert(clusterTable, clusterIndex, handler) print(' cluster', anchorGroup, 'table', clusterTable, 'position', clusterIndex) handler.anchorCluster = clusterTable handler.anchorIndex = clusterIndex else local clusterTable = self.FrameClusters[LE_FREE_FRAMES_GROUP] handler.anchorCluster = clusterTable handler.anchorIndex = #clusterTable+1 tinsert(clusterTable, handler.anchorIndex, handler) print(' free frame') end if handler.addonTrigger and not IsAddOnLoaded(handler.addonTrigger) then print('|cFFFF4400 -- dependency:', handler.addonTrigger) self.AddOnCheck[handler.addonTrigger] = self.AddOnCheck[handler.addonTrigger] or {} tinsert(self.AddOnCheck[handler.addonTrigger], handler) end if self.initialized then print(' -- initialization check') if handler.Setup then local doInit = (not handler.initialized) if handler.addonTrigger and not IsAddOnLoaded(handler.addonTrigger) then doInit = false end -- room to add other checks if doInit then handler:Setup() handler.initialized = true self:InternalReanchor(handler) end end end end function VeneerCore:Reanchor() self:ExecuteOnClusters(nil, 'Reanchor') self:DynamicReanchor(self) end function VeneerCore:Update() self:ExecuteOnClusters(nil, function(frame) if frame.initialized and frame.Update then frame:Update() end end) self:Reanchor() end -- updates anchor relations to and from the target handler function VeneerCore:GetAnchor(...) end -- Evaluates frames visibility and chains them accordingly function VeneerCore:DynamicReanchor(parent) parent = parent or self print('|cFF88FF00DynamicReanchor()') for anchorPoint, cluster in pairs(parent.FrameClusters) do if anchorPoint ~= LE_FREE_FRAMES_GROUP then local lastFrame for index, frame in ipairs(cluster) do print(' |cFF00FF00'..index, frame:GetName(), frame:IsShown(), (lastFrame and ('|cFFFFFF00'..lastFrame:GetName()..'|r') or '|cFF00FFFFUIParent')) if frame:IsShown() then if frame.anchorFrame then print(frame.anchorPoint) frame:SetPoint(frame.anchorPoint, frame.anchorFrame, frame.anchorFrom, frame.anchorX, frame.anchorY) print(frame:GetTop(), frame:GetRight()) else anchorPoint = frame.anchorPoint or anchorPoint frame:ClearAllPoints() if lastFrame then frame:SetPoint(anchorPoint, lastFrame, ANCHOR_OFFSET_POINT[anchorPoint], 0, 0) else frame:SetPoint(anchorPoint, UIParent, anchorPoint, frame.anchorX, frame.anchorY) end print(frame:GetTop(), frame:GetRight()) lastFrame = frame end end end end end end -- Evaluates the current visibility state and re-anchors adjacent blocks accordingly function VeneerCore:InternalReanchor(handler, printFunc) print('|cFF00FFFFVeneer:InternalReanchor('..handler:GetName()..')') if handler.anchorFrame then handler:SetPoint(handler.anchorPoint, handler.anchorFrame, handler.anchorFrom, handler.anchorX, handler.anchorY) return end local anchorPoint = handler.anchorPath or handler.anchorPoint local anchorParent, anchorTo = UIParent, anchorPoint local subPoint, subTo local nextFrame for index, frame in ipairs(handler.anchorCluster) do print(' |cFF00FF00'..index, frame:GetName(), frame:IsVisible()) if frame:IsShown() then if frame ~= handler then anchorParent = frame anchorTo = ANCHOR_OFFSET_POINT[anchorPoint] else nextFrame = handler.anchorCluster[index+1] if nextFrame then subPoint = nextFrame.anchorPath or nextFrame.anchorPoint subTo = ANCHOR_OFFSET_POINT[subPoint] nextFrame:ClearAllPoints() nextFrame:SetPoint(subPoint, handler, subTo, 0, 0) print(' -- pushing '..nextFrame:GetName()..' down the anchor chain', subPoint, subTo) end break end end end if handler:IsShown() then handler:SetPoint(anchorPoint, anchorParent, anchorTo, 0, 0) else if anchorParent and nextFrame then nextFrame:SetPoint(subPoint, handler, subTo, 0, 0) end end print(handler.anchorPoint, anchorParent, anchorTo) if printFunc then printFunc('|cFF88FF00'..handler:GetName()..':SetPoint(', handler.anchorPoint, anchorParent, anchorTo) end end function VeneerCore:SlideBlock(frame, ...) local aX, aY = frame:GetLeft(), frame:GetTop() frame:SetPoint('TOPLEFT', frame, 'BOTTOMLEFT', aX, aY) frame.animation = frame.animation or {} frame.animation.startX = aX frame.animation.startY = aY local targetPoint, targetParent, targetAnchor, offsetX, offsetY = ... frame.BlockSlide:SetScript('OnFinished', function() frame:SetPoint(targetPoint, targetParent, targetAnchor, offsetX, offsetY) VeneerAnimationMixin.OnFinished(frame) end) end function VeneerCore:ExecuteOnClusters(layer, method) self.parserDepth = self.parserDepth + 1 if not layer then if self.parserDepth > 1 then tinsert(self.pendingCalls, method) print('delaying walk for', method) return end print('|cFF00FF00ExecuteOnClusters|r('..tostring(layer)..', '..tostring(method)..')') else print(' Level '..self.parserDepth) end layer = layer or self.FrameClusters for anchor, cluster in pairs(layer) do for index, frame in ipairs(cluster) do print(' '..anchor..'.'..index..' = '..frame:GetName()) if type(method) == 'function' then method(frame, true) elseif frame[method] then print(' |cFF00FF00'..frame:GetName()) frame[method](frame, true) end end if cluster.FrameClusters then self:ExecuteOnClusters(cluster.FrameClusters, method) end end self.parserDepth = self.parserDepth - 1 if (self.parserDepth == 0) and (#self.pendingCalls >= 1) then local delayedMethod = tremove(self.pendingCalls, 1) print('starting delayed walk for', delayedMethod) self:ExecuteOnClusters(nil, delayedMethod) end end -- Takes frame handle and assigns a block to it function VeneerCore:Acquire (frame, template) if not frame then print('|cFFFF4400Unable to acquire frame...|r') return end local veneer = self.Frames[frame] if not veneer then local name = GetAnonymousName() veneer = CreateFrame('Frame', name, frame, template) print(self:GetName()..':Acquire()', frame:GetName(), template) veneer:SetAllPoints(frame) veneer:SetParent(frame) veneer.label:SetText(name) veneer.bg:SetColorTexture(0,0,0,0) veneer:Hide() veneer:EnableMouse(false) -- find current X/Y veneer.currentLeft = frame:GetLeft() veneer.currentTop = frame:GetTop() self.Frames[frame] = veneer end return veneer end