Nenue@40: --- ${PACKAGE_NAME} Nenue@40: -- @file-author@ Nenue@40: -- @project-revision@ @project-hash@ Nenue@40: -- @file-revision@ @file-hash@ Nenue@40: -- Created: 4/24/2016 11:30 AM Nenue@40: --- These functions deal with propagating and managing block/line templates Nenue@40: local B = select(2,...).frame Nenue@40: local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@40: local _G, ipairs, max, tostring = _G, ipairs, max, tostring Nenue@40: local tinsert, tremove, tContains = table.insert, table.remove, tContains Nenue@40: local Default = T.DefaultHandler Nenue@40: local CreateFrame = CreateFrame Nenue@40: local print = B.print('Layout') Nenue@40: local bprint = B.print('Block') Nenue@40: local lprint = B.print('Layout') Nenue@40: local fprint = B.print('Frame') Nenue@40: local used, free Nenue@40: Nenue@40: local blockFadeOut_OnPlay = function(self) Nenue@40: fprint(self:GetName(), '|cFF00FF00PLAY|r', debugstack(1,3,1)) Nenue@40: end Nenue@40: local blockFadeOut_OnFinished = function(self) Nenue@40: fprint(self:GetName(), '|cFF00FF00FINISHED|r', debugstack(1,3, 1)) Nenue@40: end Nenue@40: Nenue@40: local tMove = function(source, dest, frame) Nenue@40: -- if it's already in the stack, sanity check source stack Nenue@40: local removed Nenue@40: if tContains(dest, frame) then Nenue@40: for i, entry in ipairs(source) do Nenue@40: if entry == frame then Nenue@40: removed = i Nenue@40: tremove(source, i) Nenue@40: break Nenue@40: end Nenue@40: end Nenue@40: -- still need to resolve position Nenue@40: for i, entry in ipairs(dest) do Nenue@40: if entry == frame then Nenue@40: bprint('tMove result:', (removed and ('|cFFFF4400a|r['..removed .. '] is now ') or '') .. '|cFF00FF00b|r[' .. i..']') Nenue@40: return i Nenue@40: end Nenue@40: end Nenue@40: else Nenue@40: -- if it's not, then pull from source stack Nenue@40: for i, entry in ipairs(source) do Nenue@40: if entry == frame then Nenue@40: removed = i Nenue@40: tremove(source, i) Nenue@40: break Nenue@40: end Nenue@40: end Nenue@40: tinsert(dest, frame) Nenue@40: bprint('tMove result:', (removed and ('|cFFFF4400a|r['..removed .. '] is now ') or '') .. '|cFF00FF00b|r[' .. #dest..']') Nenue@40: return #dest Nenue@40: end Nenue@40: end Nenue@40: Nenue@40: Nenue@40: --- Creates or retrieves a complete line data object Nenue@40: Default.GetLine = function(handler, block, lineIndex) Nenue@40: local print = lprint Nenue@40: local blockIndex = block.index Nenue@40: local lines = block.lines Nenue@40: if not lineIndex then Nenue@40: lineIndex = block.currentLine + 1 Nenue@40: print(' |cFFFFFF00generating a frame') Nenue@40: end Nenue@40: Nenue@40: block.numLines = max(block.numLines, lineIndex) Nenue@40: Nenue@40: if not lines[lineIndex] then Nenue@40: print(' |cFF00FF88created line #'..lineIndex..' from for '..handler.name..' block #'..blockIndex) Nenue@40: lines[lineIndex] = CreateFrame('Frame', 'Vn'..handler.name .. blockIndex..'ObjectiveLine'..lineIndex, block, 'VeneerTrackerObjective') Nenue@40: local line = lines[lineIndex] Nenue@40: line.index = lineIndex Nenue@40: line.height = 0 Nenue@40: line.schema = '' Nenue@40: B.SetConfigLayers(line) Nenue@40: Nenue@40: if debug then Nenue@40: for _, region in ipairs(lines[lineIndex].debug) do Nenue@40: region:Show() Nenue@40: end Nenue@40: end Nenue@40: Nenue@40: end Nenue@40: return lines[lineIndex] Nenue@40: end Nenue@40: Nenue@40: Nenue@40: Nenue@40: --- Creates or retrieves a complete block frame object Nenue@40: --- todo: make it use data index to avoid re-coloring every block Nenue@40: Default.GetBlock = function(handler, index) Nenue@40: local print = bprint Nenue@40: print('|cFF0088FF'..handler.name..':GetBlock', index) Nenue@40: local block = handler.InfoBlock[index] Nenue@40: local used = handler.usedBlocks Nenue@40: local free = handler.freeBlocks Nenue@40: Nenue@40: if block then Nenue@40: print(block.info.id, index) Nenue@40: end Nenue@40: Nenue@40: -- if the frame entry is still good, sort heaps Nenue@40: if block and block.info.id == index then Nenue@40: block.posIndex = tMove(free, used, block) Nenue@40: print(' |cFFFFFF00using '..handler.name..'|r.|cFF00FFBBusedBlocks['..tostring(block.posIndex)..'] ('.. block:GetName()..', "'..tostring(block.info.title)..'")') Nenue@40: else Nenue@40: local source = 'cache' Nenue@40: if #handler.freeBlocks >= 1 then Nenue@40: block = tremove(handler.freeBlocks) Nenue@40: print(' |cFF00FF00 assigning from free heap', block:GetName()) Nenue@40: else Nenue@40: Nenue@40: local blockIndex = (#handler.usedBlocks + #handler.freeBlocks) + 1 Nenue@40: block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, handler.frame, 'VeneerTrackerBlock') Nenue@40: --block:SetParent() Nenue@40: block.schema = '' Nenue@40: block.lines = {} Nenue@40: block.numLines = 0 Nenue@40: block.currentLine = 0 Nenue@40: block.attachmentHeight = 0 Nenue@40: block.offset = 0 Nenue@40: B.SetConfigLayers(block) Nenue@40: --- methods for event handlers Nenue@40: Nenue@40: block.Select = handler.Select Nenue@40: block.Open = handler.Open Nenue@40: block.Remove = handler.Remove Nenue@40: block.Link = handler.Link Nenue@40: block.clickZone:SetScript('OnMouseUp', function(self, ...) handler.OnMouseUp(block, ...) end) Nenue@40: block.clickZone:SetScript('OnMouseDown', function(self, ...) handler.OnMouseDown(block, ...) end) Nenue@40: block:ClearAllPoints() Nenue@40: block.index = blockIndex Nenue@40: Nenue@40: block.blockFadeOut:SetScript('OnPlay', blockFadeOut_OnPlay) Nenue@40: Nenue@40: source = 'new' Nenue@40: end Nenue@40: handler.InfoBlock[index] = block Nenue@40: block.posIndex = tMove(free, used, block) Nenue@40: print(' |cFF00FF00('..source..')|r |cFF0088FF'..handler.name..'|r.|cFF00FFBBusedBlocks['..block.posIndex..'] =|r', block:GetName()) Nenue@40: end Nenue@40: block.blockFadeOut:SetScript('OnFinished', blockFadeOut_OnFinished) Nenue@40: block:SetScript('OnHide', function(self) Nenue@41: fprint(self:GetName(), '|cFF00FF00HIDE|r', debugstack(1,3,1)) Nenue@41: if(self.DebugTab:IsShown()) then Nenue@41: self.DebugTab:Hide() Nenue@41: end Nenue@40: self.blockFadeOut:SetScript('OnFinished', blockFadeOut_OnFinished) Nenue@41: self.isAnimating = nil Nenue@40: end) Nenue@40: print(' used/free: |cFFFFFF00' .. #handler.usedBlocks .. '|r/|cFF00FFFF'..#handler.freeBlocks ..'|r') Nenue@40: return block Nenue@40: end Nenue@40: Nenue@40: --- begins a blockFadeOut animation and fires FreeBlock when that's done Nenue@40: Default.ClearBlock = function(handler, block) Nenue@40: if block.isAnimating then Nenue@40: return Nenue@40: end Nenue@40: Nenue@40: block.isAnimating = true Nenue@40: block.blockFadeOut:SetScript('OnFinished', nil) Nenue@40: block.blockFadeOut:SetScript('OnFinished', function(self) Nenue@40: fprint(self:GetName(), '|cFFFFFF00FINISHED|r', debugstack()) Nenue@40: handler:FreeBlock(block) Nenue@40: self:SetScript('OnFinished', blockFadeOut_OnFinished) Nenue@40: block.isAnimating = nil Nenue@40: end) Nenue@40: block.blockFadeOut:Play() Nenue@40: end Nenue@40: Nenue@40: --- remove a block from visible existence; not called directly Nenue@40: Default.FreeBlock = function(handler, block) Nenue@40: bprint('|cFFFF4400FreeBlock|r', block:GetName()) Nenue@40: local used = handler.usedBlocks Nenue@40: local free = handler.freeBlocks Nenue@40: tMove(used, free, block) Nenue@40: Nenue@40: bprint(' |cFFFF4444used/free:|r |cFFFFFF00' .. #used .. '|r/|cFF00FFFF'..#free ..'|r') Nenue@40: Nenue@40: block:Hide() Nenue@40: local animations = {block:GetAnimationGroups() } Nenue@40: for i, animGroup in ipairs(animations) do Nenue@40: bprint(' animGroup', i, animGroup:GetName()) Nenue@40: animGroup:Stop() Nenue@40: end Nenue@40: end Nenue@40: Nenue@40: Nenue@40: Nenue@40: --- Get a usable widget for the given achievement criteria set. Nenue@40: -- Returns a frame object with dimensioning parameters needed to size the receiving tracker block Nenue@40: local wr = T.WidgetRegistry Nenue@40: T.GetWidget = function(data, objectiveType, objectiveKey) Nenue@40: local print = B.print('ObjectiveWidgets') Nenue@40: local widgetType = objectiveType Nenue@40: local widget Nenue@40: local isNew Nenue@40: if wr[widgetType] and wr[widgetType].used[objectiveKey] then Nenue@40: widget = wr[widgetType].used[objectiveKey] Nenue@40: print('|cFF00FF00Updating ('..objectiveKey..')', widget) Nenue@40: elseif not wr[widgetType] or #wr[widgetType].free == 0 then Nenue@40: -- creating a new frame Nenue@40: isNew = true Nenue@40: widget = CreateFrame(widgetType, 'VeneerObjective' .. widgetType .. (wr[widgetType] and (wr[widgetType].lastn+1) or (1)), VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType) Nenue@40: print('|cFFFF0088Creating `'..widget:GetName()..'` id', wr[widgetType].lastn) Nenue@40: T.UpdateSchema(widgetType, data.schema or 'default') Nenue@40: else Nenue@40: -- recycling for a different criteria set Nenue@40: isNew = true Nenue@40: widget = tremove(wr[widgetType].free) Nenue@40: print('|cFFFFFF00Acquiring released widget', widget:GetName()) Nenue@40: end Nenue@40: Nenue@40: for k,v in pairs(data) do Nenue@40: if not widget[k] then Nenue@40: widget[k] = v Nenue@40: tprint('widget', widget:GetName(), k, v) Nenue@40: end Nenue@40: end Nenue@40: Nenue@40: wr[widgetType].used[objectiveKey] = widget Nenue@40: widget.objective = data Nenue@40: widget.key = objectiveKey Nenue@40: T.InitializeWidget(widget, isNew) Nenue@40: return widget Nenue@40: end