Nenue@28: --- ${PACKAGE_NAME} Nenue@28: -- @file-author@ Nenue@28: -- @project-revision@ @project-hash@ Nenue@28: -- @file-revision@ @file-hash@ Nenue@28: -- Created: 3/30/2016 12:49 AM Nenue@39: --- Everything that involves directly placing elements on the screen goes here. Sizing, spacing, tiling, etc. Nenue@28: local B = select(2,...).frame Nenue@35: local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@28: local _G, ipairs, max, min, unpack, floor, pairs, tostring, type, band = _G, ipairs, max, min, unpack, floor, pairs, tostring, type, bit.band Nenue@34: local IsResting, UnitXP, UnitXPMax, GetXPExhaustion, tinsert, tremove = IsResting, UnitXP, UnitXPMax, GetXPExhaustion, table.insert, table.remove Nenue@28: local UnitLevel, IsQuestWatched, UIParent = UnitLevel, IsQuestWatched, UIParent Nenue@28: local GetAutoQuestPopUp, GetQuestLogCompletionText = GetAutoQuestPopUp, GetQuestLogCompletionText Nenue@28: local PERCENTAGE_STRING, GetQuestProgressBarPercent = PERCENTAGE_STRING, GetQuestProgressBarPercent Nenue@35: local Default, AutoQuest, Quest, Bonus, Cheevs = T.DefaultHandler, T.AutoQuest, T.Quest, T.Bonus, T.Cheevs Nenue@28: local InCombatLockdown, format, lshift, CreateFrame = InCombatLockdown, format, bit.lshift, CreateFrame Nenue@29: local IsModifiedClick, ChatEdit_GetActiveWindow = IsModifiedClick, ChatEdit_GetActiveWindow Nenue@38: local band, bor = bit.band, bit.bor Nenue@35: local print = B.print('Layout') Nenue@34: local oprint = B.print('Objectives') Nenue@34: local bprint = B.print('Block') Nenue@34: local tprint = B.print('Tracker') Nenue@35: local lprint = B.print('Layout') Nenue@28: local unitLevel = 1 Nenue@38: Nenue@38: local ANIM_STATE = 'Animation: %04X' Nenue@38: local INIT_STATE = 'Init: %04X' Nenue@38: Nenue@38: --- Bitfields of import Nenue@38: --- control value for everything Nenue@38: local OBJECTIVE_TRACKER_UPDATE_REASON = _G.OBJECTIVE_TRACKER_UPDATE_REASON Nenue@38: --- flags reason categories where frame layout requires initializing (starts high) Nenue@38: local initReason = 0xFFFF Nenue@38: --- flags reason categories where frame anchor updates must be delayed because of an ongoing animation (starts low) Nenue@38: local animateReason = 0x0000 Nenue@28: Nenue@34: --- FRAMES Nenue@28: local Wrapper = _G.VeneerObjectiveWrapper Nenue@28: local Scroller = Wrapper.scrollArea Nenue@28: local Scroll = _G.VeneerObjectiveScroll Nenue@35: local orderedHandlers = T.orderedHandlers Nenue@35: local orderedNames = T.orderedNames Nenue@28: Nenue@34: --- FRAME TEMP VARIABLES Nenue@37: local wrapperWidth, wrapperHeight = 0, 0 Nenue@28: local scrollWidth, scrollHeight Nenue@34: Nenue@34: --- SCHEMA VARIABLES Nenue@34: local schemaName, lastSchema = { Nenue@34: tracker = '', Nenue@34: block = '', Nenue@34: line = '' Nenue@34: }, {} Nenue@34: local trackerSchema, blockSchema, lineSchema Nenue@34: Nenue@28: local itemButtonSize, itemButtonSpacing = 36, 1 Nenue@34: local wrapperMaxWidth, wrapperMaxHeight = 270, 490 -- these are the hard bounds, actual *Height variables are changed Nenue@34: local wrapperHeadFont, wrapperHeadSize, wrapperHeadOutline = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 16, 'NONE' Nenue@34: local wrapperPosition = {'RIGHT', UIParent, 'RIGHT', -84, 0 } Nenue@34: local rewardSize = 24 Nenue@28: Nenue@30: local headerHeight, headerColor, headerSpacing = 16, {1,.75,0,1}, 2 Nenue@28: local headerbg = {'VERTICAL', 1, 1, 0.5, 0.5, 1, 1, 0.5, 0} Nenue@28: local headerFont, headerSize, headerOutline = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 14, 'OUTLINE' Nenue@28: Nenue@31: local titlebg = {'HORIZONTAL', 1, 0, .7, 0, 1, 0, .7, .2} Nenue@28: local titleFont, titleSize, titleOutline = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 16, 'OUTLINE' Nenue@34: local titleColor = {0,.7,1,1} Nenue@28: Nenue@28: local textbg = {'HORIZONTAL', 0, 0, 0, 0.4, 0, 0, 0, 0 } Nenue@28: local textFont, textSize, textOutline = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Regular.ttf]], 16, 'OUTLINE' Nenue@39: local textColor = {1,1,1,1 } Nenue@39: Nenue@39: local widgetTextFont, widgetTextSize, widgetTextOutline = [[Interface\Addons\SharedMedia_MyMedia\font\XOIREQE.TTF]], 11, 'OUTLINE' Nenue@39: local widgetTextColor = {1,1,1,1 } Nenue@39: local widgetHeight, widgetBorder = 17, 1 Nenue@39: Nenue@28: Nenue@28: local selectionbg = {'HORIZONTAL', 1, 1, 1, 0, 1, 1, 1, 0.225} Nenue@28: local titleSpacing, textSpacing, blockSpacing = 3, 3, 1 Nenue@28: local titleIndent, textIndent,selectionIndent = 2, 5, 50 Nenue@34: --- END SCHEMA Nenue@35: local blockPosition Nenue@35: Nenue@38: Nenue@38: local SetAnimate = function(reason, animate) Nenue@38: print('comparing', animateReason, reason) Nenue@38: if animate then Nenue@38: if band(animateReason, reason) == 0 then Nenue@38: animateReason = animateReason + reason Nenue@38: end Nenue@38: else Nenue@38: if band(animateReason, reason) > 0 then Nenue@38: animateReason = animateReason - reason Nenue@38: end Nenue@38: end Nenue@38: Wrapper.AnimState:SetFormattedText(ANIM_STATE, animateReason) Nenue@38: end Nenue@38: Nenue@38: Nenue@34: --- schema swapper Nenue@35: T.UpdateSchema = function(layer, newSchema) Nenue@35: if not (T.Conf.Schema[layer] and T.Conf.Schema[layer][newSchema]) then Nenue@34: return Nenue@34: elseif schemaName[layer] == newSchema then Nenue@34: return Nenue@34: end Nenue@34: lastSchema[layer] = schemaName[layer] Nenue@34: schemaName[layer] = newSchema Nenue@35: local c = T.Conf.Schema[layer][newSchema] Nenue@28: Nenue@34: if layer == 'tracker' then Nenue@34: headerHeight, headerSpacing = c.headerHeight, c.headerSpacing Nenue@34: headerColor = c.headerColor Nenue@34: headerbg = c.headerbg Nenue@37: headerFont, headerSize, headerOutline = unpack(c.headerFont) Nenue@34: trackerSchema = newSchema Nenue@34: elseif layer == 'block' then Nenue@34: titlebg = c.titlebg Nenue@37: titleFont, titleSize, titleOutline = unpack(c.titleFont) Nenue@34: selectionbg = c.selectionbg Nenue@34: titleSpacing, textSpacing, blockSpacing = c.titleSpacing, c.textSpacing, c.blockSpacing Nenue@37: titleIndent, textIndent,selectionIndent = c.titleIndex, c.textIndex, c.selectionIndent Nenue@34: titleColor = c.titleColor Nenue@37: print(unpack(c.titleColor)) Nenue@34: rewardSize = 24 Nenue@37: textFont, textSize, textOutline = unpack(c.textFont) Nenue@34: textbg = c.textbg Nenue@34: textIndent = c.textIndent Nenue@34: rewardSize = c.rewardSize Nenue@37: blockSchema = newSchema Nenue@34: elseif layer == 'line' then Nenue@34: textColor = c.textColor Nenue@34: lineSchema = newSchema Nenue@39: elseif layer == 'widget' then Nenue@39: widgetTextColor = c.textSpacing Nenue@39: widgetTextFont, widgetTextSize, widgetTextOutline = unpack(c.textFont) Nenue@34: end Nenue@38: tprint('|cFFFF0088 Schema:|r', layer, lastSchema[layer], '->', newSchema) Nenue@34: end Nenue@35: -- todo: figure out why objectives go invisible Nenue@35: local anchorPoint, anchorFrame Nenue@35: local abs, GetTime = math.abs, GetTime Nenue@35: Default.AddTracker = function(handler, frame, index) Nenue@38: local isInitialized = true Nenue@38: if initReason and (band(initReason, handler.updateReason) > 0 ) then Nenue@38: isInitialized = false Nenue@38: initReason = initReason - handler.updateReason Nenue@38: print('|cFF00FF00%%% initialization status update:', format('%04X', initReason)) Nenue@38: Nenue@38: frame.SlideIn:SetScript('OnPlay', function() Nenue@38: SetAnimate(handler.updateReasonModule, true) Nenue@38: end) Nenue@38: Nenue@38: frame.SlideIn:SetScript('OnFinished', function() Nenue@38: SetAnimate(handler.updateReasonModule, false) Nenue@38: end) Nenue@38: Nenue@38: if initReason == 0 then Nenue@38: initReason = nil Nenue@38: end Nenue@38: end Nenue@38: Nenue@35: if index == 1 then Nenue@35: print('|cFF00FF00### beginning wrapper layout -----------------') Nenue@35: anchorPoint, anchorFrame = 'TOP', Scroll Nenue@35: wrapperHeight = 0 Nenue@35: end Nenue@35: Nenue@35: frame.destinationOffset = -wrapperHeight Nenue@35: print(frame.destinationOffset, frame.previousOffset) Nenue@38: if isInitialized and (abs(frame.previousOffset - frame.destinationOffset) > 0.9) and frame:IsVisible() then Nenue@35: if frame.wasEmpty then Nenue@35: frame.previousOffset = -Wrapper:GetHeight() Nenue@35: end Nenue@35: Nenue@35: local postFrame, postPoint = anchorFrame, anchorPoint Nenue@35: local delta = frame.destinationOffset - frame.previousOffset Nenue@35: local _, _, _, _, offset = frame:GetPoint(1) Nenue@35: print(' |cFF00FFBBpushing', frame:GetName(), delta, 'pixels, from', frame.previousOffset, '(', offset, ')') Nenue@35: frame.SlideIn.translation:SetTarget(frame) Nenue@35: frame.SlideIn.translation:SetOffset(0, delta) Nenue@35: frame.SlideIn:Play() Nenue@35: --for i, b in ipairs(handler.usedBlocks) do Nenue@35: --b.SlideIn.translation:SetOffset(0, delta) Nenue@35: -- b.SlideIn:Play() Nenue@35: --end Nenue@35: local start = GetTime() Nenue@35: frame.SlideIn:SetScript('OnFinished', function() Nenue@35: print(' |cFF00BBFF'..frame:GetName(), 'moved', delta, 'over duration of ', GetTime()-start) Nenue@35: frame:SetParent(Scroll) Nenue@35: frame:SetPoint('TOP', Scroll, 'TOP', 0, frame.destinationOffset) Nenue@35: frame.previousOffset = frame.destinationOffset Nenue@35: frame.SlideIn:SetScript('OnFinished', nil) Nenue@35: if Wrapper.destinationHeight then Nenue@35: Wrapper:SetHeight(Wrapper.destinationHeight) Nenue@35: Scroller:SetHeight(Wrapper.destinationHeight) Nenue@35: Scroll:SetHeight(Wrapper.destinationHeight) Nenue@35: Wrapper.previousHeight = Wrapper.destinationHeight Nenue@35: Wrapper.destinationHeight = nil Nenue@35: end Nenue@35: Nenue@35: end) Nenue@35: else Nenue@37: print(' |cFF00BBFFpinning '..handler.name..' to', anchorFrame:GetName(), anchorPoint, '|rcurrent frame height:', frame.height) Nenue@35: print(' |cFFFF0088total height:', wrapperHeight) Nenue@35: frame:ClearAllPoints() Nenue@35: frame:SetParent(Scroll) Nenue@35: frame:SetPoint('TOP', Scroll, 'TOP', 0, frame.destinationOffset) Nenue@38: frame:SetPoint('LEFT', Scroll, 'LEFT') Nenue@38: frame:SetPoint('RIGHT', Scroll, 'RIGHT') Nenue@35: frame.previousOffset = frame.destinationOffset Nenue@35: handler.initialized = true Nenue@35: end Nenue@35: Nenue@35: frame.title:SetFont(headerFont, headerSize, headerOutline) Nenue@35: frame.titlebg:SetHeight(headerHeight) Nenue@35: frame.title:SetTextColor(unpack(headerColor)) Nenue@35: Nenue@35: if frame.height ~= frame.previousHeight then Nenue@35: frame:SetHeight(frame.height) Nenue@35: end Nenue@35: Nenue@35: frame:Show() Nenue@35: if frame.wasEmpty then Nenue@35: frame.headerFade:Play() Nenue@35: frame.wasEmpty = nil Nenue@35: end Nenue@35: Nenue@35: wrapperHeight = wrapperHeight + frame.height Nenue@35: anchorFrame = handler.frame Nenue@35: anchorPoint = 'BOTTOM' Nenue@35: Nenue@35: end Nenue@28: Nenue@30: Default.AddBlock = function(self, block, blockIndex) Nenue@30: local blockIndex = blockIndex or (self.currentBlock + 1) Nenue@28: local print = bprint Nenue@28: local tracker = self.frame Nenue@28: local info = block.info Nenue@30: Nenue@35: block.index = blockIndex Nenue@35: Nenue@37: print('blockschema', blockSchema, block.schema) Nenue@34: if blockSchema ~= block.schema then Nenue@37: T.UpdateSchema('block', block.schema) Nenue@38: print(' ### activating block schema:|cFF0088FF', block.schema) Nenue@37: end Nenue@34: Nenue@37: block:SetWidth(T.Conf.Wrapper.Width) Nenue@37: block.title:SetSpacing(titleSpacing) Nenue@37: block.title:SetPoint('TOP', block, 'TOP', 0, -titleSpacing) Nenue@37: block.title:SetPoint('LEFT', block, 'LEFT', titleIndent, 0) Nenue@37: block.title:SetTextColor(unpack(titleColor)) Nenue@37: block.titlebg:SetTexture(1,1,1,1) Nenue@37: block.titlebg:SetGradientAlpha(unpack(titlebg)) Nenue@37: block.titlebg:SetPoint('TOP', block, 'TOP', 0, 0) Nenue@37: block.titlebg:SetPoint('BOTTOM', block.title, 'BOTTOM', 0, -titleSpacing) Nenue@37: block.status:SetSpacing(textSpacing) Nenue@37: block.status:SetPoint('TOP', block.titlebg, 'BOTTOM', 0, -textSpacing) Nenue@37: block.status:SetPoint('LEFT', block.titlebg, 'LEFT', textIndent, 0) Nenue@37: block.statusbg:SetPoint('TOP', block.titlebg, 'BOTTOM', 0, 0) Nenue@37: block.statusbg:SetPoint('BOTTOM', block, 'BOTTOM', 0, 0) Nenue@37: block.statusbg:SetTexture(1,1,1,1) Nenue@37: block.statusbg:SetGradientAlpha(unpack(textbg)) Nenue@37: block.SelectionOverlay:SetGradientAlpha(unpack(selectionbg)) Nenue@37: block.SelectionOverlay:SetPoint('TOPLEFT', selectionIndent, 0) Nenue@37: block.SelectionOverlay:SetPoint('BOTTOMRIGHT') Nenue@37: Nenue@37: local anchor, target, point, x, y = 'TOPRIGHT', block, 'TOPRIGHT', -2, -2 Nenue@37: for i, tile in ipairs(block.rewardTile) do Nenue@37: --print(rewardSize) Nenue@37: tile:SetSize(rewardSize, rewardSize) Nenue@37: tile:ClearAllPoints() Nenue@37: tile:SetPoint(anchor, target, point, x, y) Nenue@37: block.rewardLabel[i]:SetPoint('TOP', tile, 'TOP', 0, 0) Nenue@37: anchor, target, point, x, y = 'TOPRIGHT', tile, 'TOPLEFT', -2, 0 Nenue@34: end Nenue@34: Nenue@35: Nenue@35: local titleHeight = floor(block.title:GetHeight()+.5) Nenue@35: local titlebgHeight = titleHeight + titleSpacing*2 Nenue@35: block.titlebg:SetHeight(titlebgHeight) Nenue@35: Nenue@35: local statusHeight = floor(block.status:GetHeight()+.5) Nenue@35: local statusbgHeight = statusHeight + textSpacing*2 Nenue@35: local attachmentHeight =floor(block.attachmentHeight + .5) Nenue@35: Nenue@35: print(' |cFF0088FFanchor to', self.currentAnchor:GetName()) Nenue@35: print(' |cFF00FF00attachment:|r', attachmentHeight, '|cFF00FF00title:|r', titlebgHeight, '('.. titleHeight..')') Nenue@35: if attachmentHeight > 0 then Nenue@35: attachmentHeight = attachmentHeight + textSpacing Nenue@35: end Nenue@35: Nenue@35: block.height = titlebgHeight + attachmentHeight Nenue@35: block:SetHeight(block.height) Nenue@35: Nenue@34: if block.debug then Nenue@34: local func = (B.Conf.GuidesMode == true) and 'Show' or 'Hide' Nenue@34: for _, region in ipairs(block.debug) do Nenue@34: region[func]() Nenue@34: end Nenue@34: end Nenue@34: Nenue@35: --- Handler vars Nenue@35: if blockIndex == 1 then Nenue@35: tracker.previousHeight = tracker.height Nenue@35: tracker.height = headerHeight Nenue@35: blockPosition = -headerHeight Nenue@35: tprint(' |cFF88FF00AddBlock:|r new layout: headerHeight =', headerHeight, 'previousHeight =', tracker.previousHeight) Nenue@35: else Nenue@35: blockPosition = blockPosition Nenue@35: tprint(' |cFF8888FFAddBlock:|r advancing: height =', tracker.height) Nenue@35: end Nenue@30: self.currentBlock = blockIndex Nenue@29: self.currentAnchor = block Nenue@35: Nenue@35: block:SetPoint('TOPLEFT', self.frame, 'TOPLEFT', 0, blockPosition) Nenue@35: block:SetPoint('RIGHT', tracker,'RIGHT', 0, 0) Nenue@38: block:Show() Nenue@35: self.numBlocks = self.numBlocks + 1 Nenue@29: print(' |cFFFFFF00'..tracker.height..'|r', '|cFF00FF00'..block:GetName()..'|r', block.height, tracker.height) Nenue@29: tracker.height = tracker.height + block.height Nenue@35: blockPosition = blockPosition - block.height Nenue@38: Nenue@38: Nenue@38: Nenue@38: if Devian and Devian.InWorkspace() then Nenue@38: block.DebugTab:SetParent(UIParent) Nenue@38: block.DebugTab:SetPoint('TOPRIGHT', block, 'TOPLEFT', 0, 0) Nenue@38: block.DebugTab.status:SetText(tostring(block.schema) .. ' @|cFF00FF00' .. tostring(block.posIndex) .. '|r #|cFFFFFF00'.. tostring(info.logIndex or info.id) .. '|r'.. Nenue@38: ' H|cFFFFFF00' .. tostring(block.height) .. ' L|cFF00FFFF' .. tostring(block.numLines) ..'|r') Nenue@38: block.DebugTab:Show() Nenue@38: end Nenue@28: end Nenue@28: Nenue@28: --- Used as an iterator of sorts for cascaded tag icon placements (the daily/faction/account icons) Nenue@30: Default.AddTag = function (handler, block, tagInfo, tagPoint, tagAnchor, tagRelative) Nenue@28: local print = bprint Nenue@30: Nenue@30: for order, tagName in ipairs(block.info.tagInfo) do Nenue@30: local tag = block[tagName] Nenue@30: if block.tagCoords[tagName] and tag then Nenue@30: tag:SetTexCoord(unpack(block.tagCoords[tagName])) Nenue@30: tag:Show() Nenue@30: tag:SetPoint(tagPoint, tagAnchor, tagRelative, 0, 0) Nenue@30: tagPoint, tagAnchor, tagRelative = 'TOPRIGHT', tag, 'TOPLEFT' Nenue@30: else Nenue@30: block[tagName]:Hide() Nenue@30: end Nenue@28: end Nenue@30: Nenue@28: return tagPoint, tagAnchor, tagRelative Nenue@28: end Nenue@28: Nenue@38: Default.AddReward = function(handler, block, rewardInfo, tagPoint, tagAnchor, tagRelative) Nenue@38: local print = bprint Nenue@38: Nenue@38: for order, reward in ipairs(rewardInfo) do Nenue@38: Nenue@38: end Nenue@38: end Nenue@38: Nenue@28: --- Adds the given line to the current content and advances the anchor pointer to that new line for the following call. Nenue@30: Default.AddLine = function(handler, block, text, attachment, template) Nenue@28: local print = lprint Nenue@30: local lineIndex = block.currentLine + 1 Nenue@34: local line = handler:GetLine(block, lineIndex) Nenue@36: Nenue@31: line.index = lineIndex Nenue@38: template = template or 'default' Nenue@38: if template and lineSchema ~= template then Nenue@35: print(' |cFF00FF00change schema', template) Nenue@35: T.UpdateSchema('line', template) Nenue@34: end Nenue@38: line.status:SetSpacing(textSpacing) Nenue@38: line.status:SetPoint('LEFT', line, 'LEFT', textIndent, 0) Nenue@38: line.status:SetPoint('RIGHT', line, 'RIGHT',0, 0) Nenue@38: line.status:SetTextColor(unpack(textColor)) Nenue@34: line:SetPoint('TOP', block.endPoint, 'BOTTOM', 0, -textSpacing) Nenue@37: line.status:SetPoint('LEFT', line, 'LEFT', textIndent, 0) Nenue@37: line:SetPoint('LEFT', block, 'LEFT') Nenue@37: line:SetPoint('RIGHT', block, 'RIGHT') Nenue@28: line:Show() Nenue@38: line:SetScript('OnMouseUp', function(self, button) Nenue@38: handler.OnMouseUp(block, button) Nenue@38: end) Nenue@28: Nenue@34: Nenue@35: tprint(' |cFF0088FFAddLine|r (|cFF00FFFF'..tostring(line.schema)..'|r):', line:GetName()) Nenue@38: --[[ Nenue@38: for i = 1, line:GetNumPoints() do Nenue@38: tprint(' - ', line:GetPoint(i)) Nenue@38: end Nenue@38: tprint(' - ', line:GetSize()) Nenue@38: tprint(' - ', line:GetParent(), line:GetParent():IsVisible()) Nenue@38: tprint(' - ', line:IsVisible()) Nenue@38: --]] Nenue@38: Nenue@38: Nenue@34: Nenue@34: Nenue@34: -- fill in the text, then derive pixel-rounded height Nenue@30: line.status:SetText(text) Nenue@34: line.height = floor(line.status:GetStringHeight()+.5) Nenue@30: Nenue@30: -- For progressbar and timer lines, status text may be used as the title heading Nenue@30: if attachment then Nenue@38: attachment:SetPoint('TOP', line, 'TOP') Nenue@38: attachment:SetPoint('LEFT', line, 'LEFT', textIndent, 0) Nenue@38: attachment:SetPoint('RIGHT', line, 'RIGHT') Nenue@35: print(' |cFFFF0088doing things with a widget', attachment:GetSize()) Nenue@34: line.height = attachment:GetHeight() Nenue@34: if text then Nenue@34: line.height = max(line.height, line.status:GetStringHeight()) Nenue@31: end Nenue@34: if attachment.status:GetText() then Nenue@34: line.height = max(line.height, attachment.status:GetStringHeight()) Nenue@34: end Nenue@30: attachment:Show() Nenue@30: end Nenue@30: Nenue@34: line:SetHeight(line.height) Nenue@34: block.attachmentHeight = block.attachmentHeight + line.height + textSpacing Nenue@35: Nenue@35: local debug_points = '' Nenue@35: for i = 1, line:GetNumPoints() do Nenue@35: local point, parent, anchor = line:GetPoint(i) Nenue@35: debug_points = debug_points .. tostring(parent:GetName()) .. ', ' .. anchor .. ' ' Nenue@35: end Nenue@35: Nenue@35: print(' |cFF0088FFsetting line #'..lineIndex..' for|r', block.info.title, "\n |cFF0088FFsize:|r", line.height, Nenue@35: "|cFF0088FFpoint:|r", debug_points, "|cFF0088FFwidget:|r", (line.widget and 'Y' or 'N')) Nenue@30: block.currentLine = lineIndex Nenue@36: block.endPoint = line -- edge used for the next block Nenue@31: Nenue@31: return lineIndex Nenue@28: end Nenue@28: Nenue@28: --- Creates or retrieves a complete line data object Nenue@30: Default.GetLine = function(handler, block, lineIndex) Nenue@28: local print = lprint Nenue@28: local blockIndex = block.index Nenue@30: local lines = block.lines Nenue@30: if not lineIndex then Nenue@30: lineIndex = block.currentLine + 1 Nenue@34: print(' |cFFFFFF00generating a frame') Nenue@28: end Nenue@30: Nenue@30: block.numLines = max(block.numLines, lineIndex) Nenue@30: Nenue@28: if not lines[lineIndex] then Nenue@28: print(' |cFF00FF88created line #'..lineIndex..' from for '..handler.name..' block #'..blockIndex) Nenue@28: lines[lineIndex] = CreateFrame('Frame', 'Vn'..handler.name .. blockIndex..'ObjectiveLine'..lineIndex, block, 'VeneerTrackerObjective') Nenue@28: local line = lines[lineIndex] Nenue@28: line.index = lineIndex Nenue@28: line.height = 0 Nenue@37: line.schema = '' Nenue@28: B.SetConfigLayers(line) Nenue@28: Nenue@28: if debug then Nenue@28: for _, region in ipairs(lines[lineIndex].debug) do Nenue@28: region:Show() Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: end Nenue@28: return lines[lineIndex] Nenue@28: end Nenue@28: Nenue@29: Nenue@29: Nenue@28: --- Creates or retrieves a complete block frame object Nenue@34: --- todo: make it use data index to avoid re-coloring every block Nenue@37: Default.GetBlock = function(handler, index) Nenue@28: local print = bprint Nenue@37: print('|cFF0088FFgetting a block for index', index ..',', #handler.usedBlocks,'used', #handler.freeBlocks, 'free') Nenue@37: local block = handler.InfoBlock[index] Nenue@35: local used = handler.usedBlocks Nenue@28: Nenue@34: if not block then Nenue@28: if #handler.freeBlocks >= 1 then Nenue@34: block = tremove(handler.freeBlocks) Nenue@35: tinsert(handler.usedBlocks, block) Nenue@35: block.posIndex = #handler.usedBlocks Nenue@35: print(' |cFF00FF00 assigning from free heap', block:GetName()) Nenue@28: else Nenue@34: Nenue@35: local blockIndex = (#handler.usedBlocks + #handler.freeBlocks) + 1 Nenue@30: block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, handler.frame, 'VeneerTrackerBlock') Nenue@35: --block:SetParent() Nenue@37: block.schema = '' Nenue@30: block.lines = {} Nenue@30: block.numLines = 0 Nenue@30: block.currentLine = 0 Nenue@34: block.attachmentHeight = 0 Nenue@35: block.offset = 0 Nenue@34: B.SetConfigLayers(block) Nenue@28: --- methods for event handlers Nenue@28: Nenue@28: block.Select = handler.Select Nenue@28: block.Open = handler.Open Nenue@28: block.Remove = handler.Remove Nenue@28: block.Link = handler.Link Nenue@28: block.clickZone:SetScript('OnMouseUp', function(self, ...) handler.OnMouseUp(block, ...) end) Nenue@28: block.clickZone:SetScript('OnMouseDown', function(self, ...) handler.OnMouseDown(block, ...) end) Nenue@28: block:ClearAllPoints() Nenue@34: block.index = blockIndex Nenue@35: print(' |cFF00FFBBcreating new|r', block:GetName()) Nenue@28: end Nenue@37: handler.InfoBlock[index] = block Nenue@34: tinsert(handler.usedBlocks, block) Nenue@35: block.posIndex = #handler.usedBlocks Nenue@34: else Nenue@34: print(' |cFFFFFF00use existing block|r', block:GetName()) Nenue@35: local found = false Nenue@35: for i, entry in ipairs(used) do Nenue@35: if entry == block then Nenue@35: found = true Nenue@35: break Nenue@35: end Nenue@35: end Nenue@35: if not found then Nenue@35: tinsert(used, block) Nenue@35: block.posIndex = #used Nenue@35: end Nenue@28: end Nenue@34: return block Nenue@28: end Nenue@28: Nenue@34: Nenue@30: Nenue@28: ---------- Nenue@28: --- Top level methods Nenue@28: Nenue@28: Nenue@35: T.UpdateBlockAction = function (block, itemButton) Nenue@35: local print = bprint Nenue@28: print('**|cFF0088FF'..itemButton:GetName(), '|r:Update()') Nenue@28: if itemButton.questID ~= block.info.questID then Nenue@28: print('** |cFFFF0088mismatched block assignment', itemButton.questID,'<~>', block.info.questID) Nenue@28: -- something happened between this and last frame, go back and set new probes Nenue@35: return T.UpdateActionButtons() Nenue@28: end Nenue@28: Nenue@28: local previousItem = itemButton.previousItem Nenue@28: local upper_bound = Scroller:GetTop() + Scroller.snap_upper Nenue@28: local lower_bound = Scroller:GetBottom() + Scroller.snap_lower + itemButtonSize Nenue@28: local point, anchor, relative Nenue@28: Nenue@28: if block:GetBottom() < lower_bound then Nenue@28: print('** ',block:GetName() ,'|cFFFFFF00bottom =', floor(block:GetBottom()+.5), 'threschold =', floor(lower_bound+.5)) Nenue@28: if previousItem then Nenue@28: print('adjusting', previousItem:GetName()) Nenue@28: previousItem:ClearAllPoints() Nenue@28: previousItem:SetPoint('BOTTOM', itemButton, 'TOP', 0, itemButtonSpacing) Nenue@28: end Nenue@28: itemButton:ClearAllPoints() Nenue@28: itemButton.x = Wrapper:GetLeft() -4 Nenue@28: itemButton.y = Wrapper:GetBottom() Nenue@28: point, anchor, relative = 'BOTTOMRIGHT', UIParent, 'BOTTOMLEFT' Nenue@28: Scroller.snap_lower = Scroller.snap_lower + itemButtonSize + itemButtonSpacing Nenue@28: Nenue@28: elseif block:GetTop() > upper_bound then Nenue@28: print('** ',block:GetName() ,'|cFFFFFF00top =', floor(block:GetTop()+.5), 'threschold =', floor(upper_bound+.5)) Nenue@28: itemButton:ClearAllPoints() Nenue@28: if previousItem then Nenue@28: print('latch onto another piece') Nenue@28: point, anchor, relative ='TOP', previousItem, 'BOTTOM' Nenue@28: itemButton.x = 0 Nenue@28: itemButton.y = -itemButtonSpacing Nenue@28: else Nenue@28: print('latch at corner', Scroller:GetLeft() -itemButtonSpacing, Scroller:GetTop()) Nenue@28: point, anchor, relative = 'TOPRIGHT', UIParent, 'BOTTOMLEFT' Nenue@28: itemButton.x = Scroller:GetLeft() -4 Nenue@28: itemButton.y = Scroller:GetTop() Nenue@28: end Nenue@28: itemButton:Show() Nenue@28: Scroller.snap_upper = Scroller.snap_upper - (itemButtonSize + itemButtonSpacing) Nenue@28: else Nenue@28: print('** ',block:GetName() ,'|cFF00FF00span =', floor(block:GetBottom()+.5), floor(block:GetTop()+.5), 'threschold =', floor(lower_bound+.5)) Nenue@28: itemButton:ClearAllPoints() Nenue@28: itemButton.x = block:GetLeft() - itemButtonSpacing Nenue@28: itemButton.y = block:GetTop() Nenue@28: point, anchor, relative = 'TOPRIGHT', UIParent, 'BOTTOMLEFT' Nenue@28: end Nenue@28: Nenue@28: itemButton:SetPoint(point, anchor, relative, itemButton.x, itemButton.y) Nenue@28: itemButton:Show() Nenue@28: end Nenue@28: Nenue@35: T.UpdateItemButtonCooldown = function(button) Nenue@28: Nenue@28: end Nenue@28: Nenue@35: function T:FinishWrapper () Nenue@35: if wrapperHeight > Wrapper.previousHeight then Nenue@35: Wrapper:SetHeight(wrapperHeight) Nenue@35: Scroller:SetHeight(wrapperHeight*3) Nenue@35: Scroll:SetHeight(wrapperHeight) Nenue@35: Wrapper.previousHeight = wrapperHeight Nenue@35: Wrapper.destinationHeight = wrapperHeight Nenue@35: end Nenue@35: Scroller:SetVerticalScroll(B.Conf.ObjectiveScroll or 0) Nenue@35: print('|cFF00FF00### end of wrapper layout', Wrapper:GetSize()) Nenue@35: print(' |cFF00FF00Scroller:', Scroller:GetSize()) Nenue@35: print(' |cFF00FF00Scroll:', Scroll:GetSize()) Nenue@35: for i = 1, Wrapper:GetNumPoints() do Nenue@35: print('|cFF00FF00 ', Wrapper:GetPoint(i)) Nenue@35: end Nenue@35: for i = 1, Scroller:GetNumPoints() do Nenue@35: print('|cFF00FF00 ', Scroller:GetPoint(i)) Nenue@35: end Nenue@35: for i = 1, Scroll:GetNumPoints() do Nenue@35: print('|cFF00FF00 ', Scroll:GetPoint(i)) Nenue@35: end Nenue@34: Nenue@38: if Devian and Devian.InWorkspace() then Nenue@38: Wrapper.AnimState:SetFormattedText(ANIM_STATE, animateReason) Nenue@38: end Nenue@38: Nenue@35: Wrapper:Show() Nenue@35: Scroller:Show() Nenue@35: Scroll:Show() Nenue@28: end Nenue@28: Nenue@39: Nenue@39: ----------------------------------------- Nenue@39: -- Criteria frames Nenue@39: Nenue@39: --[[ Nenue@39: text = description, Nenue@39: type = type, Nenue@39: finished = completed, Nenue@39: quantity = quantity, Nenue@39: requiredQuantity = requiredQuantity, Nenue@39: characterName = characterName, Nenue@39: flags = flags, Nenue@39: assetID = assetID, Nenue@39: quantityString = quantityString, Nenue@39: criteriaID = criteriaID, Nenue@39: ]] Nenue@39: local newWidgetID = 0 Nenue@39: T.WidgetRegistry = {} Nenue@39: local wr = T.WidgetRegistry Nenue@39: Nenue@39: --- Get a usable widget for the given achievement criteria set. Nenue@39: -- Returns a frame object with dimensioning parameters needed to size the receiving tracker block Nenue@39: T.GetWidget = function(data, objectiveType, objectiveKey) Nenue@39: local print = B.print('ObjectiveWidgets') Nenue@39: local widgetType = objectiveType Nenue@39: local widget Nenue@39: local isNew Nenue@39: if wr[widgetType] and wr[widgetType].used[objectiveKey] then Nenue@39: widget = wr[widgetType].used[objectiveKey] Nenue@39: print('|cFF00FF00Updating ('..objectiveKey..')', widget) Nenue@39: elseif not wr[widgetType] or #wr[widgetType].free == 0 then Nenue@39: -- creating a new frame Nenue@39: isNew = true Nenue@39: widget = CreateFrame(widgetType, 'VeneerObjective' .. widgetType .. (wr[widgetType] and (wr[widgetType].lastn+1) or (1)), VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType) Nenue@39: print('|cFFFF0088Creating `'..widget:GetName()..'` id', wr[widgetType].lastn) Nenue@39: T.UpdateSchema(widgetType, data.schema or 'default') Nenue@39: else Nenue@39: -- recycling for a different criteria set Nenue@39: isNew = true Nenue@39: widget = tremove(wr[widgetType].free) Nenue@39: print('|cFFFFFF00Acquiring released widget', widget:GetName()) Nenue@39: end Nenue@39: Nenue@39: Nenue@39: wr[widgetType].used[objectiveKey] = widget Nenue@39: widget.objective = data Nenue@39: widget.key = objectiveKey Nenue@39: T.InitializeWidget(widget, isNew) Nenue@39: return widget Nenue@39: end Nenue@39: Nenue@39: --- WidgetTemplate 'OnLoad' Nenue@39: T.RegisterWidget = function(frame) Nenue@39: local print = B.print('ObjectiveWidgets') Nenue@39: local widgetType = frame.widgetType Nenue@39: if not wr[frame.widgetType] then Nenue@39: print('|cFFFF4400[[WidgetTemplate]]|r', widgetType) Nenue@39: wr[widgetType] = { lastn = 1, free = {}, used = {}, usedIndex = {}, freeIndex = {} } Nenue@39: else Nenue@39: print('|cFF0088FF+ [[WidgetTemplate]]r', widgetType, wr[widgetType].lastn) Nenue@39: wr[widgetType].lastn = wr[widgetType].lastn + 1 Nenue@39: end Nenue@39: end Nenue@39: --- WidgetTemplate 'OnShow' Nenue@39: local wrapperWidth, textIndent Nenue@39: T.InitializeWidget = setmetatable({}, { Nenue@39: __call = function(t, frame, isNew, ...) Nenue@39: -- todo: config pull Nenue@39: if not wrapperWidth then Nenue@39: wrapperWidth = T.Conf.Wrapper.Width Nenue@39: textIndent = T.Conf.Wrapper.TextIndent Nenue@39: end Nenue@39: Nenue@39: tprint('Initialize', frame:GetName(), isNew, ...) Nenue@39: frame:SetWidth(wrapperWidth - textIndent * 2) Nenue@39: frame:SetScript('OnEvent', T.UpdateWidget[frame.widgetType]) Nenue@39: frame:RegisterEvent('QUEST_LOG_UPDATE') Nenue@39: frame:RegisterEvent('TRACKED_ACHIEVEMENT_UPDATE') Nenue@39: frame:RegisterEvent('TRACKED_ACHIEVEMENT_LIST_CHANGED') Nenue@39: frame:RegisterEvent('CRITERIA_UPDATE') Nenue@39: frame:RegisterEvent('CRITERIA_COMPLETE') Nenue@39: frame:RegisterEvent('CRITERIA_EARNED') Nenue@39: t[frame.widgetType](frame, isNew) Nenue@39: T.UpdateWidget[frame.widgetType](frame, isNew) Nenue@39: end, Nenue@39: }) Nenue@39: Nenue@39: --- WidgetTemplate 'OnEvent' Nenue@39: T.UpdateWidget = setmetatable({}, { Nenue@39: __call = function(t, frame, isNew, ...) Nenue@39: tprint('Update', frame:GetName(), isNew, ...) Nenue@39: if not frame.widgetType then Nenue@39: return Nenue@39: end Nenue@39: Nenue@39: return t[frame.widgetType](frame, isNew) Nenue@39: end Nenue@39: }) Nenue@39: Nenue@39: Nenue@39: local progressHeight = 17 Nenue@39: local progressBorder = 1 Nenue@39: local progressFont = _G.VeneerCriteriaFontNormal Nenue@39: Nenue@39: local lprint = B.print('Line') Nenue@39: T.InitializeWidget.StatusBar = function(self, isNew) Nenue@39: local print = lprint Nenue@39: local c = T.Conf.Wrapper Nenue@39: Nenue@39: tprint(self:GetName(), isNew) Nenue@39: if isNew then Nenue@39: self.maxValue = self.maxValue or 1 Nenue@39: self:SetMinMaxValues(0, self.maxValue) Nenue@39: Nenue@39: self:SetHeight(widgetHeight) Nenue@39: self.height = widgetHeight Nenue@39: Nenue@39: self.status:SetFont(widgetTextFont, widgetTextSize, widgetTextOutline) Nenue@39: self.status:SetTextColor(unpack(widgetTextColor)) Nenue@39: end Nenue@39: self.value = self.value or 1 Nenue@39: self:SetValue(self.value) Nenue@39: Nenue@39: self.status:SetText(self.objective.quantityString) Nenue@39: end Nenue@39: Nenue@39: T.UpdateWidget.StatusBar = function (self) Nenue@39: local value, maxValue = self.value, self.maxValue Nenue@39: print('update vals:') Nenue@39: for k,v in pairs(self) do Nenue@39: print(k, v) Nenue@39: end Nenue@39: self.width = self.width or self:GetWidth() Nenue@39: self:SetValue(self.value) Nenue@39: local format = self.format or '%d/%d' Nenue@39: self.status:SetFormattedText(format, value, maxValue) Nenue@39: local progress = (value / maxValue) Nenue@39: if progress > 0 then Nenue@39: print('color:', 1-progress*2 , progress*2 - 1,0,1) Nenue@39: print('width:', (self.width -progressBorder * 2) * progress) Nenue@39: self:SetStatusBarColor(1-progress*2 , progress*2,0,1) Nenue@39: end Nenue@39: end Nenue@39: Nenue@39: Nenue@39: T.InitializeWidget.Hidden = function (self) Nenue@39: self.height = 0 Nenue@39: end Nenue@39: T.UpdateWidget.Hidden = function (self) Nenue@39: self.height= 0 Nenue@39: end Nenue@39: Nenue@39: Nenue@39: --- Queue any active item buttons for update for that frame Nenue@39: local iprint = B.print('ItemButton') Nenue@39: local Quest = T.Quest Nenue@39: local IsQuestWatched, InCombatLockdown = IsQuestWatched, InCombatLockdown Nenue@39: T.UpdateActionButtons = function(updateReason) Nenue@39: local print = iprint Nenue@39: Scroller.snap_upper = 0 Nenue@39: Scroller.snap_lower = 0 Nenue@39: local print = B.print('ItemButton') Nenue@39: if updateReason then Nenue@39: print = B.print('IB_'..updateReason) Nenue@39: end Nenue@39: Nenue@39: local previousItem Nenue@39: for questID, itemButton in pairs(Quest.itemButtons) do Nenue@39: local info= T.Quest.Info[questID] Nenue@39: Nenue@39: print('|cFF00FFFF'.. questID .. '|r', itemButton:GetName()) Nenue@39: local block = T.Quest.QuestBlock[questID] Nenue@39: if block then Nenue@39: -- Dispatch the probe Nenue@39: if IsQuestWatched(info.logIndex) then Nenue@39: itemButton.previousItem = previousItem Nenue@39: print(' |cFFFFFF00probing', block:GetName()) Nenue@39: block:SetScript('OnUpdate', function() Nenue@39: if block:GetBottom() and not InCombatLockdown() then Nenue@39: print(' '..block:GetName()..' |cFF00FF00probe hit!') Nenue@39: T.UpdateBlockAction(block, itemButton, itemButton.previousItem) -- needs to be previousItem from this scope Nenue@39: block:SetScript('OnUpdate', nil) Nenue@39: Nenue@39: end Nenue@39: end) Nenue@39: previousItem = itemButton Nenue@39: else Nenue@39: print('hidden block or unwatched quest') Nenue@39: itemButton.previousItem = nil Nenue@39: itemButton:Hide() Nenue@39: end Nenue@39: elseif itemButton:IsVisible() then Nenue@39: print(' |cFFFF0088hiding unwatched quest button', itemButton:GetName()) Nenue@39: itemButton.previousItem = nil Nenue@39: itemButton:Hide() Nenue@39: else Nenue@39: print(' |cFFBBBBBBignoring hidden log quest button', itemButton:GetName()) Nenue@39: end Nenue@39: end Nenue@39: end