Mercurial > wow > buffalo2
view ObjectiveFrame.lua @ 5:e9b61fd5f607
- use IsQuestWatched as the determinant for setting action button updates
- check for block match-up in deferred action button updates
author | Nenue |
---|---|
date | Thu, 31 Mar 2016 15:58:08 -0400 |
parents | 18eee961038e |
children | 589de8ea05b9 |
line wrap: on
line source
--- ${PACKAGE_NAME} -- @file-author@ -- @project-revision@ @project-hash@ -- @file-revision@ @file-hash@ -- Created: 3/30/2016 12:49 AM local B = select(2,...).frame local ipairs, max, min, unpack, floor, pairs, tostring, type = ipairs, max, min, unpack, floor, pairs, tostring, type local IsResting, UnitXP, UnitXPMax, GetXPExhaustion = IsResting, UnitXP, UnitXPMax, GetXPExhaustion local UnitLevel, IsQuestWatched, UIParent = UnitLevel, IsQuestWatched, UIParent local CreateFrame = CreateFrame local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') local print = B.print('Objectives') -------------------------------------------------------------------- --- Global frame layout -------------------------------------------------------------------- --- Upvalues local Wrapper = VeneerObjectiveWrapper local Scroller = Wrapper.scrollArea local Scroll = VeneerObjectiveScroll local orderedHandlers = mod.orderedHandlers local orderedNames = mod.orderedNames --- Temp values set during updates local wrapperWidth, wrapperHeight local scrollWidth, scrollHeight local previousBlock local currentBlock --- todo: map these into config table when its sorted out local titleFont, textFont = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Regular.ttf]] local titleSize, textSize = 15, 15 local titleOutline, textOutline = "OUTLINE", "OUTLINE" local titleSpacing, textSpacing = 4, 3 local textIndent = 5 local wrapperMaxWidth, wrapperMaxHeight = 280, 490 -- these are the hard bounds, actual *Height variables are changed local wrapperHeadFont, wrapperHeadSize, wrapperHeadOutline = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 16, 'NONE' local headerFont, headerSize, headerHeight = [[Interface\Addons\SharedMedia_MyMedia\font\ArchivoNarrow-Bold.ttf]], 18, 24 local headerOutline, headerColor, headerSpacing = 'OUTLINE', {1,1,1,1}, 2 local wrapperPosition = {'RIGHT', UIParent, 'RIGHT', -84, 0} --- These are mostly aesthetic choices so it lives here mod.defaults = { ObjectiveTrackerAnchor = {'BOTTOM', 'RIGHT'}, ObjectiveTrackerParent = 'DebuffButton', ObjectiveTrackerSize = {250, 600}, ObjectiveWrapperParent = '', WrapperStyle = { Header = { Background = {Left = [[Objective-Header]], Right = [[Objective-Header]], Tile = [[Objective-Header]]}, BackgroundCrop = {Left = {0, 0.4, 0,1}, Right={0.6,1,0,1}, Tile = {0.4,.6,0,1,}}, BackgroundScale = {Left = 100, Right = 100}, Font = {wrapperHeadFont, wrapperHeadSize, wrapperHeadOutline} } }, ObjectiveHeaderStyle = { Normal = { Gradient = {MinColor = {0,0,0,0.5}, MaxColor = {0,0,0,.25}}, Font = {headerFont, headerSize, headerOutline}, Spacing = headerSpacing, } }, ObjectiveTrackerStyle = { Normal = { Title = { Gradient = { MinColor = {0.2, .4, 1, 0.45}, MaxColor = {.7, 0, 0.9, 0}}, Font = {titleFont, titleSize, titleOutline}, Spacing = titleSpacing, }, Text = { Gradient = { MinColor = {0.2, .4, 1, 0.25}, MaxColor = {.7, 0, 0.9, 0}}, Font = {textFont, textSize, textOutline}, Spacing = textSpacing, }, }, Super = { Title = { Gradient = { MinColor = {0, .7, .6, .8}, MaxColor = {0, .7, .6, 0.2}}, Font = {titleFont, titleSize, titleOutline}, Spacing = titleSpacing, BackgroundFullWidth = true }, Text = { Gradient = { MinColor = {0, .7, .6, 0.5}, MaxColor = {0, .7, .6, 0.1} }, Font = {textFont, textSize, textOutline}, Spacing = textSpacing, }, }, Active = { Title = { Gradient = { MinColor = {0.2, .4, 1, 1}, MaxColor = {0.2, .4, 1, 1}, }, Font = {titleFont, titleSize, titleOutline}, Spacing = titleSpacing, BackgroundFullWidth = true }, Text = { Gradient = { MinColor = {0.2, .4, 1, 1}, MaxColor = {0.2, .4, 1, 1}, }, Font = {textFont, textSize, textOutline}, Spacing = textSpacing, BackgroundFullWidth = true } }, Complete = { Title = { Gradient = { MinColor = {0, 1, 0, 0.34}, MaxColor = {0, 1, 0, .17}, }, Font = {titleFont, titleSize, titleOutline}, Spacing = titleSpacing, BackgroundFullWidth = true }, Text = { Gradient = { MinColor = {0, 1, 0, .25}, MaxColor = {0, 1, 0, 0.12}, }, Font = {textFont, textSize, textOutline}, Spacing = textSpacing, BackgroundFullWidth = true } }, } } local FontBank = { ['Normal'] = VeneerCriteriaFontNormal, ['Progress'] = VeneerCriteriaFontProgress, ['Complete'] = VeneerCriteriaFontComplete, ['Failed'] = VeneerCriteriaFontFailed, } local Scroller_OnShow = function() Wrapper.watchMoneyReasons = 0; mod.UpdateWrapper() mod.SetEvents() for i, region in ipairs(Wrapper.header) do region:Show() end end local Scroller_OnHide = function() local self = Wrapper Wrapper:UnregisterAllEvents() Wrapper:SetScript('OnEvent', nil) for i, region in ipairs(Wrapper.header) do region:Hide() end end local Scroller_OnMouseWheel = function(self, delta) local r = Scroll:GetHeight() - Scroller:GetHeight() local s = self:GetVerticalScroll() - delta * floor(r/5+.5) if r == 0 then return end if s >= r then s = r elseif s < 1 then s = 0 end self:SetVerticalScroll(s) print(s, r, self:GetVerticalScroll()) mod.UpdateActionButtons() end local WrapperCloseButton_OnClick = function(self) if Scroller:IsVisible() then Scroller:Hide() else Scroller:Show() end end mod.InitializeTrackers = function() local c = mod.defaults.ObjectiveHeaderStyle.Normal local g1, g2, g3, g4 = unpack(c.Gradient.MinColor) local h1, h2, h3, h4 = unpack(c.Gradient.MaxColor) for i, name in ipairs(orderedNames) do if not mod.orderedHandlers[i] then if mod.Tracker(name, i) then local handler = mod[name] local tracker = CreateFrame('Frame', 'Veneer'..name..'Tracker', Scroll, 'VeneerTrackerTemplate') tracker.header:SetText(handler.name) tracker.header:SetHeight(headerHeight) tracker.header:SetFont(unpack(c.Font)) tracker.header:SetTextColor(unpack(headerColor)) tracker.headerbg:SetGradientAlpha('HORIZONTAL', g1, g2 ,g3, g4, h1, h2, h3, h4) tracker.headerbg:SetHeight(headerHeight) handler.Tracker = tracker mod.orderedTrackers[i] = tracker mod.namedTrackers[name] = tracker mod.indexedTrackers[handler] = tracker print('created new tracker frames for new handler') end end end Scroller:SetScrollChild(Scroll) Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel) Scroller:SetScript('OnShow', Scroller_OnShow) Scroller:SetScript('OnHide', Scroller_OnHide) Wrapper.close:SetScript('OnClick', WrapperCloseButton_OnClick) Wrapper:SetPoint(unpack(wrapperPosition)) Scroller_OnShow(Scroller) mod.UpdateWrapperStyle() end mod.InitializeXPTracker = function() local XPBar = Wrapper.XPBar if UnitLevel('player') == 100 then XPBar:Hide() return end --- xp bar XPBar:Show() XPBar.rested:SetTexture(2,.6,1,1) XPBar.fg:SetTexture(.3,.1,.95,1) XPBar.bg:SetTexture(0,0,0,.25) XPBar:RegisterEvent('PLAYER_XP_UPDATE') XPBar:RegisterEvent('PLAYER_LEVEL_UP') XPBar:RegisterEvent('PLAYER_UPDATE_RESTING') XPBar:SetScript('OnEvent', mod.UpdateXP) mod.UpdateXP(Wrapper.xpBar) end mod.UpdateXP = function() local XPBar = Wrapper.XPBar local xp = UnitXP('player') local xpmax = UnitXPMax('player') local rest = GetXPExhaustion() XPBar.bg:SetAllPoints(XPBar) XPBar.fg:SetWidth((xp/xpmax) * XPBar:GetWidth()) if IsResting() then XPBar.bg:SetTexture(.2,.8,.2,.5) else XPBar.bg:SetTexture(0,0,0,.25) end if rest then XPBar.rested:ClearAllPoints() if xp == 0 then XPBar.rested:SetPoint('TOPLEFT', XPBar, 'TOPLEFT', 0, 0) else XPBar.rested:SetPoint('TOPLEFT', XPBar.fg, 'TOPRIGHT', 0, 0) end if (xp + rest) > xpmax then XPBar.rested:SetPoint('BOTTOMRIGHT', XPBar, 'BOTTOMRIGHT', 0, 0) else XPBar.rested:SetWidth((rest/xpmax) * XPBar:GetWidth()) end XPBar.rested:SetPoint('BOTTOM', XPBar, 'BOTTOM') XPBar.rested:Show() else XPBar.rested:Hide() end XPBar.xpText:SetText(xp .. '/'.. xpmax .. (rest and (' ('..tostring(rest)..')') or '')) end mod.UpdateReputation = function(self) end --- Argument containers local a1, a2, a3, a4, b1, b2, b3, b4, f1, f2, f3, w1, w2 mod.SetBlockStyle = function(block, name) -- var names intended to reflect argument order --@debug@ local c = mod.defaults.ObjectiveTrackerStyle[name] --@end-debug@ --[===[@non-debug local c = mod.Conf --@end-non-debug]===] a1, a2, a3, a4 = unpack(c.Title.Gradient.MinColor) b1, b2, b3, b4 = unpack(c.Title.Gradient.MaxColor) block.titlebg:SetGradientAlpha('HORIZONTAL', a1, a2, a3, a4, b1, b2, b3, b4) a1, a2, a3, a4 = unpack(c.Text.Gradient.MinColor) b1, b2, b3, b4 = unpack(c.Text.Gradient.MaxColor) block.bg:SetGradientAlpha('HORIZONTAL', a1, a2, a3, a4, b1, b2, b3, b4) f1, f2, f3 = unpack(c.Title.Font) block.title:SetFont(f1, f2, f3) f1, f2 ,f3 = unpack(c.Text.Font) block.objectives:SetFont(f1,f2,f3) w1 = Wrapper:GetWidth() w2 = (c.Title.BackgroundFullWidth and w1 or block.title:GetStringWidth()) local titleSpacing, titleSpacing2 = c.Title.Spacing, (c.Title.Spacing * 2) local textSpacing, textSpacing2 = c.Text.Spacing, (c.Text.Spacing * 2) if block.info.isTrivial then block.title:SetTextColor(0.7, 0.7, 0.7, 1) elseif block.info.isComplete then block.title:SetTextColor(1,1,1,1) else block.title:SetTextColor(0,.7,1,1) end block.title:SetSpacing(titleSpacing) block.objectives:SetSpacing(textSpacing) block.objectives:SetWordWrap(true) local titleHeight, textHeight = block.title:GetStringHeight(), block.objectives:GetStringHeight() local blockHeight = titleHeight + titleSpacing2 + textHeight + textSpacing2 local blockWidth = wrapperMaxWidth block.titlebg:SetSize(min(w1, w2), titleHeight + titleSpacing2) block.bg:SetSize(w1, textHeight + textSpacing2) block:SetSize(blockWidth, blockHeight) block.title:SetPoint('TOPLEFT', block.titlebg, 'TOPLEFT', 0, -titleSpacing) block.objectives:SetPoint('TOPLEFT', block.titlebg, 'BOTTOMLEFT', textIndent, -textSpacing) -- store block.titleHeight = titleHeight block.textHeight = textHeight block.width = blockWidth block.height = blockHeight print(' |cFF00FFFF'..block:GetName()..'|r:|cFF0088FFSetStyle|r(', blockWidth, 'x', blockHeight, '(textH', textHeight,', titleH', titleHeight, ')') end local segments = {'Left', 'Right', 'Tile'} mod.UpdateWrapperStyle = function() local c = mod.defaults.WrapperStyle for _, segment in ipairs(segments) do Wrapper['Background'..segment]:SetAtlas(c.Header.Background[segment]) Wrapper['Background'..segment]:SetTexCoord(unpack(c.Header.BackgroundCrop[segment])) if c.Header.BackgroundScale[segment] then Wrapper['Background'..segment]:SetWidth(c.Header.BackgroundScale[segment]) end end end --- Updates the selected block frame to display the given info batch -- If `previousBlock` is set, it will attempt to anchor to that -- @param blockNum the ordered block to be updated, not a watchIndex value -- @param info the reference returned by the GetXInfo functions -- REMEMBER: t.info and questData[questID] are the same table mod.UpdateTrackerBlock = function (handler, blockIndex, info) print(' |cFF00FFFFUpdateTrackerBlock('..blockIndex..'|r') if not blockIndex or not info then return end local tracker = handler.Tracker local t = handler:GetBlock(blockIndex) if previousBlock then if blockIndex == 1 then t:SetPoint('TOPLEFT', previousBlock, 'TOPLEFT', 0, -headerHeight) else t:SetPoint('TOPLEFT', previousBlock, 'BOTTOMLEFT', 0, 0) end t:SetPoint('RIGHT', tracker,'RIGHT', 0, 0) end --print(t:GetName(), t:GetSize()) --print(t:GetPoint(1)) t.info = info if info.questID then handler.QuestBlock[info.questID] = t end if info.questLogIndex then handler.LogBlock[info.questLogIndex] = t end if info.watchIndex then handler.WatchBlock[info.watchIndex] = t end info.blockIndex = blockIndex handler.BlockInfo[blockIndex] = info t.Select = handler.Select t.Open = handler.Open t.Remove = handler.Remove t.Link = handler.Link t:SetScript('OnMouseUp', handler.OnMouseUp) t:SetScript('OnMouseDown', handler.OnMouseDown) t.title:SetText(info.title) if info.isComplete then t.objectives:Show() t.objectives:SetText(info.completionText) elseif info.numObjectives >= 1 then t.objectives:Show() print(' - objective lines:', info.numObjectives, 'can wrap:', t.objectives:CanWordWrap()) local text = '' if info.description then print(' -- has description text:', select('#', info.description), info.description) text = info.description end --- todo: implement objective displays -- in an accumulator loop, call upon handler for the appropriate display frame, each defining: -- * height of whatever display widget is involved in conveying the task -- * number of non-wrapped text lines to account for line space; may be discarded depending on things -- * boolean that determines listening for money events or not t.attachmentHeight, text = mod.UpdateObjectives(t, info, text) t.objectives:SetText(text) t.objectives:SetWordWrap(true) elseif info.description then t.objectives:SetText(info.description) t.objectives:SetWordWrap(true) else t.objectives:SetText(nil) end local style = 'Normal' if info.isComplete then style = 'Complete' elseif info.superTracked then style = 'Super' end if info.specialItem and not info.itemButton then print(' - |cFF00FFFFgenerating item button for info set') info.itemButton = mod.SetItemButton(t, info) else --info.itemButton = nil end --- metrics are calculated in SetStyle t:SetStyle(style) t:Show() print(' |cFF00FFFF)|r -> ', t, t:GetHeight()) return t end mod.UpdateObjectives = function(block, info, text) local attachmentHeight = 0 for o, obj in ipairs(info.objectives) do --- achievement criteria if obj.flags then if bit.band(obj.flags, 0x00000001) > 0 then obj.type = 'ProgressBar' obj.widget = mod.SetWidget(obj, info) elseif bit.band(obj.flags, 0x00000002) then obj.type = 'Hidden' obj.widget = nil else obj.type = 'Text' obj.widget = nil text = text .. ((text == '') and "" or "\n") .. obj.text end print(obj.type, obj.text, obj.quantityString) --- none of the above (most quests) else local line = obj.text local color = '00FFFF' if obj.finished then color = 'FFFFFF' elseif obj.type == 'monster' then color = 'FFFF00' elseif obj.type == 'item' then color = '44DDFF' elseif obj.type == 'object' then color = 'FF44DD' end text = text .. ((text == '') and "" or "\n") .. '|cFF'..color.. line .. '|r' end if obj.widget then attachmentHeight = attachmentHeight + obj.widget.height end end return attachmentHeight, text end mod.UpdateTracker = function(handler) print('|cFF00FF88UpdateTracker(|r|cFFFF4400' .. type(handler) .. '|r :: |cFF88FFFF' .. tostring(handler) .. '|r') local tracker = handler.Tracker local blockIndex = 0 local trackerHeight = headerHeight local w = 300 previousBlock = handler.Tracker local numWatched = handler.GetNumWatched() local numBlocks = handler.numBlocks local actualBlocks = handler.actualBlocks for watchIndex = 1, 25 do blockIndex = blockIndex + 1 if watchIndex <= numWatched then local info = handler:GetInfo(watchIndex) if info then local currentBlock = mod.UpdateTrackerBlock(handler, blockIndex, info) previousBlock = currentBlock trackerHeight = trackerHeight + currentBlock.height numBlocks = max(numBlocks, watchIndex) actualBlocks = actualBlocks + 1 else print('|cFFFF0000Failed to draw info for index #'..watchIndex) end elseif watchIndex <= numBlocks then local used = handler.usedBlocks local free = handler.freeBlocks print('clean up dead quest block') if used[blockIndex] then used[blockIndex]:Hide() used[blockIndex]:ClearAllPoints() free[#free+1]= used[blockIndex] used[blockIndex] = nil end else print('Stopping scan at', blockIndex) break -- done with quest stuff end end handler.numWatched = numWatched handler.numBlocks = numBlocks handler.actualBlocks = actualBlocks handler:Report() previousBlock = nil if numBlocks > 0 then tracker.height = trackerHeight else tracker.height = 0 end print('|cFF00FF88)|r ->', numBlocks, 'blocks; height', tracker.height, 'last block: ') end mod.Quest.numButtons = 0 local usedButtons = mod.Quest.itemButtons local freeButtons = mod.Quest.freeButtons mod.UpdateWrapper = function() wrapperWidth = wrapperMaxWidth scrollWidth = wrapperWidth local wrapperBlocks = 0 -- Update scroll child vertical size scrollHeight = 0 for i, handler in ipairs(orderedHandlers) do mod.UpdateTracker(handler) if handler.actualBlocks >= 1 then local tracker = handler.Tracker print('setting', handler.Tracker, 'to anchor to offset', -scrollHeight) tracker:SetParent(Scroll) -- this doesn't do anything that relativeTo doesn't tracker:SetPoint('TOPLEFT', Scroll, 'TOPLEFT', 0, - scrollHeight) tracker:SetSize(wrapperWidth, tracker.height) print('adding ', tracker.height) scrollHeight = scrollHeight + tracker.height end wrapperBlocks = wrapperBlocks + handler.actualBlocks end print('final scrollHeight:', scrollHeight) -- Update frame dimensions if scrollHeight > wrapperMaxHeight then print(' is larger than', wrapperMaxHeight) --ScrollBar:Show() --scrollWidth = wrapperMaxWidth - scrollBarWidth wrapperHeight = wrapperMaxHeight -- Make ThumbTexture reflect the viewing scale (smaller for longer scroll, bigger for shorter) --ScrollBar:GetThumbTexture():SetHeight((wrapperMaxHeight/scrollHeight) * (wrapperMaxHeight)) --ScrollBar:SetWidth(scrollBarWidth) --ScrollBar:SetPoint('TOPRIGHT', Scroller, 'TOPRIGHT', 0, 0) --ScrollBar:SetPoint('BOTTOMLEFT', Scroller, 'BOTTOMRIGHT', -scrollBarWidth, 0) --ScrollBar:SetMinMaxValues(1, scrollHeight - wrapperMaxHeight) else --ScrollBar:Hide() wrapperHeight = scrollHeight end scrollWidth = floor(scrollWidth+.5) scrollHeight = floor(scrollHeight+.5) wrapperWidth = floor(wrapperWidth+.5) wrapperHeight = floor(wrapperHeight+.5) headerHeight = floor(headerHeight+.5) if wrapperBlocks >= 1 then for i, region in ipairs(Wrapper.header) do region:Show() end else for i, region in ipairs(Wrapper.header) do region:Hide() end return end --wrapperHeight = scrollHeight print('|cFFFFFF00params:|r scroller:', scrollWidth, 'x', scrollHeight) print('|cFFFFFF00params:|r scroll:', scrollWidth, 'x', scrollHeight) print('|cFFFFFF00params:|r wrapper:', wrapperWidth, 'x', wrapperHeight) print('|cFFFFFF00params:|r header:', headerHeight) Scroller:SetSize(wrapperWidth, wrapperHeight) Scroller:SetPoint('TOPLEFT', Wrapper, 'TOPLEFT', 0, -headerHeight) Scroller:SetPoint('BOTTOMRIGHT', Wrapper, 'BOTTOMRIGHT') Scroll:SetSize(scrollWidth, scrollHeight) Scroll:SetPoint('TOPLEFT', Scroller, 'TOPLEFT', 0, 0) Scroll:SetPoint('RIGHT', Scroller, 'RIGHT') --Scroller:UpdateScrollChildRect() Wrapper:SetSize(wrapperWidth, wrapperHeight + headerHeight) -- update action buttons print('scroll size:', Scroll:GetSize()) print('scroller size:',Scroller:GetSize()) print('wrapper size:', Wrapper:GetSize()) print('scroll range :', floor(Scroller:GetVerticalScrollRange()+.5)) mod.UpdateActionButtons() end --- Queue any active item buttons for update for that frame mod.UpdateActionButtons = function() local previousItem for questID, itemButton in pairs(usedButtons) do local questIndex = mod.Quest.Info[questID].questLogIndex print('|cFF00FFFF'.. questID .. '|r', itemButton:GetName()) local block = mod.Quest.QuestBlock[questID] if block then -- Dispatch the probe if IsQuestWatched(questIndex) then print(' |cFFFFFF00probing', block:GetName()) block:SetScript('OnUpdate', function() if block:GetBottom() and not InCombatLockdown() then print(' '..block:GetName()..' |cFF00FF00probe hit!') mod.UpdateBlockAction(block, itemButton, previousItem) block:SetScript('OnUpdate', nil) end end) else print('hidden block or unwatched quest') itemButton:Hide() end else print(' |cFFFF0088missing block data', itemButton:GetName()) end end end mod.UpdateBlockAction = function (block, itemButton, previousItem) print('**|cFF0088FF'..itemButton:GetName(), '|r:Update()') if itemButton.questID ~= block.info.questID then print('** |cFFFF0088mismatched block assignment', itemButton.questID,'<~>', block.info.questID) return mod.UpdateActionButtons() end if block:GetBottom() < Scroller:GetBottom() then print('** ',block:GetName() ,'|cFFFFFF00bottom not fully visible') if previousItem then previousItem:ClearAllPoints() previousItem:SetPoint('BOTTOM', itemButton, 'TOP', 0, 4) end itemButton:ClearAllPoints() itemButton:SetPoint('BOTTOMRIGHT', UIParent, 'BOTTOMLEFT', Wrapper:GetLeft(), Wrapper:GetBottom()) itemButton:Show() else print('** ',block:GetName() ,'|cFF00FF00visible positions') itemButton:ClearAllPoints() itemButton:SetPoint('TOPRIGHT', UIParent, 'BOTTOMLEFT', block:GetLeft(), block:GetTop()) itemButton:Show() end end mod.UpdateItemButtonCooldown = function(button) end