Nenue@28: local B = select(2,...).frame Nenue@28: local T = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@28: local print = B.print('WidgetFactory') Nenue@28: local _G, UIParent = _G, UIParent Nenue@28: local GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown Nenue@28: local CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll = CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll Nenue@28: local tremove, tContains, pairs, ipairs, setmetatable, floor = tremove, tContains, pairs, ipairs, setmetatable, floor Nenue@28: local SetItemButtonTexture, SetItemButtonCount = SetItemButtonTexture, SetItemButtonCount Nenue@28: local ToggleWorldMap, GetTrackedAchievements, GetTasksTable = ToggleWorldMap, GetTrackedAchievements, GetTasksTable Nenue@28: -- GLOBALS: Veneer_QuestObjectiveItem_UpdateCooldown, Veneer_QuestObjectiveItem_OnUpdate Nenue@28: --- frame refs Nenue@28: local Wrapper = _G.VeneerObjectiveWrapper Nenue@28: local Scroller = Wrapper.scrollArea Nenue@28: local CloseButton = Wrapper.CloseButton Nenue@28: local QuestMapButton = Wrapper.QuestMapButton Nenue@28: local Scroll = _G.VeneerObjectiveScroll Nenue@28: local usedButtons = T.Quest.itemButtons Nenue@28: local freeButtons = T.Quest.freeButtons Nenue@28: Nenue@28: T.buttons = { Nenue@28: CloseButton = { Nenue@28: closedSwatch = { Nenue@28: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@28: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@28: 0, 0.5, 0.5, 1, Nenue@28: 0.5, 1, 0.5, 1, Nenue@28: }, Nenue@28: openSwatch = { Nenue@28: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@28: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@28: 0.5, 1, 0.5, 1, Nenue@28: 0, 0.5, 0.5, 1, Nenue@28: }, Nenue@28: parent = 'VeneerObjectiveWrapper' Nenue@28: }, Nenue@28: QuestMapButton = { Nenue@28: closedSwatch = { Nenue@28: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@28: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@28: 0, 1, 0.5, 1, Nenue@28: 0, 1, 0, 0.5, Nenue@28: }, Nenue@28: openSwatch = { Nenue@28: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@28: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@28: 0, 1, 0, 0.5, Nenue@28: 0, 1, 0.5, 1, Nenue@28: } Nenue@28: } Nenue@28: } Nenue@28: Nenue@28: local Scroller_OnShow = function() Nenue@28: Wrapper.watchMoneyReasons = 0; Nenue@28: --T:Update() Nenue@28: --T:OnInitialize() Nenue@28: for i, region in ipairs(Wrapper.headerComplex) do Nenue@28: region:Show() Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: local Scroller_OnHide = function() Nenue@28: local self = Wrapper Nenue@28: Wrapper:UnregisterAllEvents() Nenue@28: Wrapper:SetScript('OnEvent', nil) Nenue@28: for i, region in ipairs(Wrapper.headerComplex) do Nenue@28: region:Hide() Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: local Scroller_OnMouseWheel = function(self, delta) Nenue@28: local r = Scroll:GetHeight() - Scroller:GetHeight() Nenue@28: local s = B.Conf.ObjectiveScroll - delta * floor(r/5+.5) Nenue@28: local from = self:GetVerticalScroll() Nenue@28: print('|cFF00FF00OnMouseWheel', 'scroll =', s) Nenue@28: if s >= r then Nenue@28: s = r Nenue@28: elseif s < 1 then Nenue@28: s = 0 Nenue@28: end Nenue@28: self:SetVerticalScroll(s) Nenue@28: B.Conf.ObjectiveScroll = s Nenue@28: print('|cFF00FF00OnMouseWheel', 'from = ', from, 'scroll =', s, ' range =', r, 'current =', self:GetVerticalScroll()) Nenue@28: Nenue@28: T.UpdateActionButtons('SCROLLING') Nenue@28: end Nenue@28: Nenue@28: local UpdatePanelButton = function (self, state) Nenue@28: state = state or true Nenue@28: local swatch = (state == true) and self.openSwatch or self.closedSwatch Nenue@28: print((state ~= true) and 'closedSwatch' or 'openSwatch') Nenue@28: self:SetNormalTexture(swatch[1]) Nenue@28: self:SetPushedTexture(swatch[2]) Nenue@28: if #swatch >= 6 then Nenue@28: self:GetNormalTexture():SetTexCoord(swatch[3], swatch[4], swatch[5], swatch[6]) Nenue@28: end Nenue@28: if #swatch == 10 then Nenue@28: self:GetPushedTexture():SetTexCoord(swatch[7], swatch[8], swatch[9], swatch[10]) Nenue@28: end Nenue@28: Nenue@28: end Nenue@28: Nenue@28: local OnClick = {} Nenue@28: OnClick.CloseButton = function(self) Nenue@28: T:SetEnabled() Nenue@34: if T.Conf.enabled then Nenue@34: T:Update() Nenue@34: end Nenue@34: Nenue@28: UpdatePanelButton(self, T.Conf.enabled) Nenue@28: end Nenue@28: Nenue@28: OnClick.QuestMapButton = function() Nenue@28: ToggleWorldMap() Nenue@28: end Nenue@28: Nenue@28: Nenue@28: T.InitializeWidgets = function() Nenue@28: local panelButtons = T.buttons Nenue@28: --- tracker scroll Nenue@28: Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel) Nenue@28: Scroller:SetScript('OnShow', Scroller_OnShow) Nenue@28: Scroller:SetScript('OnHide', Scroller_OnHide) Nenue@28: for name, swatch in pairs(panelButtons) do Nenue@28: local source = swatch and swatch or panelButtons.CloseButton Nenue@28: local button = Wrapper[name] Nenue@28: button.parent = swatch.parent Nenue@28: button.openSwatch = source.openSwatch Nenue@28: button.closedSwatch = source.closedSwatch Nenue@28: if OnClick[name] then Nenue@28: button:SetScript('OnClick', OnClick[name]) Nenue@28: end Nenue@28: UpdatePanelButton(button, T.Conf.enabled) Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: ---------------------------------------------------------------------------------------- Nenue@28: --- modified version of the itemButton initializer used by Barjack's 'QuestKing 2' addon, Nenue@28: --- url: http://mods.curse.com/addons/wow/questking Nenue@28: ---------------------------------------------------------------------------------------- Nenue@28: T.SetItemButton = function(block, info) Nenue@28: local itemInfo = info.specialItem Nenue@28: if not itemInfo then Nenue@28: return Nenue@28: end Nenue@28: Nenue@28: local itemButton Nenue@28: if not info.itemButton then Nenue@28: if #freeButtons >= 1 then Nenue@28: print(' |cFF00FFFFfound a free button') Nenue@28: itemButton = freeButtons[#freeButtons] Nenue@28: freeButtons[#freeButtons] = nil Nenue@28: if itemButton.block then Nenue@28: itemButton.block.itemButton = nil Nenue@28: itemButton.block = nil Nenue@28: end Nenue@28: else Nenue@28: local buttonIndex = T.Quest.numButtons + #freeButtons + 1 Nenue@28: itemButton = CreateFrame('Button', 'VeneerQuestItemButton' .. buttonIndex, UIParent, 'VeneerItemButtonTemplate') Nenue@28: itemButton.buttonIndex = buttonIndex Nenue@28: itemButton:SetSize(36, 36) Nenue@28: itemButton:GetNormalTexture():SetSize(36 * (5/3), 36 * (5/3)) Nenue@28: print(' |cFFFF4400starting new button', itemButton:GetName()) Nenue@28: end Nenue@28: T.Quest.numButtons = T.Quest.numButtons + 1 Nenue@28: else Nenue@28: itemButton = info.itemButton Nenue@28: print(' |cFF00FF00found assigned button', itemButton:GetName()) Nenue@28: Nenue@28: end Nenue@28: -- set values Nenue@28: Nenue@28: info.itemButton = itemButton Nenue@28: usedButtons[info.questID] = itemButton Nenue@28: print(' |cFF8800FFassigning|r', itemButton:GetName(), 'to quest|cFF00FF00', info.questID, '|rat|cFFFFFF00', block:GetName(),'|r') Nenue@28: Nenue@28: for k,v in pairs(usedButtons) do Nenue@28: print('|cFFFF44DD'..k..'|r', v:GetName()) Nenue@28: end Nenue@28: Nenue@28: itemButton:SetAttribute("type", "item") Nenue@28: itemButton:SetAttribute("item", itemInfo.link) Nenue@28: Nenue@28: itemButton.questID = info.questID Nenue@34: itemButton.logIndex = info.logIndex Nenue@28: itemButton.charges = itemInfo.charges Nenue@28: itemButton.rangeTimer = -1 Nenue@28: itemButton.block = block Nenue@28: Nenue@28: SetItemButtonTexture(itemButton, itemInfo.icon) Nenue@28: SetItemButtonCount(itemButton, itemInfo.charges) Nenue@28: Veneer_QuestObjectiveItem_UpdateCooldown(itemButton); Nenue@28: Nenue@28: return itemButton Nenue@28: end Nenue@28: --- Clear an itemButton from the given block Nenue@28: T.FreeItemButtons = function(block) Nenue@28: Nenue@28: if block.itemButton then Nenue@28: local itemButton = block.itemButton Nenue@28: if itemButton.questID ~= block.info.questID then Nenue@28: block.itemButton = nil Nenue@28: itemButton.block = T.Quest.InfoBlock[itemButton.questID] Nenue@28: else Nenue@28: itemButton.block = nil Nenue@28: itemButton:Hide() Nenue@28: Nenue@28: usedButtons[itemButton.questID] = nil Nenue@28: freeButtons[#freeButtons + 1] = itemButton Nenue@28: T.Quest.numButtons = T.Quest.numButtons - 1 Nenue@28: print('|cFFFF0088released', itemButton:GetName(),'and', block:GetName()) Nenue@28: end Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: function Veneer_QuestObjectiveItem_OnUpdate (self, elapsed) Nenue@28: -- Handle range indicator Nenue@28: local rangeTimer = self.rangeTimer Nenue@28: if (rangeTimer) then Nenue@28: rangeTimer = rangeTimer - elapsed Nenue@28: if (rangeTimer <= 0) then Nenue@34: local link, item, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(self.logIndex) Nenue@28: if ((not charges) or (charges ~= self.charges)) then Nenue@28: T:Update() Nenue@28: return Nenue@28: end Nenue@28: Nenue@28: local count = self.HotKey Nenue@34: local valid = IsQuestLogSpecialItemInRange(self.logIndex) Nenue@28: if (valid == 0) then Nenue@28: count:Show() Nenue@28: count:SetVertexColor(1.0, 0.1, 0.1) Nenue@28: elseif (valid == 1) then Nenue@28: count:Show() Nenue@28: count:SetVertexColor(0.6, 0.6, 0.6) Nenue@28: else Nenue@28: count:Hide() Nenue@28: end Nenue@28: rangeTimer = TOOLTIP_UPDATE_TIME Nenue@28: end Nenue@28: Nenue@28: self.rangeTimer = rangeTimer Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: function Veneer_QuestObjectiveItem_UpdateCooldown (itemButton) Nenue@34: local start, duration, enable = GetQuestLogSpecialItemCooldown(itemButton.logIndex) Nenue@28: if (start) then Nenue@28: CooldownFrame_SetTimer(itemButton.Cooldown, start, duration, enable) Nenue@28: if (duration > 0 and enable == 0) then Nenue@28: SetItemButtonTextureVertexColor(itemButton, 0.4, 0.4, 0.4) Nenue@28: else Nenue@28: SetItemButtonTextureVertexColor(itemButton, 1, 1, 1) Nenue@28: end Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: ----------------------------------------- Nenue@28: -- Criteria frames Nenue@28: Nenue@28: --[[ Nenue@28: text = description, Nenue@28: type = type, Nenue@28: finished = completed, Nenue@28: quantity = quantity, Nenue@28: requiredQuantity = requiredQuantity, Nenue@28: characterName = characterName, Nenue@28: flags = flags, Nenue@28: assetID = assetID, Nenue@28: quantityString = quantityString, Nenue@28: criteriaID = criteriaID, Nenue@28: ]] Nenue@28: local newWidgetID = 0 Nenue@28: T.WidgetRegistry = {} Nenue@28: local wr = T.WidgetRegistry Nenue@28: Nenue@28: --- Get a usable widget for the given achievement criteria set. Nenue@28: -- Returns a frame object with dimensioning parameters needed to size the receiving tracker block Nenue@28: T.SetWidget = function(line, data, objectiveType, objectiveKey) Nenue@28: local print = B.print('ObjectiveWidgets') Nenue@28: local widgetType = objectiveType Nenue@28: local widget Nenue@28: if wr[widgetType] and wr[widgetType].used[objectiveKey] then Nenue@28: widget = wr[widgetType].used[objectiveKey] Nenue@28: print('|cFF00FF00Updating ('..objectiveKey..')', widget) Nenue@28: elseif not wr[widgetType] or #wr[widgetType].free == 0 then Nenue@28: widget = CreateFrame('Frame', 'VeneerObjective' .. widgetType .. (wr[widgetType] and (wr[widgetType].lastn+1) or (1)), VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType) Nenue@28: Nenue@28: print('|cFFFF0088Creating `'..widget:GetName()..'` id', wr[widgetType].lastn) Nenue@28: else Nenue@28: widget = tremove(wr[widgetType].free) Nenue@28: print('|cFFFFFF00Acquiring released widget', widget:GetName()) Nenue@28: end Nenue@28: Nenue@28: Nenue@28: wr[widgetType].used[objectiveKey] = widget Nenue@28: widget.line = line Nenue@28: widget.objective = data Nenue@28: widget.key = objectiveKey Nenue@28: T.InitializeWidget(widget) Nenue@28: return widget Nenue@28: end Nenue@28: Nenue@28: --- WidgetTemplate 'OnLoad' Nenue@28: T.RegisterWidget = function(frame) Nenue@28: local print = B.print('ObjectiveWidgets') Nenue@28: local widgetType = frame.widgetType Nenue@28: if not wr[frame.widgetType] then Nenue@28: print('|cFFFF4400[[WidgetTemplate]]|r', widgetType) Nenue@28: wr[widgetType] = { lastn = 1, free = {}, used = {}, usedIndex = {}, freeIndex = {} } Nenue@28: else Nenue@28: print('|cFF0088FF+ [[WidgetTemplate]]r', widgetType, wr[widgetType].lastn) Nenue@28: wr[widgetType].lastn = wr[widgetType].lastn + 1 Nenue@28: end Nenue@28: end Nenue@28: --- WidgetTemplate 'OnShow' Nenue@33: local wrapperWidth, textIndent Nenue@28: T.InitializeWidget = setmetatable({}, { Nenue@28: __call = function(t, frame) Nenue@28: -- todo: config pull Nenue@33: if not wrapperWidth then Nenue@33: wrapperWidth = T.Conf.Wrapper.Width Nenue@33: textIndent = T.Conf.Wrapper.TextIndent Nenue@33: end Nenue@28: Nenue@33: frame:SetWidth(wrapperWidth - textIndent * 2) Nenue@28: frame:SetScript('OnEvent', T.UpdateWidget[frame.widgetType]) Nenue@34: frame:RegisterEvent('QUEST_LOG_UPDATE') Nenue@28: frame:RegisterEvent('TRACKED_ACHIEVEMENT_UPDATE') Nenue@28: frame:RegisterEvent('TRACKED_ACHIEVEMENT_LIST_CHANGED') Nenue@28: frame:RegisterEvent('CRITERIA_UPDATE') Nenue@28: frame:RegisterEvent('CRITERIA_COMPLETE') Nenue@28: frame:RegisterEvent('CRITERIA_EARNED') Nenue@28: t[frame.widgetType](frame) Nenue@28: T.UpdateWidget[frame.widgetType](frame) Nenue@28: end, Nenue@28: }) Nenue@28: Nenue@28: --- WidgetTemplate 'OnEvent' Nenue@28: T.UpdateWidget = setmetatable({}, { Nenue@28: __call = function(t, frame) Nenue@28: if not frame.widgetType then Nenue@28: error('Invalid widget template, needs .widgetType') Nenue@28: return Nenue@28: end Nenue@28: Nenue@28: return t[frame.widgetType](frame) Nenue@28: end Nenue@28: }) Nenue@28: Nenue@28: --- WidgetTemplate 'OnHide' Nenue@28: T.ReleaseWidget = function(frame) Nenue@28: --[[ Nenue@28: local print = B.print('ObjectiveWidgets') Nenue@28: local reg = wr[frame.widgetType] Nenue@28: if reg and reg.used[frame.key] then Nenue@28: reg.used[frame.key] = nil Nenue@28: frame.line = nil Nenue@28: frame.info = nil Nenue@28: frame:UnregisterAllEvents() Nenue@28: tinsert(reg.free, frame) Nenue@28: print('|cFFBBBBBBreleased from service', frame:GetName()) Nenue@28: end Nenue@28: ]] Nenue@28: end Nenue@28: Nenue@28: --- RemoveTrackedAchievement post-hook Nenue@28: T.CleanWidgets = function() Nenue@28: local print = B.print('ObjectiveWidgets') Nenue@28: local tracked = {GetTrackedAchievements() } Nenue@28: local tasks = GetTasksTable() Nenue@28: for type, reg in pairs(T.WidgetRegistry) do Nenue@28: print('collecting', type) Nenue@28: for key, frame in pairs(reg.used) do Nenue@28: if frame.objective.cheevID then Nenue@28: local id = frame.objective.cheevID Nenue@28: Nenue@28: if id and not tContains(tracked, id) then Nenue@28: Nenue@28: print(' untracked achievement', id, 'associated with', key, frame:GetName()) Nenue@28: frame:Hide() Nenue@28: end Nenue@28: elseif frame.objective.questID then Nenue@28: -- do something for quest task Nenue@28: end Nenue@28: end Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: Nenue@28: Nenue@28: T.defaults.WidgetStyle = { Nenue@28: Nenue@28: } Nenue@28: Nenue@34: local progressHeight = 8 Nenue@28: local progressBorder = 1 Nenue@28: local progressFont = _G.VeneerCriteriaFontNormal Nenue@28: Nenue@34: local lprint = B.print('Line') Nenue@28: T.InitializeWidget.ProgressBar = function(self) Nenue@34: local print = lprint Nenue@28: local c = T.Conf.Wrapper Nenue@28: self.height = progressHeight + c.TextSpacing Nenue@28: self.width = c.Width - c.TextSpacing Nenue@34: self.value = self.value or 1 Nenue@34: self.maxValue = self.maxValue or 1 Nenue@28: Nenue@28: self:SetHeight(progressHeight) Nenue@28: self.bg:SetHeight(progressHeight) Nenue@28: self.bg:SetWidth(self.width) Nenue@28: self.fg:ClearAllPoints() Nenue@28: self.fg:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', progressBorder, progressBorder) Nenue@28: self.fg:SetHeight(progressHeight - progressBorder * 2) Nenue@34: Nenue@28: self.status:SetFontObject(progressFont) Nenue@28: self.status:SetText(self.objective.quantityString) Nenue@28: end Nenue@28: Nenue@28: T.UpdateWidget.ProgressBar = function (self) Nenue@33: local quantity, requiredQuantity = self.value, self.maxValue Nenue@28: print('update vals:') Nenue@28: for k,v in pairs(self.line) do Nenue@28: print(k, v) Nenue@28: end Nenue@28: Nenue@28: local progress = (quantity / requiredQuantity) Nenue@28: if progress >= 1 then Nenue@28: self.fg:Show() Nenue@28: self.fg:SetWidth(self.width - progressBorder * 2) Nenue@28: elseif progress > 0 then Nenue@28: self.fg:Show() Nenue@28: print('color:', 1-progress*2 , progress*2 - 1,0,1) Nenue@28: print('width:', (self.width -progressBorder * 2) * progress) Nenue@28: self.fg:SetTexture(1-progress*2 , progress*2,0,1) Nenue@28: self.fg:SetWidth((self.width -progressBorder * 2) * progress) Nenue@28: else Nenue@28: self.fg:Hide() Nenue@28: end Nenue@28: end Nenue@28: Nenue@28: Nenue@28: T.InitializeWidget.Hidden = function (self) Nenue@28: self.height = 0 Nenue@28: end Nenue@28: T.UpdateWidget.Hidden = function (self) Nenue@28: self.height= 0 Nenue@35: end Nenue@35: Nenue@35: Nenue@35: --- Queue any active item buttons for update for that frame Nenue@35: local iprint = B.print('ItemButton') Nenue@35: local Quest = T.Quest Nenue@35: local IsQuestWatched, InCombatLockdown = IsQuestWatched, InCombatLockdown Nenue@35: T.UpdateActionButtons = function(updateReason) Nenue@35: local print = iprint Nenue@35: Scroller.snap_upper = 0 Nenue@35: Scroller.snap_lower = 0 Nenue@35: local print = B.print('ItemButton') Nenue@35: if updateReason then Nenue@35: print = B.print('IB_'..updateReason) Nenue@35: end Nenue@35: Nenue@35: local previousItem Nenue@35: for questID, itemButton in pairs(Quest.itemButtons) do Nenue@35: local info= T.Quest.Info[questID] Nenue@35: Nenue@35: print('|cFF00FFFF'.. questID .. '|r', itemButton:GetName()) Nenue@35: local block = T.Quest.QuestBlock[questID] Nenue@35: if block then Nenue@35: -- Dispatch the probe Nenue@35: if IsQuestWatched(info.logIndex) then Nenue@35: itemButton.previousItem = previousItem Nenue@35: print(' |cFFFFFF00probing', block:GetName()) Nenue@35: block:SetScript('OnUpdate', function() Nenue@35: if block:GetBottom() and not InCombatLockdown() then Nenue@35: print(' '..block:GetName()..' |cFF00FF00probe hit!') Nenue@35: T.UpdateBlockAction(block, itemButton, itemButton.previousItem) -- needs to be previousItem from this scope Nenue@35: block:SetScript('OnUpdate', nil) Nenue@35: Nenue@35: end Nenue@35: end) Nenue@35: previousItem = itemButton Nenue@35: else Nenue@35: print('hidden block or unwatched quest') Nenue@35: itemButton.previousItem = nil Nenue@35: itemButton:Hide() Nenue@35: end Nenue@35: elseif itemButton:IsVisible() then Nenue@35: print(' |cFFFF0088hiding unwatched quest button', itemButton:GetName()) Nenue@35: itemButton.previousItem = nil Nenue@35: itemButton:Hide() Nenue@35: else Nenue@35: print(' |cFFBBBBBBignoring hidden log quest button', itemButton:GetName()) Nenue@35: end Nenue@35: end Nenue@28: end