Mercurial > wow > buffalo2
view ObjectiveTracker/Widgets.lua @ 37:e84d645c8ab8
- revised the tracker update function to build its complete data list up front and use the values as points of comparison for determining possible out of place blocks, which will be iterated over afterward to remove what wasn't re-used
- also entailed revising the exact role of global event handlers and function hooks, limiting their directions of communication so one doesn't end up calling the other multiple or inifinity times
- schema handling polish
author | Nenue |
---|---|
date | Mon, 18 Apr 2016 07:56:23 -0400 |
parents | 69d03f8e293e |
children | 1f8f9cc3d956 |
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() if T.Conf.enabled then T:Update() end 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.logIndex = info.logIndex 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.logIndex) if ((not charges) or (charges ~= self.charges)) then T:Update() return end local count = self.HotKey local valid = IsQuestLogSpecialItemInRange(self.logIndex) 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.logIndex) 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' local wrapperWidth, textIndent T.InitializeWidget = setmetatable({}, { __call = function(t, frame) -- todo: config pull if not wrapperWidth then wrapperWidth = T.Conf.Wrapper.Width textIndent = T.Conf.Wrapper.TextIndent end frame:SetWidth(wrapperWidth - textIndent * 2) frame:SetScript('OnEvent', T.UpdateWidget[frame.widgetType]) frame:RegisterEvent('QUEST_LOG_UPDATE') 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 = 17 local progressBorder = 1 local progressFont = _G.VeneerCriteriaFontNormal local lprint = B.print('Line') T.InitializeWidget.ProgressBar = function(self) local print = lprint local c = T.Conf.Wrapper self.height = progressHeight + c.TextSpacing self.width = c.Width - c.TextSpacing self.value = self.value or 1 self.maxValue = self.maxValue or 1 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.value, self.maxValue print('update vals:') for k,v in pairs(self.line) do print(k, v) 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 --- Queue any active item buttons for update for that frame local iprint = B.print('ItemButton') local Quest = T.Quest local IsQuestWatched, InCombatLockdown = IsQuestWatched, InCombatLockdown T.UpdateActionButtons = function(updateReason) local print = iprint Scroller.snap_upper = 0 Scroller.snap_lower = 0 local print = B.print('ItemButton') if updateReason then print = B.print('IB_'..updateReason) end local previousItem for questID, itemButton in pairs(Quest.itemButtons) do local info= T.Quest.Info[questID] print('|cFF00FFFF'.. questID .. '|r', itemButton:GetName()) local block = T.Quest.QuestBlock[questID] if block then -- Dispatch the probe if IsQuestWatched(info.logIndex) then itemButton.previousItem = previousItem print(' |cFFFFFF00probing', block:GetName()) block:SetScript('OnUpdate', function() if block:GetBottom() and not InCombatLockdown() then print(' '..block:GetName()..' |cFF00FF00probe hit!') T.UpdateBlockAction(block, itemButton, itemButton.previousItem) -- needs to be previousItem from this scope block:SetScript('OnUpdate', nil) end end) previousItem = itemButton else print('hidden block or unwatched quest') itemButton.previousItem = nil itemButton:Hide() end elseif itemButton:IsVisible() then print(' |cFFFF0088hiding unwatched quest button', itemButton:GetName()) itemButton.previousItem = nil itemButton:Hide() else print(' |cFFBBBBBBignoring hidden log quest button', itemButton:GetName()) end end end