Mercurial > wow > buffalo2
view Veneer.lua @ 88:b107b4df7eb6
- core:DynamicReanchor
- top-down evaluation of clustered frames
- core:InternalReanchor(module)
- bottom-up evaluation of target and frames anchored to it
author | Nenue |
---|---|
date | Thu, 20 Oct 2016 04:08:11 -0400 |
parents | 27db212af783 |
children | 74e714637d6a |
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" SlashCmdList.VENEER = function(cmd) end VeneerCore = { Frames = {}, ConfigLayers = {}, FrameClusters = {}, parserDepth = 0, pendingCalls = {}, } VeneerHandlerMixin = { anchorPoint = 'CENTER', -- indicates the initial cluster group point --anchorPath = 'BOTTOM', -- indicates the point from which the frame is anchored in a cluster arrangement OnHide = function() Veneer:DynamicReanchor() end, OnShow = function(self) self:Reanchor() Veneer:StaticReanchor(self) end } VeneerAnimationMixin = {} local print = DEVIAN_WORKSPACE and function(...) print('Veneer', ...) end or nop local wipe = table.wipe local defaults = { enableAll = true, enableModule = { BuffFrame = true, }, BuffFrame = { width = 48, height = 48, } } local configMode local anonID = 0 local tostring = tostring 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 function VeneerCore:OnEvent(event, ...) if event == 'ADDON_LOADED' or event == 'PLAYER_LOGIN' then if IsLoggedIn() and not self.intialized then self:Setup() self:UnregisterEvent('ADDON_LOADED') self:UnregisterEvent('PLAYER_LOGIN') self:Reanchor() self:Update() end end end function VeneerCore:OnDragStart() self:StartMoving() end function VeneerCore:OnDragStop() self:StopMovingOrSizing() end function VeneerCore:Setup () self.initialized = true if (not VeneerData) or (not VeneerData.version) then VeneerData = defaults end self.data = VeneerData self:ExecuteOnClusters(nil, 'Setup') end function VeneerCore:GetClusterFromArgs (...) local primaryAnchor local insertPosition 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(string.rep(' ', i)..'anchor cluster', i, arg) elseif argType == 'boolean' then insertPosition = 1 end end if not primaryAnchor then primaryAnchor = 'TOPLEFT' end if not insertPosition then insertPosition = #clusterTable + 1 end return primaryAnchor, clusterTable, insertPosition end function VeneerCore:AddHandler(handler, ...) print('*** Adding handler:', handler.moduleName or handler:GetName()) local anchorGroup, clusterTable, clusterIndex = 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 for k,v in pairs(VeneerHandlerMixin) do if not handler[k] then print(' * from mixin:', k) handler[k] = v end end if self.initialized then print(' -- doing initialization') if handler.Setup and not handler.initialized then handler:Setup() handler.initialized = true end self:InternalReanchor(handler) end end function VeneerCore:Reanchor() self:ExecuteOnClusters(nil, 'Reanchor') self:DynamicReanchor(self) end function VeneerCore:Update() self:ExecuteOnClusters(nil, 'Update') 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 local lastFrame for index, frame in ipairs(cluster) do print(' |cFF00FF00'..index, frame:GetName(), frame:IsVisible()) if frame:IsVisible() then anchorPoint = frame.anchorPoint frame:ClearAllPoints() if lastFrame then frame:SetPoint(anchorPoint, lastFrame, ANCHOR_OFFSET_POINT[anchorPoint], 0, 0) else frame:SetPoint(anchorPoint, UIParent, anchorPoint, 0, 0) end lastFrame = frame 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()..')') 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:IsVisible() 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:IsVisible() 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 anchorPoint, parent, anchorTo, pX,pY = ... print(' |cFF0088FFSlide:|r', frame, 'to', parent, pX,pY) local qX, qY = pX, pY local bX, bY local dX, dY = 0, 0 local aX, aY = frame:GetLeft(), frame:GetTop() local str = '' if not aX then dY = ((anchorPoint == 'TOP') and frame:GetHeight()) or (((anchorPoint == 'BOTTOM') and -frame:GetHeight()) or 0) dX = ((anchorPoint == 'LEFT') and -frame:GetWidth()) or (((anchorPoint == 'RIGHT') and frame:GetWidth()) or 0) qX = pX + dX qY = pY + dY aX, aY = qX, qY bX, bY = pX, pY str = '|cFFFFFF00relative|r' else frame:ClearAllPoints() bX, bY = frame:GetLeft(), frame:GetTop() dX, dY = (bX-aX), (bY-aY) str = '|cFFFFFF00existing|r' end if ((dX ~= 0) or (dY ~= 0)) and frame.BlockSlide then print(' |cFF00FF88Slide result:|r',str, dX, dY) frame:ClearAllPoints() frame:SetPoint(anchorPoint, parent, anchorTo, qX, qY) frame.BlockSlide.dX = dX frame.BlockSlide.dY = dY frame.BlockSlide.sourcePoint = {anchorPoint, parent, anchorTo, qX, qY} frame.BlockSlide.destPoint = {anchorPoint, parent, anchorTo, pX,pY} frame.BlockSlide.translation:SetOffset(dX, dY) frame.BlockSlide:Play() return 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('|cFF00FF00Veneer:ExecuteOnClusters|r('..tostring(layer)..', '..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 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 local VeneerButton_OnDragStart = function(self) self.startingLeft = self:GetLeft() self.startingBottom = self:GetBottom() self.anchors = self.anchors or {} table.wipe(self.anchors) local frame = self:GetParent() local n = frame:GetNumPoints() for i = 1, n do local anchor, parent, relative, x, y = frame:GetPoint(i) self.anchors[i] = { anchor = anchor, parent = parent, relative = relative, x = x, y = y } end print(self:GetName(), 'start moving', self.startingLeft, self.startingBottom) self:StartMoving() end local VeneerButton_OnDragStop = function(self) self:StopMovingOrSizing() if self.OnDragStop then self.OnDragStop(self) else local frame = self:GetParent() local dx = self:GetLeft() - self.startingLeft local dy = self:GetBottom() - self.startingBottom frame:ClearAllPoints() for i, point in ipairs(self.anchors) do frame:SetPoint(point.anchor, point.parent, point.relative, point.x + dx, point.y + dy) print('adjusting anchor', point.anchor, point.parent, point.relative, point.x + dx, point.y + dy) end end end local Veneer_FixMovers = function() for frame, veneer in pairs(veneers) do if veneer:IsMoving() then VeneerButton_OnDragStop(veneer) end end end local VeneerButton_Update = function(self) if configMode then self:SetScript('OnDragStart', VeneerButton_OnDragStart) self:SetScript('OnDragStop', VeneerButton_OnDragStop) self:SetMovable(true) self:EnableMouse(true) self:RegisterForDrag('LeftButton') self.bg:SetColorTexture(0,1,0,0.5) for i, region in ipairs(self.configLayers) do region:Show() end self:Show() else self:SetScript('OnDragStart', self.StartMoving) self:SetScript('OnDragStop', self.StopMovingOrSizing) self:SetMovable(false) self:EnableMouse(false) self.bg:SetColorTexture(0,1,0,0) for i, region in ipairs(self.configLayers) do region:Hide() end if self.isHidden then self:Hide() end end end local ToggleVeneerConfig = function() if configMode then configMode = false Veneer:print('Config mode off.') else configMode = true Veneer:print('Config mode on.') end for frame, veneer in pairs(veneers) do VeneerButton_Update(veneer) end end local VeneerButton_OnShow = function(self) VeneerButton_Update(self) 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 = type(frame) == 'table' and GetTableName(frame) or GetAnonymousName() veneer = CreateFrame('Frame', name, frame, template or 'VeneerTemplate') print('+veneer', name) veneer:SetAllPoints(frame) veneer:SetParent(frame) veneer.label:SetText(name) veneer.bg:SetColorTexture(0,0,0,0) veneer:Hide() veneer:EnableMouse(false) veneer:SetScript('OnShow', VeneerButton_OnShow) -- find current X/Y veneer.currentLeft = frame:GetLeft() veneer.currentTop = frame:GetTop() self.Frames[frame] = veneer end return veneer end function VeneerHandlerMixin:Reanchor (anchorAll) if not anchorAll then Veneer:InternalReanchor(self) end end function VeneerAnimationMixin:OnPlay() PlaySoundKitID(229) print('|cFF00FF00Anim:OnPlay|r @', unpack(self.sourcePoint)) end function VeneerAnimationMixin:OnStop() PlaySoundKitID(229) end function VeneerAnimationMixin:OnFinished() PlaySoundKitID(229) print('|cFF00FF00Anim:OnFinish|r @', unpack(self.destPoint)) self:GetParent():ClearAllPoints() self:GetParent():SetPoint(unpack(self.destPoint)) end