Nenue@13: local B = select(2,...).frame Nenue@13: local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame') Nenue@13: local print = B.print('WidgetFactory') Nenue@13: local UIParent = UIParent Nenue@13: local GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown = GetQuestLogSpecialItemInfo, IsQuestLogSpecialItemInRange, GetQuestLogSpecialItemCooldown Nenue@13: local CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll = CooldownFrame_SetTimer, SetItemButtonTextureVertexColor, CreateFrame, VeneerObjectiveScroll Nenue@13: local tremove, tinsert, tContains, pairs, setmetatable = tremove, tinsert, tContains, pairs, setmetatable Nenue@14: Nenue@14: --- frame refs Nenue@14: local Wrapper = _G.VeneerObjectiveWrapper Nenue@14: local Scroller = Wrapper.scrollArea Nenue@14: local CloseButton = Wrapper.CloseButton Nenue@14: local QuestMapButton = Wrapper.QuestMapButton Nenue@14: local Scroll = _G.VeneerObjectiveScroll Nenue@14: Nenue@14: local panelButtons = { Nenue@14: CloseButton = { Nenue@14: closedSwatch = { Nenue@14: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@14: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@14: 0, 0.5, 0.5, 1, Nenue@14: 0.5, 1, 0.5, 1, Nenue@14: }, Nenue@14: openSwatch = { Nenue@14: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@14: [[Interface\Buttons\UI-Panel-QuestHideButton]], Nenue@14: 0.5, 1, 0.5, 1, Nenue@14: 0, 0.5, 0.5, 1, Nenue@14: }, Nenue@14: parent = 'VeneerObjectiveWrapper' Nenue@14: }, Nenue@14: QuestMapButton = { Nenue@14: closedSwatch = { Nenue@14: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@14: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@14: 0, 1, 0.5, 1, Nenue@14: 0, 1, 0, 0.5, Nenue@14: }, Nenue@14: openSwatch = { Nenue@14: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@14: [[Interface\QUESTFRAME\UI-QUESTMAP_BUTTON]], Nenue@14: 0, 1, 0, 0.5, Nenue@14: 0, 1, 0.5, 1, Nenue@14: } Nenue@14: } Nenue@14: } Nenue@14: Nenue@14: local Scroller_OnShow = function() Nenue@14: Wrapper.watchMoneyReasons = 0; Nenue@14: mod.UpdateWrapper() Nenue@14: mod.SetEvents() Nenue@14: for i, region in ipairs(Wrapper.headerComplex) do Nenue@14: region:Show() Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: local Scroller_OnHide = function() Nenue@14: local self = Wrapper Nenue@14: Wrapper:UnregisterAllEvents() Nenue@14: Wrapper:SetScript('OnEvent', nil) Nenue@14: for i, region in ipairs(Wrapper.headerComplex) do Nenue@14: region:Hide() Nenue@14: end Nenue@14: end Nenue@14: Nenue@14: local Scroller_OnMouseWheel = function(self, delta) Nenue@14: local r = Scroll:GetHeight() - Scroller:GetHeight() Nenue@14: local s = B.Conf.ObjectiveScroll - delta * floor(r/5+.5) Nenue@14: local from = self:GetVerticalScroll() Nenue@14: if s >= r then Nenue@14: s = r Nenue@14: elseif s < 1 then Nenue@14: s = 0 Nenue@14: end Nenue@14: self:SetVerticalScroll(s) Nenue@14: B.Conf.ObjectiveScroll = s Nenue@14: print('|cFF00FF00OnMouseWheel', 'from = ', from, 'scroll =', s, ' range =', r, 'current =', self:GetVerticalScroll()) Nenue@14: Nenue@14: mod.UpdateActionButtons('SCROLLING') Nenue@14: end Nenue@14: Nenue@14: local UpdatePanelButton = function (self, state) Nenue@14: state = state and B.Conf.FrameState[state] or 1 Nenue@14: local swatch = (state == 1) and self.openSwatch or self.closedSwatch Nenue@14: self:SetNormalTexture(swatch[1]) Nenue@14: self:SetPushedTexture(swatch[2]) Nenue@14: if #swatch >= 6 then Nenue@14: self:GetNormalTexture():SetTexCoord(swatch[3], swatch[4], swatch[5], swatch[6]) Nenue@14: end Nenue@14: if #swatch == 10 then Nenue@14: self:GetPushedTexture():SetTexCoord(swatch[7], swatch[8], swatch[9], swatch[10]) Nenue@14: end Nenue@14: Nenue@14: end Nenue@14: Nenue@14: local OnClick = {} Nenue@14: OnClick.CloseButton = function(self) Nenue@14: Wrapper:Minimize() Nenue@14: UpdatePanelButton(self, self.parent) Nenue@14: end Nenue@14: Nenue@14: OnClick.QuestMapButton = function() Nenue@14: ToggleWorldMap() Nenue@14: end Nenue@14: Nenue@14: mod.InitializeWrapperWidgets = function() Nenue@14: --- tracker scroll Nenue@14: Scroller:SetScript('OnMouseWheel', Scroller_OnMouseWheel) Nenue@14: Scroller:SetScript('OnShow', Scroller_OnShow) Nenue@14: Scroller:SetScript('OnHide', Scroller_OnHide) Nenue@14: for name, swatch in pairs(panelButtons) do Nenue@14: local source = swatch and swatch or panelButtons.CloseButton Nenue@14: local button = Wrapper[name] Nenue@14: button.parent = swatch.parent Nenue@14: button.openSwatch = source.openSwatch Nenue@14: button.closedSwatch = source.closedSwatch Nenue@14: if OnClick[name] then Nenue@14: button:SetScript('OnClick', OnClick[name]) Nenue@14: end Nenue@14: UpdatePanelButton(button, button.parent) Nenue@14: end Nenue@14: end Nenue@14: Nenue@13: ---------------------------------------------------------------------------------------- Nenue@13: --- XML and script code lifted from "QuestKing 2" by Barjack, Nenue@13: --- found at http://mods.curse.com/addons/wow/questking Nenue@13: ---------------------------------------------------------------------------------------- Nenue@13: local usedButtons = mod.Quest.itemButtons Nenue@13: local freeButtons = mod.Quest.freeButtons Nenue@13: mod.SetItemButton = function(block, info) Nenue@13: local itemInfo = info.specialItem Nenue@13: if not itemInfo then Nenue@13: return Nenue@13: end Nenue@13: Nenue@13: --- Quest.GetInfo().specialItem :: {link = link, charges = charges, icon = icon, start = start, duration = duration, enable = enable} Nenue@13: Nenue@13: Nenue@13: local itemButton Nenue@13: if not info.itemButton then Nenue@13: if #freeButtons >= 1 then Nenue@13: print(' |cFF00FFFFfound a free button') Nenue@13: itemButton = freeButtons[#freeButtons] Nenue@13: freeButtons[#freeButtons] = nil Nenue@13: if itemButton.block then Nenue@13: itemButton.block.itemButton = nil Nenue@13: itemButton.block = nil Nenue@13: end Nenue@13: else Nenue@13: local buttonIndex = mod.Quest.numButtons + #freeButtons + 1 Nenue@13: itemButton = CreateFrame('Button', 'VeneerQuestItemButton' .. buttonIndex, UIParent, 'VeneerItemButtonTemplate') Nenue@13: itemButton.buttonIndex = buttonIndex Nenue@13: itemButton:SetSize(36, 36) Nenue@13: itemButton:GetNormalTexture():SetSize(36 * (5/3), 36 * (5/3)) Nenue@13: print(' |cFFFF4400starting new button', itemButton:GetName()) Nenue@13: end Nenue@13: mod.Quest.numButtons = mod.Quest.numButtons + 1 Nenue@13: else Nenue@13: itemButton = info.itemButton Nenue@13: print(' |cFF00FF00found assigned button', itemButton:GetName()) Nenue@13: Nenue@13: end Nenue@13: -- set values Nenue@13: Nenue@13: info.itemButton = itemButton Nenue@13: usedButtons[info.questID] = itemButton Nenue@13: print(' |cFF8800FFassigning|r', itemButton:GetName(), 'to quest|cFF00FF00', info.questID, '|rat|cFFFFFF00', block:GetName(),'|r') Nenue@13: Nenue@13: for k,v in pairs(usedButtons) do Nenue@13: print('|cFFFF44DD'..k..'|r', v:GetName()) Nenue@13: end Nenue@13: Nenue@13: itemButton:SetAttribute("type", "item") Nenue@13: itemButton:SetAttribute("item", itemInfo.link) Nenue@13: Nenue@13: itemButton.questID = info.questID Nenue@13: itemButton.questLogIndex = info.questLogIndex Nenue@13: itemButton.charges = itemInfo.charges Nenue@13: itemButton.rangeTimer = -1 Nenue@13: itemButton.block = block Nenue@13: Nenue@13: SetItemButtonTexture(itemButton, itemInfo.icon) Nenue@13: SetItemButtonCount(itemButton, itemInfo.charges) Nenue@13: Veneer_QuestObjectiveItem_UpdateCooldown(itemButton); Nenue@13: Nenue@13: return itemButton Nenue@13: end Nenue@13: --- Clear an itemButton from the given block Nenue@13: mod.FreeItemButtons = function(block) Nenue@13: Nenue@13: if block.itemButton then Nenue@13: local itemButton = block.itemButton Nenue@13: if itemButton.questID ~= block.info.questID then Nenue@13: block.itemButton = nil Nenue@13: itemButton.block = mod.Quest.InfoBlock[itemButton.questID] Nenue@13: else Nenue@13: itemButton.block = nil Nenue@13: itemButton:Hide() Nenue@13: Nenue@13: usedButtons[itemButton.questID] = nil Nenue@13: freeButtons[#freeButtons + 1] = itemButton Nenue@13: mod.Quest.numButtons = mod.Quest.numButtons - 1 Nenue@13: print('|cFFFF0088released', itemButton:GetName(),'and', block:GetName()) Nenue@13: end Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: function Veneer_QuestObjectiveItem_OnUpdate (self, elapsed) Nenue@13: -- Handle range indicator Nenue@13: local rangeTimer = self.rangeTimer Nenue@13: if (rangeTimer) then Nenue@13: rangeTimer = rangeTimer - elapsed Nenue@13: if (rangeTimer <= 0) then Nenue@13: local link, item, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(self.questLogIndex) Nenue@13: if ((not charges) or (charges ~= self.charges)) then Nenue@13: mod.UpdateWrapper() Nenue@13: return Nenue@13: end Nenue@13: Nenue@13: local count = self.HotKey Nenue@13: local valid = IsQuestLogSpecialItemInRange(self.questLogIndex) Nenue@13: if (valid == 0) then Nenue@13: count:Show() Nenue@13: count:SetVertexColor(1.0, 0.1, 0.1) Nenue@13: elseif (valid == 1) then Nenue@13: count:Show() Nenue@13: count:SetVertexColor(0.6, 0.6, 0.6) Nenue@13: else Nenue@13: count:Hide() Nenue@13: end Nenue@13: rangeTimer = TOOLTIP_UPDATE_TIME Nenue@13: end Nenue@13: Nenue@13: self.rangeTimer = rangeTimer Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: function Veneer_QuestObjectiveItem_UpdateCooldown (itemButton) Nenue@13: local start, duration, enable = GetQuestLogSpecialItemCooldown(itemButton.questLogIndex) Nenue@13: if (start) then Nenue@13: CooldownFrame_SetTimer(itemButton.Cooldown, start, duration, enable) Nenue@13: if (duration > 0 and enable == 0) then Nenue@13: SetItemButtonTextureVertexColor(itemButton, 0.4, 0.4, 0.4) Nenue@13: else Nenue@13: SetItemButtonTextureVertexColor(itemButton, 1, 1, 1) Nenue@13: end Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: ----------------------------------------- Nenue@13: -- Criteria frames Nenue@13: Nenue@13: --[[ Nenue@13: text = description, Nenue@13: type = type, Nenue@13: finished = completed, Nenue@13: quantity = quantity, Nenue@13: requiredQuantity = requiredQuantity, Nenue@13: characterName = characterName, Nenue@13: flags = flags, Nenue@13: assetID = assetID, Nenue@13: quantityString = quantityString, Nenue@13: criteriaID = criteriaID, Nenue@13: ]] Nenue@13: local newWidgetID = 0 Nenue@13: mod.WidgetRegistry = {} Nenue@13: local wr = mod.WidgetRegistry Nenue@13: Nenue@13: --- Get a usable widget for the given achievement criteria set. Nenue@13: -- Returns a frame object with dimensioning parameters needed to size the receiving tracker block Nenue@14: mod.SetWidget = function(line, info, objectiveType, objectiveKey) Nenue@13: local print = B.print('ObjectiveWidgets') Nenue@14: local widgetType = objectiveType Nenue@13: local widget Nenue@14: if wr[widgetType] and wr[widgetType].used[objectiveKey] then Nenue@14: widget = wr[widgetType].used[objectiveKey] Nenue@14: print('|cFF00FF00Updating ('..objectiveKey..')', widget) Nenue@13: elseif not wr[widgetType] or #wr[widgetType].free == 0 then Nenue@13: widget = CreateFrame('Frame', 'VeneerObjective' .. widgetType .. (wr[widgetType] and (wr[widgetType].lastn+1) or (1)), VeneerObjectiveScroll, 'VeneerObjectiveCriteria' .. widgetType) Nenue@13: Nenue@13: print('|cFFFF0088Creating `'..widget:GetName()..'` id', wr[widgetType].lastn) Nenue@13: else Nenue@13: widget = tremove(wr[widgetType].free) Nenue@13: print('|cFFFFFF00Acquiring released widget', widget:GetName()) Nenue@13: end Nenue@13: Nenue@14: Nenue@14: wr[widgetType].used[objectiveKey] = widget Nenue@14: widget.line = line Nenue@14: widget.info = info Nenue@14: widget.key = objectiveKey Nenue@13: mod.InitializeWidget(widget) Nenue@13: return widget Nenue@13: end Nenue@13: Nenue@13: --- WidgetTemplate 'OnLoad' Nenue@13: mod.RegisterWidget = function(frame) Nenue@13: local print = B.print('ObjectiveWidgets') Nenue@13: local widgetType = frame.widgetType Nenue@13: if not wr[frame.widgetType] then Nenue@13: print('|cFFFF4400[[WidgetTemplate]]|r', widgetType) Nenue@13: wr[widgetType] = { lastn = 1, free = {}, used = {}, usedIndex = {}, freeIndex = {} } Nenue@13: else Nenue@13: print('|cFF0088FF+ [[WidgetTemplate]]r', widgetType, wr[widgetType].lastn) Nenue@13: wr[widgetType].lastn = wr[widgetType].lastn + 1 Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: --- WidgetTemplate 'OnShow' Nenue@13: mod.InitializeWidget = setmetatable({}, { Nenue@13: __call = function(t, frame) Nenue@13: -- todo: config pull Nenue@13: Nenue@15: frame:SetWidth(mod.Conf.Wrapper.WrapperWidth - mod.Conf.Style.Format.status.Indent * 2) Nenue@13: frame:SetScript('OnEvent', mod.UpdateWidget[frame.widgetType]) Nenue@13: if frame.info.isCurrency then Nenue@13: frame:RegisterEvent('CHAT_MSG_CURRENCY') Nenue@13: frame:RegisterEvent('CURRENCY_LIST_UPDATE') Nenue@13: end Nenue@13: frame:RegisterEvent('TRACKED_ACHIEVEMENT_UPDATE') Nenue@13: frame:RegisterEvent('TRACKED_ACHIEVEMENT_LIST_CHANGED') Nenue@13: frame:RegisterEvent('CRITERIA_UPDATE') Nenue@13: frame:RegisterEvent('CRITERIA_COMPLETE') Nenue@13: frame:RegisterEvent('CRITERIA_EARNED') Nenue@14: t[frame.widgetType](frame) Nenue@14: mod.UpdateWidget[frame.widgetType](frame) Nenue@13: end, Nenue@13: }) Nenue@13: Nenue@13: --- WidgetTemplate 'OnEvent' Nenue@13: mod.UpdateWidget = setmetatable({}, { Nenue@13: __call = function(t, frame) Nenue@13: if not frame.widgetType then Nenue@13: error('Invalid widget template, needs .widgetType') Nenue@13: return Nenue@13: end Nenue@13: Nenue@13: return t[frame.widgetType](frame) Nenue@13: end Nenue@13: }) Nenue@13: Nenue@13: --- WidgetTemplate 'OnHide' Nenue@13: mod.ReleaseWidget = function(frame) Nenue@13: local print = B.print('ObjectiveWidgets') Nenue@13: local reg = wr[frame.widgetType] Nenue@14: if reg and reg.used[frame.key] then Nenue@14: reg.used[frame.key] = nil Nenue@14: frame.line = nil Nenue@13: frame.info = nil Nenue@13: frame:UnregisterAllEvents() Nenue@13: tinsert(reg.free, frame) Nenue@13: print('|cFFBBBBBBreleased from service', frame:GetName()) Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: --- RemoveTrackedAchievement post-hook Nenue@13: mod.CleanWidgets = function() Nenue@13: local print = B.print('ObjectiveWidgets') Nenue@13: local tracked = {GetTrackedAchievements() } Nenue@14: local tasks = GetTasksTable() Nenue@13: for type, reg in pairs(mod.WidgetRegistry) do Nenue@13: print('collecting', type) Nenue@14: for key, frame in pairs(reg.used) do Nenue@14: if frame.info.cheevID then Nenue@14: local id = frame.info.cheevID Nenue@13: Nenue@14: if id and not tContains(tracked, id) then Nenue@13: Nenue@14: print(' untracked achievement', id, 'associated with', key, frame:GetName()) Nenue@14: frame:Hide() Nenue@14: end Nenue@14: elseif frame.info.questID then Nenue@14: -- do something for quest task Nenue@13: end Nenue@13: end Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: Nenue@14: Nenue@14: mod.defaults.WidgetStyle = { Nenue@13: ProgressBar = { Nenue@14: Spacing = 4, Nenue@13: bg = { Nenue@13: Height = 20, Nenue@13: }, Nenue@13: fg = { Nenue@13: Height = 16, Nenue@13: }, Nenue@13: status = { Nenue@14: FontObject = _G.VeneerCriteriaFontNormal Nenue@13: } Nenue@13: } Nenue@13: } Nenue@13: mod.InitializeWidget.ProgressBar = function(self) Nenue@14: local c = mod.defaults.WidgetStyle.ProgressBar Nenue@14: self.height = c.bg.Height + c.Spacing Nenue@13: self:SetHeight(c.bg.Height) Nenue@13: self.bg:SetHeight(c.bg.Height) Nenue@13: self.fg:ClearAllPoints() Nenue@14: self.indent = (c.bg.Height - c.fg.Height) / 2 Nenue@14: self.fg:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', self.indent, self.indent) Nenue@13: self.fg:SetHeight(c.fg.Height) Nenue@13: self.status:SetFontObject(c.status.FontObject) Nenue@13: self.status:SetText(self.info.quantityString) Nenue@13: end Nenue@13: Nenue@13: mod.UpdateWidget.ProgressBar = function (self) Nenue@14: local quantity, requiredQuantity = self.line.value, self.line.maxValue Nenue@14: print('update vals:') Nenue@14: for k,v in pairs(self.line) do Nenue@14: print(k, v) Nenue@14: end Nenue@13: Nenue@14: if self.line.format then Nenue@14: self.status:SetFormattedText(self.line.format, self.line.value, self.line.maxValue) Nenue@14: end Nenue@14: Nenue@14: Nenue@15: if quantity == 0 then Nenue@15: self.fg:Hide() Nenue@15: elseif quantity >= requiredQuantity then Nenue@14: self.fg:SetWidth(self.bg:GetWidth() - self.indent) Nenue@13: else Nenue@13: self.fg:Show() Nenue@14: self.fg:SetWidth((self.bg:GetWidth() -self.indent) * (quantity / requiredQuantity)) Nenue@13: end Nenue@13: end Nenue@13: Nenue@13: Nenue@13: mod.InitializeWidget.Hidden = function (self) Nenue@13: self.height = 0 Nenue@13: end Nenue@13: mod.UpdateWidget.Hidden = function (self) Nenue@13: self.height= 0 Nenue@13: end