diff ObjectiveTracker/ObjectiveWidgets.lua @ 23:e837384ac363

Separating objective tracker module
author Nenue
date Sun, 10 Apr 2016 04:35:32 -0400
parents ObjectiveWidgets.lua@9b3fa734abff
children 66b927b46776
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveTracker/ObjectiveWidgets.lua	Sun Apr 10 04:35:32 2016 -0400
@@ -0,0 +1,439 @@
+local B = select(2,...).frame
+local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
+local print = B.print('WidgetFactory')
+local UIParent = UIParent
+local GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown
+local CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll = CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll
+local tremove, tinsert, tContains, pairs, setmetatable = tremove, tinsert, tContains, pairs, setmetatable
+
+--- frame refs
+local Wrapper = _G.VeneerObjectiveWrapper
+local Scroller = Wrapper.scrollArea
+local CloseButton = Wrapper.CloseButton
+local QuestMapButton = Wrapper.QuestMapButton
+local Scroll = _G.VeneerObjectiveScroll
+
+local panelButtons = {
+  CloseButton = {
+    closedSwatch = {
+      [[Interface\Buttons\UI-Panel-QuestHideButton]],
+      [[Interface\Buttons\UI-Panel-QuestHideButton]],
+      0, 0.5, 0.5, 1,
+      0.5, 1, 0.5, 1,
+    },
+    openSwatch = {
+      [[Interface\Buttons\UI-Panel-QuestHideButton]],
+      [[Interface\Buttons\UI-Panel-QuestHideButton]],
+      0.5, 1, 0.5, 1,
+      0, 0.5, 0.5, 1,
+    },
+    parent = 'VeneerObjectiveWrapper'
+  },
+  QuestMapButton = {
+    closedSwatch = {
+      [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]],
+      [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]],
+      0, 1, 0.5, 1,
+      0, 1, 0, 0.5,
+    },
+    openSwatch = {
+      [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]],
+      [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]],
+      0, 1, 0, 0.5,
+      0, 1, 0.5, 1,
+    }
+  }
+}
+
+local Scroller_OnShow = function()
+  Wrapper.watchMoneyReasons = 0;
+  --mod:Update()
+  --mod:OnInitialize()
+  for i, region in ipairs(Wrapper.headerComplex) do
+    region:Show()
+  end
+end
+
+local Scroller_OnHide = function()
+  local self = Wrapper
+  Wrapper:UnregisterAllEvents()
+  Wrapper:SetScript('OnEvent', nil)
+  for i, region in ipairs(Wrapper.headerComplex) do
+    region:Hide()
+  end
+end
+
+local Scroller_OnMouseWheel = function(self, delta)
+  local r = Scroll:GetHeight() - Scroller:GetHeight()
+  local s = B.Conf.ObjectiveScroll - delta * floor(r/5+.5)
+  local from = self:GetVerticalScroll()
+  print('|cFF00FF00OnMouseWheel', 'scroll =', s)
+  if s >= r then
+    s = r
+  elseif s < 1 then
+    s = 0
+  end
+  self:SetVerticalScroll(s)
+  B.Conf.ObjectiveScroll = s
+  print('|cFF00FF00OnMouseWheel', 'from = ', from, 'scroll =', s, ' range =', r, 'current =', self:GetVerticalScroll())
+
+  mod.UpdateActionButtons('SCROLLING')
+end
+
+local UpdatePanelButton = function (self, state)
+  state = state and B.Conf.FrameState[state] or 1
+  local swatch = (state == 1) and self.openSwatch or self.closedSwatch
+  self:SetNormalTexture(swatch[1])
+  self:SetPushedTexture(swatch[2])
+  if #swatch >= 6 then
+    self:GetNormalTexture():SetTexCoord(swatch[3], swatch[4], swatch[5], swatch[6])
+  end
+  if #swatch == 10 then
+    self:GetPushedTexture():SetTexCoord(swatch[7], swatch[8], swatch[9], swatch[10])
+  end
+
+end
+
+local OnClick = {}
+OnClick.CloseButton = function(self)
+  Wrapper:Minimize()
+  UpdatePanelButton(self, self.parent)
+end
+
+OnClick.QuestMapButton = function()
+  ToggleWorldMap()
+end
+
+
+mod.InitializeWidgets = function()
+  --- tracker scroll
+  Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel)
+  Scroller:SetScript('OnShow', Scroller_OnShow)
+  Scroller:SetScript('OnHide', Scroller_OnHide)
+  for name, swatch in pairs(panelButtons) do
+    local source = swatch and swatch or panelButtons.CloseButton
+    local button = Wrapper[name]
+    button.parent = swatch.parent
+    button.openSwatch = source.openSwatch
+    button.closedSwatch = source.closedSwatch
+    if OnClick[name] then
+      button:SetScript('OnClick', OnClick[name])
+    end
+    UpdatePanelButton(button, button.parent)
+  end
+end
+
+----------------------------------------------------------------------------------------
+--- XML and script code lifted from "QuestKing 2" by Barjack,
+---   found at http://mods.curse.com/addons/wow/questking
+----------------------------------------------------------------------------------------
+local usedButtons = mod.Quest.itemButtons
+local freeButtons = mod.Quest.freeButtons
+mod.SetItemButton = function(block, info)
+  local itemInfo = info.specialItem
+  if not itemInfo then
+    return
+  end
+
+  --- Quest.GetInfo().specialItem :: {link = link, charges = charges, icon = icon, start = start, duration = duration, enable = enable}
+
+
+  local itemButton
+  if not info.itemButton then
+    if #freeButtons >= 1 then
+      print('    |cFF00FFFFfound a free button')
+      itemButton = freeButtons[#freeButtons]
+      freeButtons[#freeButtons] = nil
+      if itemButton.block then
+        itemButton.block.itemButton = nil
+        itemButton.block = nil
+      end
+    else
+      local buttonIndex = mod.Quest.numButtons + #freeButtons + 1
+      itemButton = CreateFrame('Button', 'VeneerQuestItemButton' .. buttonIndex, UIParent, 'VeneerItemButtonTemplate')
+      itemButton.buttonIndex = buttonIndex
+      itemButton:SetSize(36, 36)
+      itemButton:GetNormalTexture():SetSize(36 * (5/3), 36 * (5/3))
+      print('    |cFFFF4400starting new button', itemButton:GetName())
+    end
+    mod.Quest.numButtons = mod.Quest.numButtons + 1
+  else
+    itemButton = info.itemButton
+    print('    |cFF00FF00found assigned button', itemButton:GetName())
+
+  end
+  -- set values
+
+  info.itemButton = itemButton
+  usedButtons[info.questID] = itemButton
+  print('      |cFF8800FFassigning|r', itemButton:GetName(), 'to quest|cFF00FF00', info.questID, '|rat|cFFFFFF00', block:GetName(),'|r')
+
+  for k,v in pairs(usedButtons) do
+    print('|cFFFF44DD'..k..'|r', v:GetName())
+  end
+
+  itemButton:SetAttribute("type", "item")
+  itemButton:SetAttribute("item", itemInfo.link)
+
+  itemButton.questID = info.questID
+  itemButton.questLogIndex = info.questLogIndex
+  itemButton.charges = itemInfo.charges
+  itemButton.rangeTimer = -1
+  itemButton.block = block
+
+  SetItemButtonTexture(itemButton, itemInfo.icon)
+  SetItemButtonCount(itemButton, itemInfo.charges)
+  Veneer_QuestObjectiveItem_UpdateCooldown(itemButton);
+
+  return itemButton
+end
+--- Clear an itemButton from the given block
+mod.FreeItemButtons = function(block)
+
+  if block.itemButton then
+    local itemButton = block.itemButton
+    if itemButton.questID ~= block.info.questID then
+      block.itemButton = nil
+      itemButton.block = mod.Quest.InfoBlock[itemButton.questID]
+    else
+      itemButton.block = nil
+      itemButton:Hide()
+
+      usedButtons[itemButton.questID] = nil
+      freeButtons[#freeButtons + 1] = itemButton
+      mod.Quest.numButtons = mod.Quest.numButtons - 1
+      print('|cFFFF0088released', itemButton:GetName(),'and', block:GetName())
+    end
+  end
+end
+
+function Veneer_QuestObjectiveItem_OnUpdate (self, elapsed)
+  -- Handle range indicator
+  local rangeTimer = self.rangeTimer
+  if (rangeTimer) then
+    rangeTimer = rangeTimer - elapsed
+    if (rangeTimer <= 0) then
+      local link, item, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(self.questLogIndex)
+      if ((not charges) or (charges ~= self.charges)) then
+        mod:Update()
+        return
+      end
+
+      local count = self.HotKey
+      local valid = IsQuestLogSpecialItemInRange(self.questLogIndex)
+      if (valid == 0) then
+        count:Show()
+        count:SetVertexColor(1.0, 0.1, 0.1)
+      elseif (valid == 1) then
+        count:Show()
+        count:SetVertexColor(0.6, 0.6, 0.6)
+      else
+        count:Hide()
+      end
+      rangeTimer = TOOLTIP_UPDATE_TIME
+    end
+
+    self.rangeTimer = rangeTimer
+  end
+end
+
+function Veneer_QuestObjectiveItem_UpdateCooldown (itemButton)
+  local start, duration, enable = GetQuestLogSpecialItemCooldown(itemButton.questLogIndex)
+  if (start) then
+    CooldownFrame_SetTimer(itemButton.Cooldown, start, duration, enable)
+    if (duration > 0 and enable == 0) then
+      SetItemButtonTextureVertexColor(itemButton, 0.4, 0.4, 0.4)
+    else
+      SetItemButtonTextureVertexColor(itemButton, 1, 1, 1)
+    end
+  end
+end
+
+-----------------------------------------
+-- Criteria frames
+
+--[[
+      text = description,
+      type = type,
+      finished = completed,
+      quantity = quantity,
+      requiredQuantity = requiredQuantity,
+      characterName = characterName,
+      flags = flags,
+      assetID = assetID,
+      quantityString = quantityString,
+      criteriaID = criteriaID,
+]]
+local newWidgetID = 0
+mod.WidgetRegistry = {}
+local wr = mod.WidgetRegistry
+
+--- Get a usable widget for the given achievement criteria set.
+-- Returns a frame object with dimensioning parameters needed to size the receiving tracker block
+mod.SetWidget = function(line, data, objectiveType, objectiveKey)
+  local print = B.print('ObjectiveWidgets')
+  local widgetType = objectiveType
+  local widget
+  if wr[widgetType] and wr[widgetType].used[objectiveKey] then
+    widget = wr[widgetType].used[objectiveKey]
+    print('|cFF00FF00Updating ('..objectiveKey..')', widget)
+  elseif not wr[widgetType] or #wr[widgetType].free == 0 then
+    widget = CreateFrame('Frame', 'VeneerObjective' .. widgetType .. (wr[widgetType] and (wr[widgetType].lastn+1) or (1)), VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType)
+
+    print('|cFFFF0088Creating `'..widget:GetName()..'` id', wr[widgetType].lastn)
+  else
+    widget = tremove(wr[widgetType].free)
+    print('|cFFFFFF00Acquiring released widget', widget:GetName())
+  end
+
+
+  wr[widgetType].used[objectiveKey] = widget
+  widget.line = line
+  widget.objective = data
+  widget.key = objectiveKey
+  mod.InitializeWidget(widget)
+  return widget
+end
+
+--- WidgetTemplate 'OnLoad'
+mod.RegisterWidget = function(frame)
+  local print = B.print('ObjectiveWidgets')
+  local widgetType = frame.widgetType
+  if not wr[frame.widgetType] then
+    print('|cFFFF4400[[WidgetTemplate]]|r', widgetType)
+    wr[widgetType] = { lastn = 1, free = {}, used = {}, usedIndex = {}, freeIndex = {} }
+  else
+    print('|cFF0088FF+ [[WidgetTemplate]]r', widgetType, wr[widgetType].lastn)
+    wr[widgetType].lastn = wr[widgetType].lastn + 1
+  end
+end
+
+--- WidgetTemplate 'OnShow'
+mod.InitializeWidget = setmetatable({}, {
+  __call = function(t, frame)
+    -- todo: config pull
+
+    frame:SetWidth(mod.Conf.Wrapper.Width - mod.Conf.Style.Format.status.Indent * 2)
+    frame:SetScript('OnEvent', mod.UpdateWidget[frame.widgetType])
+    frame:RegisterEvent('TRACKED_ACHIEVEMENT_UPDATE')
+    frame:RegisterEvent('TRACKED_ACHIEVEMENT_LIST_CHANGED')
+    frame:RegisterEvent('CRITERIA_UPDATE')
+    frame:RegisterEvent('CRITERIA_COMPLETE')
+    frame:RegisterEvent('CRITERIA_EARNED')
+    t[frame.widgetType](frame)
+    mod.UpdateWidget[frame.widgetType](frame)
+  end,
+})
+
+--- WidgetTemplate 'OnEvent'
+mod.UpdateWidget = setmetatable({}, {
+  __call = function(t, frame)
+    if not frame.widgetType then
+      error('Invalid widget template, needs .widgetType')
+      return
+    end
+
+    return t[frame.widgetType](frame)
+  end
+})
+
+--- WidgetTemplate 'OnHide'
+mod.ReleaseWidget = function(frame)
+  --[[
+  local print = B.print('ObjectiveWidgets')
+  local reg = wr[frame.widgetType]
+  if reg and reg.used[frame.key] then
+    reg.used[frame.key] = nil
+    frame.line = nil
+    frame.info = nil
+    frame:UnregisterAllEvents()
+    tinsert(reg.free, frame)
+    print('|cFFBBBBBBreleased from service', frame:GetName())
+  end
+  ]]
+end
+
+--- RemoveTrackedAchievement post-hook
+mod.CleanWidgets = function()
+  local print = B.print('ObjectiveWidgets')
+  local tracked = {GetTrackedAchievements() }
+  local tasks = GetTasksTable()
+  for type, reg in pairs(mod.WidgetRegistry) do
+    print('collecting', type)
+    for key, frame in pairs(reg.used) do
+      if frame.objective.cheevID then
+        local id = frame.objective.cheevID
+
+        if id and not tContains(tracked, id) then
+
+          print('  untracked achievement', id, 'associated with', key, frame:GetName())
+          frame:Hide()
+        end
+      elseif frame.objective.questID then
+        -- do something for quest task
+      end
+    end
+  end
+end
+
+
+
+mod.defaults.WidgetStyle = {
+
+}
+
+local progressHeight = 16
+local progressBorder = 1
+local progressIndent = 3
+local progressFont = _G.VeneerCriteriaFontNormal
+
+
+mod.InitializeWidget.ProgressBar = function(self)
+  local c = mod.Conf.Wrapper
+  self.height = progressHeight + c.TextSpacing
+  self.width = c.Width - c.TextSpacing
+  self.indent = progressIndent
+
+  self:SetHeight(progressHeight)
+  self.bg:SetHeight(progressHeight)
+  self.bg:SetWidth(self.width)
+  self.fg:ClearAllPoints()
+  self.fg:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', progressBorder, progressBorder)
+  self.fg:SetHeight(progressHeight - progressBorder *  2)
+  self.status:SetFontObject(progressFont)
+  self.status:SetText(self.objective.quantityString)
+end
+
+mod.UpdateWidget.ProgressBar = function (self)
+  local quantity, requiredQuantity = self.objective.value, self.objective.maxValue
+  print('update vals:')
+  for k,v in pairs(self.line) do
+    print(k, v)
+  end
+
+  if self.line.format then
+    self.status:SetFormattedText(self.line.format, quantity, requiredQuantity)
+  end
+
+  local progress = (quantity / requiredQuantity)
+  if progress >= 1 then
+    self.fg:Show()
+    self.fg:SetWidth(self.width  - progressBorder * 2)
+  elseif progress > 0 then
+    self.fg:Show()
+    print('color:', 1-progress*2 , progress*2 - 1,0,1)
+    print('width:', (self.width  -progressBorder * 2) * progress)
+    self.fg:SetTexture(1-progress*2 , progress*2,0,1)
+    self.fg:SetWidth((self.width  -progressBorder * 2) * progress)
+  else
+    self.fg:Hide()
+  end
+end
+
+
+mod.InitializeWidget.Hidden = function (self)
+  self.height = 0
+end
+mod.UpdateWidget.Hidden = function (self)
+  self.height=  0
+end
\ No newline at end of file