Nenue@30: -- WorldPlan Nenue@30: -- FilterBar.lua Nenue@30: -- Created: 10/27/2016 8:55 PM Nenue@30: -- %file-revision% Nenue@30: -- Nenue@40: local _, db = ... Nenue@30: local print = DEVIAN_WORKSPACE and function(...) _G.print('FilterBar', ...) end or nop Nenue@33: local wprint = DEVIAN_WORKSPACE and function(...) _G.print('WP', ...) end or function() end Nenue@31: local wipe, ipairs, pairs = table.wipe, ipairs, pairs Nenue@30: Nenue@30: local REWARD_CASH = WORLD_QUEST_REWARD_TYPE_FLAG_GOLD Nenue@30: local REWARD_ARTIFACT_POWER = WORLD_QUEST_REWARD_TYPE_FLAG_ARTIFACT_POWER Nenue@30: local REWARD_GEAR = WORLD_QUEST_REWARD_TYPE_FLAG_EQUIPMENT Nenue@30: local REWARD_CURRENCY = WORLD_QUEST_REWARD_TYPE_FLAG_ORDER_RESOURCES Nenue@30: local REWARD_REAGENT = WORLD_QUEST_REWARD_TYPE_FLAG_MATERIALS Nenue@30: Nenue@30: Nenue@30: local LE_QUEST_TAG_TYPE_PVP = LE_QUEST_TAG_TYPE_PVP Nenue@30: local LE_QUEST_TAG_TYPE_PET_BATTLE = LE_QUEST_TAG_TYPE_PET_BATTLE Nenue@30: local LE_QUEST_TAG_TYPE_DUNGEON = LE_QUEST_TAG_TYPE_DUNGEON Nenue@30: local LE_QUEST_TAG_TYPE_PROFESSION = LE_QUEST_TAG_TYPE_PROFESSION Nenue@33: Nenue@33: local familiars = { Nenue@33: [42159] = {npc = 106552, name = 'Nightwatcher Merayl'}, Nenue@33: [40277] = {npc = 97804, name = 'Tiffany Nelson'}, Nenue@33: [40298] = {npc = 99182, name = 'Sir Galveston'}, Nenue@33: [40282] = {npc= 99150, name = 'Grixis Tinypop'}, Nenue@33: [40278] = {npc = 98270, name = 'Robert Craig'}, Nenue@33: [48195] = {npc = 105250, name = 'Aulier'}, Nenue@33: [41990] = {npc = 105674, name = 'Varenne'}, Nenue@33: [41860] = {npc = 104970, name = 'Xorvasc'}, Nenue@33: [40299] = {npc = 99210, name = 'Bodhi Sunwayver'}, Nenue@33: [42442] = {npc = 107489, name = 'Amalia'}, Nenue@33: [40280] = {npc = 99077, name = 'Bredda Tenderhide'}, Nenue@33: [41687] = {npc = 104553, name = 'Odrogg'}, Nenue@33: [41944] = {npc = 105455, name = 'Trapper Jarrun'}, Nenue@33: [40337] = {npc = 97709, name = 'Master Tamer Flummox'}, Nenue@33: [40279] = {npc = 99035, name = 'Durian Strongfruit'} Nenue@33: } Nenue@33: local familiars_id = 9696 Nenue@33: Nenue@40: db.DefaultFilterType = { Nenue@36: iconWidth = 24, Nenue@40: iconHeight = 18, Nenue@36: borderWidth = 3, Nenue@36: highlightWidth = 2, Nenue@30: TagSize = 12, Nenue@30: TimeleftStage = 3, Nenue@30: showNumber = true, Nenue@30: numberFontObject = 'WorldPlanNumberFontThin' Nenue@30: } Nenue@40: db.DefaultFilters = { Nenue@30: { label = 'Filters', texture = "Interface\\WorldMap\\WorldMap-Icon" }, Nenue@30: { filterKey= 'rewardType', cVar = 'worldQuestFilterArtifactPower', filterValue = REWARD_ARTIFACT_POWER, label = 'Artifact Power', texture = "Interface\\ICONS\\inv_7xp_inscription_talenttome01" }, Nenue@31: { filterKey= 'rewardType', cVar = 'worldQuestFilterOrderResources', filterValue = REWARD_CURRENCY,label = 'Order Resources', texture = "Interface\\Icons\\inv_orderhall_orderresources" }, Nenue@30: { filterKey= 'rewardType', cVar = 'worldQuestFilterEquipment', filterValue = REWARD_GEAR, label = 'Equipment', texture = "Interface\\ICONS\\garrison_bluearmorupgrade" }, Nenue@30: { filterKey= 'rewardType', cVar = 'worldQuestFilterProfessionMaterials', filterValue = REWARD_REAGENT, label = 'Materials', texture = 1417744 }, Nenue@30: { filterKey= 'rewardType', cVar = 'worldQuestFilterGold', filterValue = REWARD_CASH, label = 'Gold', texture = "Interface\\Buttons\\UI-GroupLoot-Coin-Up" }, Nenue@30: { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PVP, label = 'PvP', texture = "Interface\\Icons\\Ability_PVP_GladiatorMedallion", spacing = 10 }, Nenue@30: { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PET_BATTLE, label = 'Pet Battle', texture = "Interface\\Icons\\PetJournalPortrait", }, Nenue@30: { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_DUNGEON, label = 'Dungeon', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", }, Nenue@30: { filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\ICONS\\70_professions_scroll_02", }, Nenue@30: } Nenue@30: local defaults = {} Nenue@30: Nenue@40: WorldPlanSummaryMixin = WorldPlanSummaryMixin or {} Nenue@41: local Module = WorldPlanSummaryMixin Nenue@41: Module.selectedBountyIndex = {} Nenue@41: Module.bounties = {} Nenue@41: Module.filterList = {} Nenue@41: Module.buttons = {} Nenue@41: Module.cvarFiltersDirty = false Nenue@30: WorldPlanFilterPinMixin = {} Nenue@41: local Pin = WorldPlanFilterPinMixin Nenue@30: Nenue@41: function Module:OnLoad() Nenue@45: self:SetParent(WorldMapFrame.UIElementsFrame) Nenue@45: self:ClearAllPoints() Nenue@45: self:SetPoint('TOPRIGHT') Nenue@40: WorldPlan:AddHandler(self) Nenue@40: for index, info in ipairs(db.DefaultFilters) do Nenue@40: info.zone = db.DefaultFilterType Nenue@40: info.continent = db.DefaultFilterType Nenue@30: info.pinMask = "Interface\\Minimap\\UI-Minimap-Background" Nenue@30: WorldPlan:AddTypeInfo(self,index, info) Nenue@30: end Nenue@30: end Nenue@30: Nenue@30: Nenue@57: function Module:OnEvent(event, arg) Nenue@33: print('|cFF00FF88'..self:GetName()..':OnEvent()', event) Nenue@57: if (event == 'QUEST_LOG_UPDATE') and arg then Nenue@57: if db.QuestsByID[arg] then Nenue@57: if db.QuestsByID[arg].factionID then Nenue@57: Nenue@57: end Nenue@57: end Nenue@57: end Nenue@57: Nenue@33: self.isStale = true Nenue@30: end Nenue@30: Nenue@30: local bountyIndex Nenue@30: local debug_headers = {} Nenue@30: Nenue@41: function Module:Setup() Nenue@33: print('|cFF00FF88'..self:GetName()..':Setup()') Nenue@45: self.isStale = true Nenue@30: end Nenue@30: Nenue@30: Nenue@41: function Module:OnUpdate() Nenue@33: if self.isStale then Nenue@33: wprint('|cFF00FF00pushing update') Nenue@33: self:Refresh() Nenue@33: end Nenue@30: end Nenue@33: Nenue@41: function Module:OnMapInfo(isBrokenIsle, mapAreaID) Nenue@41: if not isBrokenIsle then Nenue@41: self:SetShown(false) Nenue@41: else Nenue@41: self:SetShown(true) Nenue@41: self:Refresh() Nenue@41: end Nenue@41: end Nenue@41: Nenue@41: function Module:OnShow() Nenue@33: print('|cFF00FF88'..self:GetName()..':OnShow()') Nenue@32: if self.isStale then Nenue@32: self:Refresh() Nenue@32: end Nenue@32: end Nenue@30: Nenue@41: local tinsert, GetQuestBountyInfoForMapID, GetQuestLogTitle, GetQuestLogIndexByID = tinsert, GetQuestBountyInfoForMapID, GetQuestLogTitle, GetQuestLogIndexByID Nenue@41: function Module:GetFilters() Nenue@30: Nenue@33: print('|cFF00FFFF'..self:GetName()..':GetFilters()') Nenue@30: Nenue@30: wipe(self.filterList) Nenue@30: Nenue@40: for index, info in ipairs(db.DefaultFilters) do Nenue@30: tinsert(self.filterList, info) Nenue@30: end Nenue@40: self.bounties, self.numBounties = GetQuestBountyInfoForMapID(db.currentMapID) Nenue@30: self.BountyFilters = {} Nenue@30: for index, data in ipairs(self.bounties) do Nenue@30: local info = self.BountyFilters[index] Nenue@30: if not info then Nenue@30: info = {} Nenue@30: self.BountyFilters[index] = info Nenue@30: end Nenue@30: Nenue@30: local questTitle = GetQuestLogTitle(GetQuestLogIndexByID(data.questID)) Nenue@30: Nenue@30: info.filterKey = 'factionID' Nenue@30: info.filterValue = data.factionID Nenue@30: info.label = questTitle Nenue@30: info.texture = data.icon Nenue@30: print('loading emissary', questTitle) Nenue@30: Nenue@30: tinsert(self.filterList, info) Nenue@30: --{ filterKey= 'worldQuestType', filterValue = LE_QUEST_TAG_TYPE_PROFESSION, label = 'Profession', texture = "Interface\\LFGFRAME\\UI-LFR-PORTRAIT", }, Nenue@30: end Nenue@30: end Nenue@30: Nenue@41: function Module:Reset() Nenue@30: self.pinLayout = self:GetTypeInfo(255) Nenue@30: self:GetFilters() Nenue@30: end Nenue@30: Nenue@41: function Module:Refresh() Nenue@40: self:GetFilters() Nenue@33: self:Update() Nenue@30: end Nenue@30: Nenue@30: local filterFill = "Interface\\BUTTONS\\YELLOWORANGE64" Nenue@30: local filterMask = "Interface\\Minimap\\UI-Minimap-Background" Nenue@31: Nenue@31: local questResults = {{}} Nenue@41: function Module:Update() Nenue@30: local blocks = self.buttons Nenue@40: Nenue@45: local relativeFrame = self Nenue@40: Nenue@40: local numHeaders = 0 Nenue@33: print('|cFF00FF88'..self:GetName()..':Update()|r', 'currentMap=',WorldPlan.currentMapID) Nenue@30: Nenue@40: Nenue@40: local layout = db.DefaultFilterType Nenue@36: local borderWidth = layout.iconWidth + (layout.borderWidth * 2) Nenue@36: local highlightWidth = borderWidth + (layout.highlightWidth * 2) Nenue@40: local mapQuests = db.QuestsByZone[db.currentMapID] or db.QuestsByID Nenue@57: local firstCvar, lastCvar Nenue@30: for index, info in ipairs(self.filterList) do Nenue@40: local numQuestsHere = 0 Nenue@40: local numQuestsTotal = 0 Nenue@40: info.questList = info.questList or {} Nenue@40: wipe(info.questList) Nenue@40: Nenue@40: for questID, pin in pairs(db.QuestsByID) do Nenue@45: --print(pin.worldQuestType ~= LE_QUEST_TAG_TYPE_PROFESSION, (db.Config.ShowAllProfessionQuests or pin.isKnownProfession)) Nenue@40: if (pin.worldQuestType ~= LE_QUEST_TAG_TYPE_PROFESSION) or (db.Config.ShowAllProfessionQuests or pin.isKnownProfession) then Nenue@45: --print(pin.title) Nenue@30: if not info.filterKey then Nenue@40: if mapQuests[questID] then Nenue@40: numQuestsHere = numQuestsHere + 1 Nenue@40: end Nenue@40: numQuestsTotal = numQuestsTotal + 1 Nenue@30: elseif pin[info.filterKey] == info.filterValue then Nenue@40: if mapQuests[questID] then Nenue@40: numQuestsHere = numQuestsHere + 1 Nenue@40: tinsert(info.questList, pin) Nenue@40: end Nenue@40: numQuestsTotal = numQuestsTotal + 1 Nenue@30: end Nenue@30: end Nenue@30: end Nenue@40: --print('num here', numQuestsHere, numQuestsTotal) Nenue@40: info.totalQuests = maxQuests Nenue@30: Nenue@40: --print(tostring(index).. ' ("'..tostring(info.label)..'" f('.. tostring(info.filterKey).. '='..tostring(info.filterValue) .. '), '..tostring(numQuests)..')') Nenue@40: Nenue@40: if numQuestsTotal >= 1 then Nenue@30: numHeaders = numHeaders + 1 Nenue@30: local button = blocks[numHeaders] Nenue@30: if not blocks[numHeaders] then Nenue@40: button = CreateFrame('Button', 'WorldPlanFilterButton'..numHeaders, self, 'WorldPlanFilterPin') Nenue@40: button:SetSize(32,20) Nenue@40: button.icon:SetTexCoord(0.1,.9,.1,(1 * (20/32))) Nenue@30: Nenue@40: button.RewardBorder:ClearAllPoints() Nenue@40: button.RewardBorder:SetPoint('TOPLEFT', button, 'TOPLEFT') Nenue@40: button.RewardBorder:SetPoint('BOTTOMRIGHT', button, 'BOTTOMRIGHT') Nenue@30: Nenue@40: Nenue@30: blocks[numHeaders] = button Nenue@30: end Nenue@30: Nenue@30: button.info = info Nenue@40: button.numQuestsTotal = numQuestsTotal Nenue@40: button.numQuestsHere = numQuestsHere Nenue@40: button.questList = info.questList Nenue@40: button.isFirst = (numHeaders == 1) Nenue@30: button:SetID(index) Nenue@40: button.spacing = ((relativeFrame.cVar and (not info.cVar)) or (relativeFrame.filterKey ~= info.filterKey)) and 5 or 1 Nenue@30: button.relativeFrame = relativeFrame Nenue@40: button:Refresh() Nenue@30: button:Show() Nenue@30: relativeFrame = button Nenue@40: Nenue@40: if info.cVar then Nenue@40: firstCvar = firstCvar or button Nenue@40: lastCvar = button Nenue@40: end Nenue@40: Nenue@30: end Nenue@30: end Nenue@30: Nenue@30: self.numHeaders = numHeaders Nenue@30: for i = numHeaders + 1, #blocks do Nenue@30: if blocks[i] then Nenue@30: blocks[i]:Hide() Nenue@57: wipe(blocks[i].questList) Nenue@31: end Nenue@30: end Nenue@40: Nenue@40: Nenue@40: Nenue@32: self.isStale = nil Nenue@30: end Nenue@30: Nenue@41: function Module:Cleanup() Nenue@30: -- hide trailing buttons Nenue@30: end Nenue@30: Nenue@31: local rgbWhite = {r = 1, g= 1, b= 1, hex = '|cFFFFFFFF'} Nenue@41: function Pin:OnEnter() Nenue@40: if #self.questList >= 1 then Nenue@31: GameTooltip:SetOwner(self, 'ANCHOR_LEFT') Nenue@31: GameTooltip:AddLine(self.info.label) Nenue@31: for index, pin in ipairs(self.questList) do Nenue@31: local colorInfo = (pin.quality and ITEM_QUALITY_COLORS[pin.quality]) or rgbWhite Nenue@40: GameTooltip:AddLine('|T'.. tostring(pin.itemTexture)..':16:16|t ' .. tostring(pin.title) ..(pin.cheevos and " |cFFFFFF00!|R" or ''), colorInfo.r, colorInfo.g, colorInfo.b) Nenue@31: end Nenue@40: GameTooltip:AddLine(self.numQuestsTotal .. ' total') Nenue@36: GameTooltip:Show() Nenue@31: end Nenue@30: end Nenue@30: Nenue@41: function Pin:OnLeave() Nenue@31: if GameTooltip:IsOwned(self) then Nenue@31: GameTooltip:Hide() Nenue@31: end Nenue@31: end Nenue@30: Nenue@41: function Pin:Refresh() Nenue@30: local info = self.info Nenue@30: self.filterKey = info.filterKey Nenue@30: self.filterValue = info.filterValue Nenue@30: self.tagID = info.tagID Nenue@30: Nenue@30: self.icon:SetTexture(info.texture) Nenue@40: self.count:SetText(self.numQuestsHere) Nenue@30: self.cVar = info.cVar Nenue@30: Nenue@30: self.itemTexture = self.texture Nenue@30: Nenue@45: self:ClearAllPoints() Nenue@40: if self.isFirst then Nenue@45: self:SetPoint('TOPRIGHT', self.relativeFrame, 'TOPRIGHT', -5, -42) Nenue@30: else Nenue@45: self:SetPoint('TOPLEFT', self.relativeFrame, 'BOTTOMLEFT', 0, -(self.spacing or 0)) Nenue@30: end Nenue@45: print('anchor', self.relativeFrame:IsShown(), self:GetPoint(1)) Nenue@30: Nenue@40: self.icon:SetDesaturated(self.numQuestsHere == 0) Nenue@40: Nenue@40: local r, g, b, a = 0,0,0,1 Nenue@31: local desaturated = false Nenue@40: if (self.numQuestsHere > 0) then Nenue@40: if self.cVar then Nenue@40: if GetCVarBool(self.cVar) then Nenue@40: self.count:SetTextColor(1,1,1) Nenue@41: r,g,b,a = 0, 0, 0, 1 Nenue@31: else Nenue@40: self:GetParent().cvarFiltersDirty = true Nenue@40: self.count:SetTextColor(1,0,0) Nenue@40: self.icon:SetDesaturated(true) Nenue@41: r,g,b,a = 1, 0, 0, 0.5 Nenue@31: end Nenue@31: else Nenue@40: if db.UsedFilters[self.filterKey] then Nenue@40: if db.UsedFilters[self.filterKey] == self.filterValue then Nenue@40: self.count:SetTextColor(0,1,0) Nenue@41: r, g, b = 0, 1, 0 Nenue@40: else Nenue@40: self.count:SetTextColor(1,0,0) Nenue@40: r, g, b = 1, 0, 0 Nenue@40: end Nenue@36: else Nenue@36: Nenue@40: self.count:SetTextColor(1,1,1) Nenue@40: if self.filterKey == 'worldQuestType' then Nenue@40: r, g, b = 0, 0, 1 Nenue@40: elseif self.filterKey == 'factionID' then Nenue@40: r, g, b = 1, 1, 0 Nenue@40: end Nenue@36: end Nenue@30: end Nenue@30: end Nenue@41: self.RewardBorder:SetColorTexture(r, g, b) Nenue@41: self:SetAlpha(a) Nenue@31: Nenue@30: --self:UpdateSize() Nenue@30: end Nenue@30: Nenue@41: function Pin:OnLoad() Nenue@30: self:RegisterForClicks('AnyUp') Nenue@30: self:SetFrameStrata('HIGH') Nenue@30: self:SetFrameLevel(151) Nenue@30: self:SetScript('OnUpdate', nil) Nenue@40: self.questList = {} Nenue@41: -- WORLD_MAP_UPDATE and PLAYER_ENTERING_WORLD are passed down from a higher level Nenue@30: end Nenue@30: Nenue@41: function Pin:OnUpdate () Nenue@30: end Nenue@30: Nenue@30: -- shift-click: reset filter Nenue@30: -- click: rotate through include(1), exclude(-1), ignore(nil) Nenue@36: local filtered_report = {} Nenue@40: local RESET_FILTER = "|cFFFFFFFF+%s|r" Nenue@40: local FILTER_EXCLUDE_TYPE = '|cFFFF0000-%s|r' Nenue@40: local FILTER_INCLUDE_TYPE = '|cFF00FF00+%s|r' Nenue@41: function Pin:OnClick (button) Nenue@30: Nenue@30: local filterKey = self.filterKey Nenue@30: local filterValue = self.filterValue Nenue@36: local cVar = self.cVar Nenue@36: local parent = self:GetParent() Nenue@40: local setDirty Nenue@40: Nenue@40: print('|cFF00FF88'..self:GetName()..':OnClick()|r', filterKey, filterValue, cVar, parent) Nenue@30: Nenue@36: local resetMode = (button == 'RightButton') Nenue@36: wipe(filtered_report) Nenue@36: if not (filterKey or cVar) then Nenue@40: for i, info in ipairs(db.DefaultFilters) do Nenue@33: if info.cVar then Nenue@40: SetCVar(info.cVar, 1) Nenue@40: elseif info.filterKey then Nenue@40: if db.UsedFilters[info.filterKey] then Nenue@40: db.UsedFilters[info.filterKey] = nil Nenue@36: end Nenue@33: end Nenue@33: end Nenue@40: parent.cvarFiltersDirty = false Nenue@33: Nenue@40: --WorldPlan:print('All filters reset.') Nenue@36: elseif cVar then Nenue@40: if resetMode then Nenue@40: print('|cFFFF4400cleaning dirty') Nenue@40: for i, info in ipairs(db.DefaultFilters) do Nenue@33: if info.cVar then Nenue@40: parent.cvarFiltersDirty = false Nenue@40: SetCVar(info.cVar, 1) Nenue@33: end Nenue@33: end Nenue@40: --WorldPlan:print('Reward filters reset.') Nenue@40: elseif parent.cvarFiltersDirty == true then Nenue@40: if GetCVarBool(cVar) then Nenue@40: tinsert(filtered_report, FILTER_EXCLUDE_TYPE:format(tostring(self.info.label))) Nenue@40: SetCVar(cVar, 0) Nenue@40: else Nenue@40: Nenue@40: tinsert(filtered_report, FILTER_INCLUDE_TYPE:format(tostring(self.info.label))) Nenue@40: SetCVar(cVar, 1) Nenue@40: end Nenue@40: Nenue@40: -- check the visible filters and consider it clean if they're all lit Nenue@40: parent.cvarFiltersDirty = false Nenue@40: for i, info in ipairs(parent.filterList) do Nenue@40: if info.cVar and (#info.questList >= 1) then Nenue@40: print(info.cVar, GetCVarBool(info.cVar)) Nenue@40: if GetCVarBool(info.cVar) == false then Nenue@40: parent.cvarFiltersDirty = true Nenue@40: print('|cFFFF4400still dirty') Nenue@40: break Nenue@40: end Nenue@40: end Nenue@36: end Nenue@36: else Nenue@40: print('|cFFFF4400making dirty') Nenue@40: for i, info in ipairs(db.DefaultFilters) do Nenue@40: if info.cVar then Nenue@40: local msgType = (cVar == info.cVar) and FILTER_INCLUDE_TYPE or FILTER_EXCLUDE_TYPE Nenue@40: SetCVar(info.cVar, ((cVar == info.cVar) and 1) or 0) Nenue@40: tinsert(filtered_report, msgType:format(info.label)) Nenue@40: end Nenue@40: end Nenue@40: parent.cvarFiltersDirty = true Nenue@36: end Nenue@30: else Nenue@40: if resetMode then Nenue@40: wipe(db.UsedFilters) Nenue@40: --WorldPlan:print('Type filters reset.') Nenue@31: else Nenue@40: if (db.UsedFilters[filterKey] == filterValue) or resetMode then Nenue@40: db.UsedFilters[filterKey] = nil Nenue@40: tinsert(filtered_report, FILTER_INCLUDE_TYPE:format(tostring(filterKey))) Nenue@40: else Nenue@40: db.UsedFilters[filterKey] = filterValue Nenue@40: tinsert(filtered_report, FILTER_EXCLUDE_TYPE:format(tostring(filterKey))) Nenue@40: end Nenue@30: end Nenue@30: end Nenue@40: if #filtered_report >= 1 then Nenue@40: --WorldPlan:print('Setting filter(s):', table.concat(filtered_report, ', ')) Nenue@40: end Nenue@33: WorldPlan:Refresh(true) Nenue@30: end