view ObjectiveTracker/ObjectiveWidgets.lua @ 35:69d03f8e293e

- separated layout and data logic between Frame.lua and Update.lua - solved disappearing tracker mystery
author Nenue
date Sun, 17 Apr 2016 11:07:48 -0400
parents 66b927b46776
children
line wrap: on
line source
local B = select(2,...).frame
local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
local print = B.print('WidgetFactory')
local _G, UIParent = _G, UIParent
local GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown
local CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll = CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll
local tremove, tContains, pairs, ipairs, setmetatable, floor = tremove, tContains, pairs, ipairs, setmetatable, floor
local SetItemButtonTexture, SetItemButtonCount = SetItemButtonTexture, SetItemButtonCount
local ToggleWorldMap, GetTrackedAchievements, GetTasksTable = ToggleWorldMap, GetTrackedAchievements, GetTasksTable
-- GLOBALS: Veneer_QuestObjectiveItem_UpdateCooldown, Veneer_QuestObjectiveItem_OnUpdate
--- frame refs
local Wrapper = _G.VeneerObjectiveWrapper
local Scroller = Wrapper.scrollArea
local CloseButton = Wrapper.CloseButton
local QuestMapButton = Wrapper.QuestMapButton
local Scroll = _G.VeneerObjectiveScroll
local usedButtons = T.Quest.itemButtons
local freeButtons = T.Quest.freeButtons

T.buttons = {
  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;
  --T:Update()
  --T: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())

  T.UpdateActionButtons('SCROLLING')
end

local UpdatePanelButton = function (self, state)
  state = state or true
  local swatch = (state == true) and self.openSwatch or self.closedSwatch
  print((state ~= true) and 'closedSwatch' or 'openSwatch')
  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)
  T:SetEnabled()
  UpdatePanelButton(self, T.Conf.enabled)
end

OnClick.QuestMapButton = function()
  ToggleWorldMap()
end


T.InitializeWidgets = function()
  local panelButtons = T.buttons
  --- 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, T.Conf.enabled)
  end
end

----------------------------------------------------------------------------------------
--- modified version of the itemButton initializer used by Barjack's 'QuestKing 2' addon,
--- url: http://mods.curse.com/addons/wow/questking
----------------------------------------------------------------------------------------
T.SetItemButton = function(block, info)
  local itemInfo = info.specialItem
  if not itemInfo then
    return
  end

  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 = T.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
    T.Quest.numButtons = T.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
T.FreeItemButtons = function(block)

  if block.itemButton then
    local itemButton = block.itemButton
    if itemButton.questID ~= block.info.questID then
      block.itemButton = nil
      itemButton.block = T.Quest.InfoBlock[itemButton.questID]
    else
      itemButton.block = nil
      itemButton:Hide()

      usedButtons[itemButton.questID] = nil
      freeButtons[#freeButtons + 1] = itemButton
      T.Quest.numButtons = T.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
        T: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
T.WidgetRegistry = {}
local wr = T.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
T.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
  T.InitializeWidget(widget)
  return widget
end

--- WidgetTemplate 'OnLoad'
T.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'
T.InitializeWidget = setmetatable({}, {
  __call = function(t, frame)
    -- todo: config pull

    frame:SetWidth(T.Conf.Wrapper.Width - T.Conf.Style.Format.status.Indent * 2)
    frame:SetScript('OnEvent', T.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)
    T.UpdateWidget[frame.widgetType](frame)
  end,
})

--- WidgetTemplate 'OnEvent'
T.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'
T.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
T.CleanWidgets = function()
  local print = B.print('ObjectiveWidgets')
  local tracked = {GetTrackedAchievements() }
  local tasks = GetTasksTable()
  for type, reg in pairs(T.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



T.defaults.WidgetStyle = {

}

local progressHeight = 16
local progressBorder = 1
local progressIndent = 3
local progressFont = _G.VeneerCriteriaFontNormal


T.InitializeWidget.ProgressBar = function(self)
  local c = T.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

T.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


T.InitializeWidget.Hidden = function (self)
  self.height = 0
end
T.UpdateWidget.Hidden = function (self)
  self.height=  0
end