Mercurial > wow > buffalo2
view Veneer.lua @ 87:27db212af783
- polished position management code; goes something like:
- core:Reanchor() to soft fix all anchors
- module:Reanchor() or core:InternalReanchor(module) to position a specific set of neighboring frames
author | Nenue |
---|---|
date | Wed, 19 Oct 2016 16:51:17 -0400 |
parents | 16b300d96724 |
children | b107b4df7eb6 |
line wrap: on
line source
-- Veneer -- Base framework for making things draggable. SLASH_VENEER1 = "/veneer" SLASH_VENEER2 = "/vn" SlashCmdList.VENEER = function(cmd) end VeneerCore = { Frames = {}, ConfigLayers = {}, FrameClusters = {}, parserDepth = 0, pendingCalls = {}, } VeneerHandlerMixin = { Reanchor = nop, anchorPoint = 'CENTER', -- indicates the initial cluster group point --anchorPath = 'BOTTOM', -- indicates the point from which the frame is anchored in a cluster arrangement } 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 if handler.Update then handler:Update() end self:InternalReanchor(handler) end end function VeneerCore:Reanchor() self:ExecuteOnClusters(nil, 'Reanchor') end function VeneerCore:Update() self:ExecuteOnClusters(nil, 'Update') end -- updates anchor relations to and from the target handler function VeneerCore:GetAnchor(...) end function VeneerCore:InternalReanchor(handler, printFunc) print('|cFF00FFFFVeneer:InternalReanchor('..handler:GetName()..')') local anchorPoint = handler.anchorPath or handler.anchorPoint local anchorParent, anchorTo = UIParent, anchorPoint for i, frame in ipairs(handler.anchorCluster) do if frame ~= handler then anchorParent = frame anchorTo = ANCHOR_OFFSET_POINT[anchorPoint] else local nextFrame = handler.anchorCluster[i+1] if nextFrame then local subPoint = nextFrame.anchorPath or nextFrame.anchorPoint local 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 handler:ClearAllPoints() handler:SetPoint(anchorPoint, anchorParent, anchorTo, 0, 0) print(handler.anchorPoint, anchorParent, anchorTo) if printFunc then printFunc('|cFF88FF00'..handler:GetName()..':SetPoint(', handler.anchorPoint, anchorParent, anchorTo) 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 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 local mixin_probe = { 'ArtifactFrame', 'ArtifactFrameUnderlay', }