annotate ObjectiveWidgets.lua @ 13:9455693fc290

Init - recall XML display state on reload ObjectiveFrame - quest coloring by relative level - quest coloring by daily/weekly/complete status - remember starting scroll value between reload - limit anchor points to edges for regions affected by style attributes ObjectiveInfo - AutoQuest outline definitions - Pull Quest title and tag data in addition to WatchInfo ObjectiveStyle - ensure consistent style table - hardcode certain attributes for sanity XML - ensure consistent naming conventions for heading and content elements - ensure hardcore anchors are based on edges - expansion of file structure to deal with complexities of dynamic widgets and style caching ObjectiveUI - determine primary style by block handler when restoring original style - moved framescript to 'ObjectiveWidgets' lua
author Nenue
date Sat, 02 Apr 2016 17:46:52 -0400
parents
children ed642234f017
rev   line source
Nenue@13 1 local B = select(2,...).frame
Nenue@13 2 local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
Nenue@13 3 local print = B.print('WidgetFactory')
Nenue@13 4 local UIParent = UIParent
Nenue@13 5 local GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown
Nenue@13 6 local CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll = CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll
Nenue@13 7 local tremove, tinsert, tContains, pairs, setmetatable = tremove, tinsert, tContains, pairs, setmetatable
Nenue@13 8 ----------------------------------------------------------------------------------------
Nenue@13 9 --- XML and script code lifted from "QuestKing 2" by Barjack,
Nenue@13 10 --- found at http://mods.curse.com/addons/wow/questking
Nenue@13 11 ----------------------------------------------------------------------------------------
Nenue@13 12 local usedButtons = mod.Quest.itemButtons
Nenue@13 13 local freeButtons = mod.Quest.freeButtons
Nenue@13 14 mod.SetItemButton = function(block, info)
Nenue@13 15 local itemInfo = info.specialItem
Nenue@13 16 if not itemInfo then
Nenue@13 17 return
Nenue@13 18 end
Nenue@13 19
Nenue@13 20 --- Quest.GetInfo().specialItem :: {link = link, charges = charges, icon = icon, start = start, duration = duration, enable = enable}
Nenue@13 21
Nenue@13 22
Nenue@13 23 local itemButton
Nenue@13 24 if not info.itemButton then
Nenue@13 25 if #freeButtons >= 1 then
Nenue@13 26 print(' |cFF00FFFFfound a free button')
Nenue@13 27 itemButton = freeButtons[#freeButtons]
Nenue@13 28 freeButtons[#freeButtons] = nil
Nenue@13 29 if itemButton.block then
Nenue@13 30 itemButton.block.itemButton = nil
Nenue@13 31 itemButton.block = nil
Nenue@13 32 end
Nenue@13 33 else
Nenue@13 34 local buttonIndex = mod.Quest.numButtons + #freeButtons + 1
Nenue@13 35 itemButton = CreateFrame('Button', 'VeneerQuestItemButton' .. buttonIndex, UIParent, 'VeneerItemButtonTemplate')
Nenue@13 36 itemButton.buttonIndex = buttonIndex
Nenue@13 37 itemButton:SetSize(36, 36)
Nenue@13 38 itemButton:GetNormalTexture():SetSize(36 * (5/3), 36 * (5/3))
Nenue@13 39 print(' |cFFFF4400starting new button', itemButton:GetName())
Nenue@13 40 end
Nenue@13 41 mod.Quest.numButtons = mod.Quest.numButtons + 1
Nenue@13 42 else
Nenue@13 43 itemButton = info.itemButton
Nenue@13 44 print(' |cFF00FF00found assigned button', itemButton:GetName())
Nenue@13 45
Nenue@13 46 end
Nenue@13 47 -- set values
Nenue@13 48
Nenue@13 49 info.itemButton = itemButton
Nenue@13 50 usedButtons[info.questID] = itemButton
Nenue@13 51 print(' |cFF8800FFassigning|r', itemButton:GetName(), 'to quest|cFF00FF00', info.questID, '|rat|cFFFFFF00', block:GetName(),'|r')
Nenue@13 52
Nenue@13 53 for k,v in pairs(usedButtons) do
Nenue@13 54 print('|cFFFF44DD'..k..'|r', v:GetName())
Nenue@13 55 end
Nenue@13 56
Nenue@13 57 itemButton:SetAttribute("type", "item")
Nenue@13 58 itemButton:SetAttribute("item", itemInfo.link)
Nenue@13 59
Nenue@13 60 itemButton.questID = info.questID
Nenue@13 61 itemButton.questLogIndex = info.questLogIndex
Nenue@13 62 itemButton.charges = itemInfo.charges
Nenue@13 63 itemButton.rangeTimer = -1
Nenue@13 64 itemButton.block = block
Nenue@13 65
Nenue@13 66 SetItemButtonTexture(itemButton, itemInfo.icon)
Nenue@13 67 SetItemButtonCount(itemButton, itemInfo.charges)
Nenue@13 68 Veneer_QuestObjectiveItem_UpdateCooldown(itemButton);
Nenue@13 69
Nenue@13 70 return itemButton
Nenue@13 71 end
Nenue@13 72 --- Clear an itemButton from the given block
Nenue@13 73 mod.FreeItemButtons = function(block)
Nenue@13 74
Nenue@13 75 if block.itemButton then
Nenue@13 76 local itemButton = block.itemButton
Nenue@13 77 if itemButton.questID ~= block.info.questID then
Nenue@13 78 block.itemButton = nil
Nenue@13 79 itemButton.block = mod.Quest.InfoBlock[itemButton.questID]
Nenue@13 80 else
Nenue@13 81 itemButton.block = nil
Nenue@13 82 itemButton:Hide()
Nenue@13 83
Nenue@13 84 usedButtons[itemButton.questID] = nil
Nenue@13 85 freeButtons[#freeButtons + 1] = itemButton
Nenue@13 86 mod.Quest.numButtons = mod.Quest.numButtons - 1
Nenue@13 87 print('|cFFFF0088released', itemButton:GetName(),'and', block:GetName())
Nenue@13 88 end
Nenue@13 89 end
Nenue@13 90 end
Nenue@13 91
Nenue@13 92 function Veneer_QuestObjectiveItem_OnUpdate (self, elapsed)
Nenue@13 93 -- Handle range indicator
Nenue@13 94 local rangeTimer = self.rangeTimer
Nenue@13 95 if (rangeTimer) then
Nenue@13 96 rangeTimer = rangeTimer - elapsed
Nenue@13 97 if (rangeTimer <= 0) then
Nenue@13 98 local link, item, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(self.questLogIndex)
Nenue@13 99 if ((not charges) or (charges ~= self.charges)) then
Nenue@13 100 mod.UpdateWrapper()
Nenue@13 101 return
Nenue@13 102 end
Nenue@13 103
Nenue@13 104 local count = self.HotKey
Nenue@13 105 local valid = IsQuestLogSpecialItemInRange(self.questLogIndex)
Nenue@13 106 if (valid == 0) then
Nenue@13 107 count:Show()
Nenue@13 108 count:SetVertexColor(1.0, 0.1, 0.1)
Nenue@13 109 elseif (valid == 1) then
Nenue@13 110 count:Show()
Nenue@13 111 count:SetVertexColor(0.6, 0.6, 0.6)
Nenue@13 112 else
Nenue@13 113 count:Hide()
Nenue@13 114 end
Nenue@13 115 rangeTimer = TOOLTIP_UPDATE_TIME
Nenue@13 116 end
Nenue@13 117
Nenue@13 118 self.rangeTimer = rangeTimer
Nenue@13 119 end
Nenue@13 120 end
Nenue@13 121
Nenue@13 122 function Veneer_QuestObjectiveItem_UpdateCooldown (itemButton)
Nenue@13 123 local start, duration, enable = GetQuestLogSpecialItemCooldown(itemButton.questLogIndex)
Nenue@13 124 if (start) then
Nenue@13 125 CooldownFrame_SetTimer(itemButton.Cooldown, start, duration, enable)
Nenue@13 126 if (duration > 0 and enable == 0) then
Nenue@13 127 SetItemButtonTextureVertexColor(itemButton, 0.4, 0.4, 0.4)
Nenue@13 128 else
Nenue@13 129 SetItemButtonTextureVertexColor(itemButton, 1, 1, 1)
Nenue@13 130 end
Nenue@13 131 end
Nenue@13 132 end
Nenue@13 133
Nenue@13 134 -----------------------------------------
Nenue@13 135 -- Criteria frames
Nenue@13 136
Nenue@13 137 --[[
Nenue@13 138 text = description,
Nenue@13 139 type = type,
Nenue@13 140 finished = completed,
Nenue@13 141 quantity = quantity,
Nenue@13 142 requiredQuantity = requiredQuantity,
Nenue@13 143 characterName = characterName,
Nenue@13 144 flags = flags,
Nenue@13 145 assetID = assetID,
Nenue@13 146 quantityString = quantityString,
Nenue@13 147 criteriaID = criteriaID,
Nenue@13 148 ]]
Nenue@13 149 local newWidgetID = 0
Nenue@13 150 mod.WidgetRegistry = {}
Nenue@13 151 local wr = mod.WidgetRegistry
Nenue@13 152
Nenue@13 153 --- Get a usable widget for the given achievement criteria set.
Nenue@13 154 -- Returns a frame object with dimensioning parameters needed to size the receiving tracker block
Nenue@13 155 mod.SetWidget = function(obj, info)
Nenue@13 156 local print = B.print('ObjectiveWidgets')
Nenue@13 157 local widgetType = obj.type
Nenue@13 158 local widget
Nenue@13 159 if wr[widgetType] and wr[widgetType].used[obj.criteriaID] then
Nenue@13 160 widget = wr[widgetType].used[obj.criteriaID]
Nenue@13 161 print('|cFF00FF00Updating ('..obj.criteriaID..')', widget)
Nenue@13 162 elseif not wr[widgetType] or #wr[widgetType].free == 0 then
Nenue@13 163 widget = CreateFrame('Frame', 'VeneerObjective' .. widgetType .. (wr[widgetType] and (wr[widgetType].lastn+1) or (1)), VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType)
Nenue@13 164
Nenue@13 165 print('|cFFFF0088Creating `'..widget:GetName()..'` id', wr[widgetType].lastn)
Nenue@13 166 else
Nenue@13 167 widget = tremove(wr[widgetType].free)
Nenue@13 168 print('|cFFFFFF00Acquiring released widget', widget:GetName())
Nenue@13 169 end
Nenue@13 170
Nenue@13 171 wr[widgetType].used[obj.criteriaID] = widget
Nenue@13 172 widget.info = obj
Nenue@13 173 widget.parentInfo = info
Nenue@13 174 mod.InitializeWidget(widget)
Nenue@13 175 return widget
Nenue@13 176 end
Nenue@13 177
Nenue@13 178 --- WidgetTemplate 'OnLoad'
Nenue@13 179 mod.RegisterWidget = function(frame)
Nenue@13 180 local print = B.print('ObjectiveWidgets')
Nenue@13 181 local widgetType = frame.widgetType
Nenue@13 182 if not wr[frame.widgetType] then
Nenue@13 183 print('|cFFFF4400[[WidgetTemplate]]|r', widgetType)
Nenue@13 184 wr[widgetType] = { lastn = 1, free = {}, used = {}, usedIndex = {}, freeIndex = {} }
Nenue@13 185 else
Nenue@13 186 print('|cFF0088FF+ [[WidgetTemplate]]r', widgetType, wr[widgetType].lastn)
Nenue@13 187 wr[widgetType].lastn = wr[widgetType].lastn + 1
Nenue@13 188 end
Nenue@13 189 end
Nenue@13 190
Nenue@13 191 --- WidgetTemplate 'OnShow'
Nenue@13 192 mod.InitializeWidget = setmetatable({}, {
Nenue@13 193 __call = function(t, frame)
Nenue@13 194 -- todo: config pull
Nenue@13 195 local maxWidth = 250
Nenue@13 196
Nenue@13 197 frame:SetWidth(maxWidth)
Nenue@13 198 mod.UpdateWidget[frame.widgetType](frame)
Nenue@13 199 frame:SetScript('OnEvent', mod.UpdateWidget[frame.widgetType])
Nenue@13 200 if frame.info.isCurrency then
Nenue@13 201 frame:RegisterEvent('CHAT_MSG_CURRENCY')
Nenue@13 202 frame:RegisterEvent('CURRENCY_LIST_UPDATE')
Nenue@13 203 end
Nenue@13 204 frame:RegisterEvent('TRACKED_ACHIEVEMENT_UPDATE')
Nenue@13 205 frame:RegisterEvent('TRACKED_ACHIEVEMENT_LIST_CHANGED')
Nenue@13 206 frame:RegisterEvent('CRITERIA_UPDATE')
Nenue@13 207 frame:RegisterEvent('CRITERIA_COMPLETE')
Nenue@13 208 frame:RegisterEvent('CRITERIA_EARNED')
Nenue@13 209
Nenue@13 210 return t[frame.widgetType](frame)
Nenue@13 211 end,
Nenue@13 212 })
Nenue@13 213
Nenue@13 214 --- WidgetTemplate 'OnEvent'
Nenue@13 215 mod.UpdateWidget = setmetatable({}, {
Nenue@13 216 __call = function(t, frame)
Nenue@13 217 if not frame.widgetType then
Nenue@13 218 error('Invalid widget template, needs .widgetType')
Nenue@13 219 return
Nenue@13 220 end
Nenue@13 221
Nenue@13 222 return t[frame.widgetType](frame)
Nenue@13 223 end
Nenue@13 224 })
Nenue@13 225
Nenue@13 226 --- WidgetTemplate 'OnHide'
Nenue@13 227 mod.ReleaseWidget = function(frame)
Nenue@13 228 local print = B.print('ObjectiveWidgets')
Nenue@13 229 local reg = wr[frame.widgetType]
Nenue@13 230 if reg and reg.used[frame.info.criteriaID] then
Nenue@13 231 reg.used[frame.info.criteriaID] = nil
Nenue@13 232 frame.info = nil
Nenue@13 233 frame.parentInfo = nil
Nenue@13 234 frame:UnregisterAllEvents()
Nenue@13 235 tinsert(reg.free, frame)
Nenue@13 236 print('|cFFBBBBBBreleased from service', frame:GetName())
Nenue@13 237 end
Nenue@13 238 end
Nenue@13 239
Nenue@13 240 --- RemoveTrackedAchievement post-hook
Nenue@13 241 mod.CleanWidgets = function()
Nenue@13 242 local print = B.print('ObjectiveWidgets')
Nenue@13 243 local tracked = {GetTrackedAchievements() }
Nenue@13 244 for type, reg in pairs(mod.WidgetRegistry) do
Nenue@13 245 print('collecting', type)
Nenue@13 246 for criteriaID, frame in pairs(reg.used) do
Nenue@13 247 local id = frame.info.cheevID
Nenue@13 248
Nenue@13 249 if id and not tContains(tracked, id) then
Nenue@13 250
Nenue@13 251 print(' untracked achievement', id, 'associated with', criteriaID, frame:GetName())
Nenue@13 252 frame:Hide()
Nenue@13 253 end
Nenue@13 254 end
Nenue@13 255 end
Nenue@13 256 end
Nenue@13 257
Nenue@13 258
Nenue@13 259 mod.defaults.WidgetVars = {
Nenue@13 260 ProgressBar = {
Nenue@13 261 bg = {
Nenue@13 262 Height = 20,
Nenue@13 263 },
Nenue@13 264 fg = {
Nenue@13 265 Height = 16,
Nenue@13 266 },
Nenue@13 267 status = {
Nenue@13 268 FontObject = _G.VeneerFontNormal
Nenue@13 269 }
Nenue@13 270 }
Nenue@13 271 }
Nenue@13 272 mod.InitializeWidget.ProgressBar = function(self)
Nenue@13 273 local c = mod.defaults.WidgetVars.ProgressBar
Nenue@13 274 local params = mod.WidgetParams[self.widgetType]
Nenue@13 275 self.height = params.height
Nenue@13 276 self:SetHeight(c.bg.Height)
Nenue@13 277 self.bg:SetHeight(c.bg.Height)
Nenue@13 278 self.fg:ClearAllPoints()
Nenue@13 279 self.fg:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', 2, 2)
Nenue@13 280 self.fg:SetHeight(c.fg.Height)
Nenue@13 281 self.status:SetFontObject(c.status.FontObject)
Nenue@13 282 self.status:SetText(self.info.quantityString)
Nenue@13 283 end
Nenue@13 284
Nenue@13 285 mod.UpdateWidget.ProgressBar = function (self)
Nenue@13 286 local quantity, requiredQuantity = self.info.quantity, self.info.requiredQuantity
Nenue@13 287
Nenue@13 288 if self.info.finished then
Nenue@13 289 self.fg:SetWidth(self.bg:GetWidth() - 4)
Nenue@13 290 elseif quantity == 0 then
Nenue@13 291 self.fg:Hide()
Nenue@13 292 else
Nenue@13 293 self.fg:Show()
Nenue@13 294 self.fg:SetWidth((self.bg:GetWidth()-4) * (quantity / requiredQuantity))
Nenue@13 295 end
Nenue@13 296 end
Nenue@13 297
Nenue@13 298
Nenue@13 299 mod.InitializeWidget.Hidden = function (self)
Nenue@13 300 self.height = 0
Nenue@13 301 end
Nenue@13 302 mod.UpdateWidget.Hidden = function (self)
Nenue@13 303 self.height= 0
Nenue@13 304 end