view ObjectiveUI.lua @ 7:5301c68f28d8

TrackerBlock - use IsModifiedClick function to determine appropriate OnClick actions - handle 'CHATLINK' modifier - handle 'TOGGLEQUESTWATCH' modifier TrackerBlockObjectives - use a generic framework to manage frame creation for various criteria tracker types: - ProgressBar when Blizzard flag data indicates so - skip when Blizzard flag data indicates so - DynamicText otherwise - events related to the criteria are registered in the criteria frame, and unregistered when the frame is hidden, either by destruction of its parent or completion
author Nenue
date Fri, 01 Apr 2016 12:27:05 -0400
parents 589de8ea05b9
children 7923243ae972
line wrap: on
line source
--- ${PACKAGE_NAME}
-- @file-author@
-- @project-revision@ @project-hash@
-- @file-revision@ @file-hash@
-- Created: 3/29/2016 7:07 PM
local B = select(2,...).frame
local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
local print = B.print('Objectives')
local Tracker, AutoQuest, Quest, Cheevs = mod.Tracker, mod.AutoQuest, mod.Quest, mod.Cheevs
local itemButtonSize, itemButtonSpacing =  36, 1
local tremove, tremovebyval = table.remove, table.removebyval

--------------------------------------------------------------------
--- Tracker-specific widgets and their handlers
--------------------------------------------------------------------

Tracker.Select = function(self) end
Tracker.Open = function(self) end
Tracker.Remove = function(self) end
Tracker.Report = function(self)
  print('Stats:', self.numWatched,'items tracked,', self.numBlocks,'blocks assigned.')
end

Tracker.OnMouseUp = function(self, button)
  if self.initialButton == 'LeftButton' then
    if self.modChatLink and ChatEdit_GetActiveWindow() then
      self:Link()
    elseif self.modQuestWatch then
      self:Remove()
    else
      self:Select()
    end
  elseif button == 'RightButton' then
    self:Open()
  end
  self.initialButton = nil
  self.modChatLink = nil
  self.modQuestWatch = nil
  print('|cFFFF8800'..tostring(self:GetName())..':MouseUp()|r ->',self.info.trackingID)
end

Tracker.OnMouseDown = function(self, button)
  self.initialButton = button
  self.modChatLink = IsModifiedClick("CHATLINK")
  self.modQuestWatch = IsModifiedClick("QUESTWATCHTOGGLE")
  self:SetStyle('Active')
  print(self.info.title)
end

-----------------------------
--- AUTO_QUEST
AutoQuest.name = "Remote Quests"
AutoQuest.GetNumWatched = GetNumAutoQuestPopUps

-----------------------------
--- QUEST
Quest.name = "Quests"
Quest.Select = function(self)
  SetSuperTrackedQuestID(self.info.questID)
  mod.UpdateWrapper()
end
Quest.Link = function(self)
  local questLink = GetQuestLink(block.questLogIndex);
  if ( questLink ) then
    ChatEdit_InsertLink(questLink);
  end
end
Quest.Open = function(self)
  QuestMapFrame_OpenToQuestDetails(self.info.questID)
end

Quest.Remove = function(self)
  print('removing', self.info.questLogIndex, 'from watcher')
  RemoveQuestWatch(self.info.questLogIndex)

  mod.Quest.LogBlock[self.info.questLogIndex] = nil
  mod.Quest.QuestBlock[self.info.questID] = nil
  QuestPOIUpdateIcons()
  mod.UpdateWrapper()
end


-----------------------------
--- CHEEVS
Cheevs.Select = function(self)
end
Cheevs.Link = function(self)
    local achievementLink = GetAchievementLink(self.info.cheevID);
    if ( achievementLink ) then
      ChatEdit_InsertLink(achievementLink);
    end
  self:SetStyle('CheevNormal')
end

Cheevs.Open = function(self)
  if ( not AchievementFrame ) then
    AchievementFrame_LoadUI();
  end
  if ( not AchievementFrame:IsShown() ) then
    AchievementFrame_ToggleAchievementFrame();
  end
  AchievementFrame_SelectAchievement(self.info.cheevID);
end

----------------------------------------------------------------------------------------
--- frame template and scripts lifted from "QuestKing 2" by Barjack
--- url: 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
  --- .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(itemButtonSize, itemButtonSize)
      itemButton:GetNormalTexture():SetSize(itemButtonSize * (5/3), itemButtonSize * (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.UpdateWrapper()
        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(obj, info)
  local widgetType = obj.type
  local widget

  if not wr[widgetType] or #wr[widgetType].free == 0 then
    print('VeneerObjectiveCriteria' .. widgetType)
    widget = CreateFrame('Frame', nil, VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType)
  end
  local free = wr[widgetType].free
  local used = wr[widgetType].used

  widget = tremove(free)
  local index = #used+1
  used[index] = widget
  wr[widgetType].usedIndex[widget] = index
  widget.info = obj
  widget.parentInfo = info
  mod.InitializeWidget(widget)

  return widget
end

--- Fired by OnLoad() when a new frame is spawned
mod.RegisterWidget = function(frame)
  local widgetType = frame.widgetType
  local obj = frame.info
  if not wr[frame.widgetType] then
    print('|cFFFF4400[[WidgetTemplate]]|r', widgetType)
    wr[widgetType] = { lastn = 0, free = {}, used = {}, usedIndex = {}, freeIndex = {} }
  end
  tinsert(wr[frame.widgetType].free, frame)
end
mod.InitializeWidget = setmetatable({}, {
  __call = function(t, frame)
    -- todo: config pull
    local maxWidth = 250

    frame:SetWidth(maxWidth)
    mod.UpdateWidget[frame.widgetType](frame)
    frame:SetScript('OnEvent', mod.UpdateWidget[frame.widgetType])
    if frame.info.isCurrency then
      frame:RegisterEvent('CHAT_MSG_CURRENCY')
      frame:RegisterEvent('CURRENCY_LIST_UPDATE')
    end
    frame:RegisterEvent('TRACKED_ACHIEVEMENT_UPDATE')
    frame:RegisterEvent('TRACKED_ACHIEVEMENT_LIST_CHANGED')
    frame:RegisterEvent('CRITERIA_UPDATE')
    frame:RegisterEvent('CRITERIA_COMPLETE')
    frame:RegisterEvent('CRITERIA_EARNED')

    return t[frame.widgetType](frame)
  end,
})
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
})

mod.ReleaseWidget = function(frame)
  local reg = wr[frame.widgetType]
  if reg and reg.usedIndex[frame] then
    tremove(reg.used, reg.usedIndex[frame])
    reg.usedIndex[frame] = nil
    frame:UnregisterAllEvents()
    tinsert(reg.free, frame)
  end
end

mod.WidgetParams = {
  ['ProgressBar'] = {
    height = 20,
    caption = {},
    quantityString = {SetFontObject = _G.VeneerFontNormal}
  }
}

mod.InitializeWidget.ProgressBar = function(self)
  local params = mod.WidgetParams[self.widgetType]
  self.height = params.height
  self:SetHeight(20)
  self.bg:SetHeight(20)
  self.fg:SetHeight(18)
  self.fg:SetPoint('BOTTOMLEFT', self.bg, 'BOTTOMLEFT', 1, 1)
  self.quantityString:SetFontObject(params.quantityString.SetFontObject)
  self.quantityString:SetText(self.info.quantityString)
end

mod.UpdateWidget.ProgressBar = function (self)
  local quantity, requiredQuantity = self.info.quantity, self.info.requiredQuantity
  self.fg:SetPoint('TOPLEFT', self, 'TOPLEFT', 0, 0)
  if self.info.finished then
    self.fg:SetWidth(self.bg:GetWidth() - 2)
  elseif quantity == 0 then
    self.fg:Hide()
  else
    self.fg:Show()
    self.fg:SetWidth(self:GetWidth() * (quantity / requiredQuantity))
  end

end