diff Veneer_Objectives/ObjectiveTracker.lua @ 77:51f248dc0276

setup working copy dingaling
author Nenue
date Sat, 27 Aug 2016 10:51:08 -0400
parents
children 0784b87f9722
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Veneer_Objectives/ObjectiveTracker.lua	Sat Aug 27 10:51:08 2016 -0400
@@ -0,0 +1,559 @@
+-- Veneer
+-- ObjectiveTracker.lua
+-- Created: 8/16/2016 8:19 AM
+-- %file-revision%
+-- This is more or less a copy of the blizzard code with some customization stuff added
+
+local plugin = VeneerObjectives
+local vn, print = LibStub("LibKraken").register(Veneer, VeneerObjectives)
+local ot
+local otvn
+
+local band, floor, min = bit.band, math.floor, math.min
+
+
+local X_QUEST						= 0x00001;
+local X_QUEST_ADDED				= 0x00002;
+local X_TASK_ADDED					= 0x00004;
+local X_WORLD_QUEST_ADDED			= 0x00008;
+local X_SCENARIO					= 0x00010;
+local X_SCENARIO_NEW_STAGE			= 0x00020;
+local X_ACHIEVEMENT				= 0x00040;
+local X_ACHIEVEMENT_ADDED			= 0x00080;
+local X_SCENARIO_BONUS_DELAYED		= 0x00100;
+local X_SUPER_TRACK_CHANGED		= 0x00200;
+-- these are for the specific module ONLY!
+local X_MODULE_QUEST				= 0x00400;
+local X_MODULE_AUTO_QUEST_POPUP	= 0x00800;
+local X_MODULE_BONUS_OBJECTIVE		= 0x01000;
+local X_MODULE_WORLD_QUEST			= 0x02000;
+local X_MODULE_SCENARIO			= 0x04000;
+local X_MODULE_ACHIEVEMENT			= 0x08000;
+local X_SCENARIO_SPELLS			= 0x10000;
+-- special updates
+local X_STATIC						= 0x0000;
+local X_ALL						= 0xFFFF;
+
+-- state information
+local X_REASON = X_ALL;		-- default
+local X_MONEY = 0
+local X_ANIMATION = 0
+local X_ID = 0;
+
+local INSET_V = -20
+
+
+
+local trackerWidth = 240
+local blockIndent = 12
+local blockSpacing = 3
+
+local tracker = {
+  freeBlocks = {},
+  usedBlocks = {},
+  freeProgressBars = {},
+  usedProgressBars = {},
+  freeTimers = {},
+  usedTimers = {},
+  freeLines = {},
+
+  headerText = 'Default Header',
+  contentHeight = 0,
+  animationHeight = 0,
+  updateReasonModule = 0,
+  updateReasonEvents = 0,
+}
+local GetTrackerHandler = function(handler)
+  handler = handler or {}
+  setmetatable(handler, {__index=tracker})
+  return handler
+end
+
+local Header_OnAnimationStart = function (self, forced)
+  local header = self:GetParent()
+  header.animating = true
+  plugin:UpdateAnimation(header)
+end
+
+local Header_OnAnimationFinished = function (self, forced)
+  local header = self:GetParent()
+  header.animating = nil
+  plugin:Update(X_ANIMATION)
+end
+
+-- reset generic flags for layout compilation
+function tracker:InitLayout (isStatic)
+  print('|cFF00FFFFlayout|r', self.headerText)
+  self.firstBlock = nil
+  self.lastBlock = nil
+  self.currentBlock = nil
+  self.oldContentHeight = self.contentHeight
+  self.oldAnimationHeight = self.animationHeight
+  self.numBlocks = 0
+  for id, block in pairs(self.usedBlocks) do
+    block.used = nil
+  end
+  if not isStatic then
+    self.hasSkippedBlocks = false
+  end
+
+  if not self.header then
+    self:SetHeader(self.headerText, X_REASON)
+    self.header:SetPoint('TOPLEFT', plugin, 'TOPLEFT', 0, -plugin.contentHeight)
+    plugin.contentHeight = plugin.contentHeight + self.header:GetHeight()
+  end
+
+
+  self.contentHeight = 0
+
+end
+
+-- clear out generic flags and set aside block frames for re-use
+tracker.EndLayout = function(self)
+  self.lastBlock = self.currentBlock
+  for id, block in pairs(self.usedBlocks) do
+    if not block.used then
+      self:FreeBlock(block)
+    end
+  end
+end
+
+function tracker:SetHeader (text, animateReason)
+  if self.header then
+    return self.header
+  end
+
+  local block = CreateFrame('Button', nil, plugin, 'VeneerObjectiveHeader')
+  block.handler = self
+  block.text:SetText(self.headerText)
+
+  self.currentBlock = block
+  self.header = block
+  return block
+end
+
+function tracker:FreeBlock(block)
+  self.usedBlocks[block.id] = nil
+  print('|cFF0088FFfree|r', block:GetName())
+  tinsert(self.freeBlocks, block)
+
+  block.numLines = 0
+  block:SetHeight(0)
+  block:Hide()
+end
+
+-- should only be used in an N-lastN loop
+function tracker:FreeLine(line)
+  if line.block then
+    line.block.lines[line.index] = nil
+  end
+  print('|cFF0088FFfree|r', line:GetName())
+  local freeLines = line.type or self.freeLines
+  tinsert(freeLines, line)
+end
+
+local blocksn = 0
+tracker.GetBlock = function(self, id)
+  local block = self.usedBlocks[id]
+  if not block then
+    local numFree = #self.freeBlocks
+    if numFree >= 1 then
+      block = tremove(self.freeBlocks, numFree)
+    else
+      blocksn = blocksn + 1
+      block = CreateFrame('Button', 'OTVNBlock'..blocksn, plugin, 'VeneerObjectiveBlock')
+      block.lines = {}
+    end
+    self.usedBlocks[id] = block
+    block.id = id
+    block.handler = self
+  end
+
+  block.used = true
+  block.currentLine = nil
+  block.numLines = 0
+
+  if block.lines then
+    for i, line in ipairs(block.lines) do
+      line.used = nil
+    end
+  end
+
+  block.contentHeight = blockSpacing
+  block:SetWidth(trackerWidth)
+  block:SetHeight(0)
+
+  return block
+end
+
+-- obtain line
+local linesn = 0
+function tracker:GetLine(block, index, lineType)
+  local line = block.lines[index]
+  if line and line.lineType ~= lineType then
+
+    tinsert(self.freeLines, line)
+    line = nil
+  end
+
+  if not line then
+    local freeLines = (lineType and lineType.freeLines) or self.freeLines
+    local numFreeLines = #freeLines
+    if numFreeLines >= 1 then
+      line = tremove(freeLines, numFreeLines)
+    else
+      linesn = linesn + 1
+      line = CreateFrame('Frame', 'OTVNLine'.. linesn, block, (lineType and lineType.template) or 'VeneerObjectiveLine')
+    end
+    line:SetParent(block)
+  end
+
+  line.type = lineType
+  line.index = index
+  line.used = true
+  line.block = block
+  line.text:SetPoint('TOPLEFT', line, 'TOPLEFT', blockIndent, 0)
+  line:SetHeight(0) -- in order for GetStringHeight to be useful
+
+  block.lines[index] = line
+
+  return line
+end
+
+function tracker:AddProgressBar(block, line, questID)
+end
+
+function tracker:FreeProgressBar(block, line)
+end
+
+function tracker:AddTimerBar(block, line, duration, startTime)
+end
+
+function tracker:FreeTimerBar(block, line)
+end
+
+-- Checks for space and anchors or frees the block accordingly
+function tracker:AddBlock (block, force)
+  local anchor = self.currentBlock or self.header
+  self.numBlocks = self.numBlocks + 1
+
+  if block.header then
+    print('header!', floor(block.contentHeight), '+', floor(block.header:GetStringHeight()))
+    block.contentHeight = block.contentHeight + block.header:GetStringHeight()
+    self.used = true
+  end
+
+
+  if self.currentBlock then
+    self.currentBlock.nextBlock = block
+    block.prevBlock = self.currentBlock
+  else
+    self.firstBlock = block
+  end
+
+  self.contentHeight = self.contentHeight + block.contentHeight
+  self.currentBlock = block
+
+  if not plugin.currentBlock then
+    plugin.firstBlock = block
+  end
+  plugin.currentBlock = block
+
+
+
+  block:SetHeight(block.contentHeight)
+  print('block|cFF88FF00', self.numBlocks, block, '|rto', anchor, 'size', block.contentHeight)
+  block:ClearAllPoints()
+  block:SetPoint('TOPLEFT', anchor, 'BOTTOMLEFT', 0, -blockSpacing)
+  block:Show()
+
+  -- free unused lines
+  local numLines = #block.lines
+  for i = 1, numLines do
+    local line = block.lines[i]
+    if not line.used or block.collapsed then
+      print('|cFFFF4400!|r')
+      self:FreeLine(line)
+    else
+      if not line:IsShown() then
+        line:Show()
+      end
+    end
+  end
+
+  return true
+end
+
+function tracker:SetLine(block, index, lineType, textOrFunc)
+  local anchor = block.currentLine or block.header
+  local line = self:GetLine(block, index, lineType)
+
+  if line.ticker then
+    line.ticker:Cancel()
+    line.ticker = nil
+  end
+
+  local text = textOrFunc
+  if type(textOrFunc) == 'function' then
+    text = textOrFunc()
+
+    line.ticker = C_Timer.NewTicker(10, function()
+      line.height = tracker:SetLineText(line.text, textOrTextFunc())
+      line:SetHeight(line.height)
+    end)
+  end
+  line.height = tracker:SetLineText(line.text, text)
+  line:SetHeight(line.height)
+
+  print('line|cFFFFFF00', line:GetName(), '|rto', anchor:GetName(), 'size', line.height)
+  line:SetPoint('TOPLEFT', anchor, 'BOTTOMLEFT', 0, 0)
+
+  block.contentHeight = block.contentHeight + line.height
+  block.numLines = block.numLines + 1
+
+  if block.currentLine then
+    line.prevLine = block.currentLine
+    block.currentLine.nextLine = line
+  else
+    block.firstLine = line
+  end
+
+  block.currentLine = line
+  plugin.currentLine = line
+
+end
+
+function tracker:SetLineText(fontString, text)
+  fontString:SetText(text)
+  return fontString:GetStringHeight()
+end
+
+-- Update lite
+function tracker:ResetAnchors ()
+  self:InitLayout()
+
+  self:EndLayout()
+end
+
+
+local UpdateQuestTracker = function(watchIndex, logIndex)
+  return true
+end
+
+-- top-down updaters
+
+local questTracker = GetTrackerHandler({
+  headerText = 'Quests',
+  updateReasonModule = X_MODULE_QUEST,
+  updateReasonEvents = (X_QUEST + X_QUEST_ADDED),
+})
+function questTracker:Update ()
+  self:InitLayout()
+  for watchIndex = 1, GetNumQuestWatches() do
+    local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete, startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isBounty, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
+    if not questID then
+      -- stop parsing; end of data or variables haven't completely loaded
+      break
+    end
+    local showQuest = true
+    if isTask or (isBounty and not IsQuestComplete(questID)) then
+      -- do nothing
+    else
+      -- obtain a block
+      local block = self:GetBlock(questID)
+
+      block.header:SetText(title)
+
+      for i = 1, numObjectives do
+        local text, objectiveType, finished = GetQuestLogLeaderBoard(i, questLogIndex)
+        if text then
+          self:SetLine(block, i, nil, text)
+        end
+      end
+
+      block:SetScript('OnClick', self.OnClick)
+      block:RegisterForClicks('AnyDown')
+
+      self:AddBlock(block)
+    end
+  end
+
+  self:EndLayout()
+end
+questTracker.OnClick = function(block, button)
+  if button == 'RightButton' then
+    ObjectiveTracker_ToggleDropDown(block, QuestObjectiveTracker_OnOpenDropDown)
+  else
+    CloseDropDownMenus()
+
+    local questLogIndex = GetQuestLogIndexByID(block.id)
+    if ( IsModifiedClick("QUESTWATCHTOGGLE") ) then
+      QuestObjectiveTracker_UntrackQuest(nil, block.id);
+    else
+      if ( IsQuestComplete(block.id) and GetQuestLogIsAutoComplete(questLogIndex) ) then
+        AutoQuestPopupTracker_RemovePopUp(block.id);
+        ShowQuestComplete(questLogIndex);
+      else
+        QuestLogPopupDetailFrame_Show(questLogIndex);
+      end
+    end
+  end
+end
+
+local UpdateAchievementTracker = function() end
+local UpdateTaskTracker = function() end
+local UpdateScenarioTracker = function() end
+
+function plugin:Update(reason, id)
+
+  print('update', reason, #plugin.trackers)
+
+  if plugin.minimized then
+    for i, tracker in ipairs(plugin.trackers) do
+      tracker:Hide()
+    end
+    return
+  end
+
+
+  local X_REASON = reason or X_ALL
+  local X_ID = id
+
+  plugin.maxHeight = plugin:GetHeight()
+  plugin.oldContentsHeight = plugin.contentHeight
+  plugin.contentHeight = 0
+  plugin.currentBlock = nil
+  plugin.firstBlock = nil
+  plugin:SetWidth(trackerWidth)
+
+  -- pad for header
+  plugin.contentHeight = plugin.header:GetHeight()
+
+  for i, header in ipairs(plugin.trackers) do
+    header.used = nil
+  end
+
+
+  local addedSpace = false
+  for i, tracker in ipairs(plugin.trackers) do
+    if ( band(X_REASON, tracker.updateReasonModule + tracker.updateReasonEvents ) > 0 ) then
+      print('->', tracker.headerText)
+      tracker:Update()
+      if tracker.oldContentHeight - tracker.contentHeight >= 1 then
+        addedSpace = true
+      end
+    else
+      -- if we can fit another header or an animation handler popped, contents need to be generated
+      if addedSpace or (tracker.header and tracker.header.animating) then
+        print('->', tracker.headerText, 'added space')
+        tracker:Update()
+      else
+        print('->', tracker.headerText, 'lite update')
+        -- otherwise, measure contents and hide anything that won't fit
+        tracker:ResetAnchors()
+      end
+    end
+  end
+
+  for i, tracker in ipairs(plugin.trackers) do
+    if tracker.currentBlock then
+      if not tracker.header:IsShown() then
+        tracker.header:Show()
+      end
+    else
+      if tracker.header:IsShown() then
+        tracker.header:Hide()
+      end
+    end
+  end
+
+  if VeneerBuffFrame and VeneerBuffFrame.lastBuff then
+    plugin:ClearAllPoints()
+    plugin:SetPoint('TOP', VeneerBuffFrame.lastBuff, 'BOTTOM', 0, -4)
+    plugin:SetPoint('RIGHT', UIParent, 'RIGHT', -6, 0)
+  else
+    plugin:ClearAllPoints()
+    plugin:SetPoint('TOPRIGHT', UIParent, 'TOPRIGHT', -6, -120)
+  end
+
+  plugin:Show()
+end
+
+plugin.init = function()
+
+  plugin:RegisterEvent("QUEST_LOG_UPDATE")
+  plugin:RegisterEvent("TRACKED_ACHIEVEMENT_LIST_CHANGED")
+  plugin:RegisterEvent("QUEST_WATCH_LIST_CHANGED")
+  plugin:RegisterEvent("QUEST_AUTOCOMPLETE")
+  plugin:RegisterEvent("QUEST_ACCEPTED")
+  plugin:RegisterEvent("SUPER_TRACKED_QUEST_CHANGED")
+  plugin:RegisterEvent("SCENARIO_UPDATE")
+  plugin:RegisterEvent("SCENARIO_CRITERIA_UPDATE")
+  plugin:RegisterEvent("SCENARIO_SPELL_UPDATE")
+  plugin:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE")
+  plugin:RegisterEvent("ZONE_CHANGED_NEW_AREA");
+  plugin:RegisterEvent("ZONE_CHANGED");
+  plugin:RegisterEvent("QUEST_POI_UPDATE");
+  plugin:RegisterEvent("VARIABLES_LOADED");
+  plugin:RegisterEvent("QUEST_TURNED_IN");
+  plugin:RegisterEvent("PLAYER_MONEY");
+
+  plugin.trackers = {
+    questTracker,
+  }
+  print('bub')
+end
+function plugin:event(event, ...)
+  print('|cFFFF0088' .. event, ...)
+  if event == 'QUEST_WATCH_LIST_CHANGED' then
+    local questID, added = ...
+    if added then
+      if not IsQuestBounty(questID) or IsQuestComplete(questId) then
+        print(questID, added)
+        plugin:Update(X_QUEST_ADDED, questID)
+      end
+    else
+      print()
+      plugin:Update(X_QUEST)
+    end
+  elseif event == 'QUEST_LOG_UPDATE' then
+    plugin:Update(X_MODULE_QUEST)
+  elseif event == 'QUEST_POI_UPDATE' then
+    
+    if GetCVar("trackQuestSorting") == "proximity" then
+      -- todo: sort blocks
+    end
+    plugin:Update(X_MODULE_QUEST)
+    elseif event == 'PLAYER_MONEY' then
+    plugin:Update(X_MONEY)
+  end
+
+end
+
+-- adjusts money events bitcode when a tracker is displaying money data
+function plugin:UpdateMoneyFlag(watchMoney, reason)
+  if watchMoney then
+    if (band(X_MONEY, reason) == 0) then
+      X_MONEY = X_MONEY - reason
+    end
+  else
+    if (band(X_MONEY, reason) > 0) then
+      X_MONEY = X_MONEY + reason
+    end
+  end
+end
+
+-- used by framescripts to poke the updater when an animation has ended
+function plugin:UpdateAnimation(block)
+
+  local reason = block.handler.updateReasonEvents
+  if block.animating then
+    if (band(X_ANIMATION, reason) == 0) then
+      X_ANIMATION = X_ANIMATION - reason
+    end
+  else
+    if (band(X_ANIMATION, reason) > 0) then
+      X_ANIMATION = X_ANIMATION + reason
+    end
+  end
+end
\ No newline at end of file