local L = BtWQuests.L; BTWQUESTS_VIEW_ALL = L["BTWQUESTS_VIEW_ALL"]; local min = math.min; local max = math.max; local floor = math.floor; local ceil = math.ceil; local CHAIN_GRID_HORIZONTAL_SIZE = 95; local CHAIN_GRID_VERTICAL_SIZE = 80; local CHAIN_GRID_HORIZONTAL_PADDING = 99; local CHAIN_GRID_VERTICAL_PADDING = 52 + (CHAIN_GRID_VERTICAL_SIZE * 2); --@REMOVE AFTER 9.0 local GetLogIndexForQuestID = C_QuestLog.GetLogIndexForQuestID local IsQuestComplete = C_QuestLog.IsComplete local IsQuestFailed = C_QuestLog.IsFailed if select(4, GetBuildInfo()) < 90000 then GetLogIndexForQuestID = GetQuestLogIndexByID function IsQuestComplete(questLogIndex) local complete = select(6, GetQuestLogTitle(questLogIndex)) return complete and complete > 0 end function IsQuestFailed(questLogIndex) local complete = select(6, GetQuestLogTitle(questLogIndex)) return complete and complete < 0 end end -- [[ Chain ]] function BtWQuestsChainItemPool_HideAndClearAnchors(framePool, frame) FramePool_HideAndClearAnchors(framePool, frame) frame.linePool:ReleaseAll() frame.IsNextAnim:Stop() frame.previousButtons = nil frame.status = nil end BtWQuestsExpansionItemMixin = {} BtWQuestsChainItemMixin = {} function BtWQuestsChainItemMixin:OnLoad() self.linePool = CreateFramePool("FRAME", self:GetParent(), "BtWQuestsLineTemplate"); self.Name:SetText("Quest Name") self.Tick:SetShown(false) self.tooltip = BtWQuestsTooltip end function BtWQuestsChainItemMixin:SetHideSpoilers(value) self.hideSpoilers = value end function BtWQuestsChainItemMixin:GetHideSpoilers() return self.hideSpoilers end function BtWQuestsChainItemMixin:Set(item, character) self.item = item self.character = character; self:StopAnimating() local status = item:GetStatus(character) self.Name:SetText(item:GetName(character)) self.Name:SetShown(not self.hideSpoilers or status ~= nil) self.SpoilerName:SetShown(not self.Name:IsShown()) local tagID = item:GetTagID() local difficulty = item:GetDifficulty() if tagID and QUEST_TAG_TCOORDS[tagID] then self.TagTexture:SetTexCoord(unpack(QUEST_TAG_TCOORDS[tagID])) self.TagTexture:Show() if difficulty then self.TagTexture:SetPoint("BOTTOMRIGHT", -10, 6) else self.TagTexture:SetPoint("BOTTOMRIGHT", -10, 16) end else self.TagTexture:Hide() end self.HeroicTexture:SetShown(difficulty == "heroic" or difficulty == "normal" or difficulty == "lfr") self.MythicTexture:SetShown(difficulty == "mythic") local atlas = item.GetAtlas and item:GetAtlas() if atlas ~= nil then self.Icon:SetAtlas(atlas) end if status == "complete" then self.ForgottenAnimQuick:Play() -- Just setting the alpha doesnt always work, using a animation with a very short duration seems to solve this else self.Name:SetAlpha(1) end if status == "active" then self.ActiveTexture:Show() self.ActiveAnim:Play() else self.ActiveTexture:Hide() end self.Tick:SetShown(status == "complete") self:SetShown(item:Visible(character)) self.status = status end function BtWQuestsChainItemMixin:Update(item) self.item = item local character = self.character; local status = item:GetStatus(character) self:StopAnimating() self.Name:SetText(item:GetName(character)) if not self.hideSpoilers or status ~= nil then self.Name:SetShown(true) self.SpoilerName:SetShown(false) end if self.status ~= status then if status == "complete" then self.ForgottenAnim:Play() end if status == "active" then self.ActiveTexture:Show() self.ActiveAnim:Play() else self.ActiveTexture:Hide() end end self.Tick:SetShown(status == "complete") self:SetShown(item:Visible(character)) self.status = status end function BtWQuestsChainItemMixin:SetChainView(value) self.chainView = value end function BtWQuestsChainItemMixin:GetChainView() return self.chainView end function BtWQuestsChainItemMixin:SetTooltip(value) self.tooltip = value end function BtWQuestsChainItemMixin:GetTooltip() return self.tooltip end function BtWQuestsChainItemMixin:OnClick() if self.item then return self.item:OnClick(self.character, self, self:GetChainView(), self:GetTooltip()) end end function BtWQuestsChainItemMixin:OnEnter() if not self.hideSpoilers or self.status ~= nil then if self.item then return self.item:OnEnter(self.character, self, self:GetChainView(), self:GetTooltip()) end end end function BtWQuestsChainItemMixin:OnLeave() if self.item then return self.item:OnLeave(self.character, self, self:GetChainView(), self:GetTooltip()) end end BtWQuestsCategoryHeaderMixin = {} function BtWQuestsCategoryHeaderMixin:Set(item, character) self.item = item self.Name:SetText(item:GetName()) self.id = item:GetID(); end BtWQuestsCategoryItemMixin = {} function BtWQuestsCategoryItemMixin:Set(item, character) self.item = item self.character = character; self.Name:SetText(item:GetName(character)) if item:GetType() == "chain" and character:IsChainIgnored(item:GetID()) then self.Name:SetAlpha(0.5) elseif item:GetType() == "category" and character:IsCategoryIgnored(item:GetID()) then self.Name:SetAlpha(0.5) else self.Name:SetAlpha(1) end local texture, left, right, top, bottom = item:GetButtonImage() self.Background:SetTexture(texture) if left ~= nil then self.Background:SetTexCoord(left, right, top, bottom) else self.Background:SetTexCoord(0.01953125, 0.66015625, 0.0390625, 0.7109375) end self.Acive:SetShown(item:IsActive(character)) self.Tick:SetShown(item:IsCompleted(character)) self.Major:SetShown(item:IsMajor()) self.id = item:GetID(); end function BtWQuestsCategoryItemMixin:OnClick() return self.item:OnClick(self.character, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip) end function BtWQuestsCategoryItemMixin:OnEnter() return self.item:OnEnter(self.character, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip) end function BtWQuestsCategoryItemMixin:OnLeave() return self.item:OnLeave(self.character, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip) end function BtWQuestsCategoryItemMixin:OnMouseUp(button) if button == "RightButton" then BtWQuestsFrame:ZoomOut() end end BtWQuestsCategoryListItemMixin = Mixin({}, BtWQuestsCategoryItemMixin) function BtWQuestsCategoryListItemMixin:Set(item, character) self.item = item self.character = character; local subtext = item:GetSubtext(character) self.Name:SetText(item:GetName(character)) self.Subtext:SetText(subtext) self.Name:ClearAllPoints() if subtext == nil then self.Name:SetPoint("LEFT", 60, 0) else self.Name:SetPoint("TOPLEFT", 60, -13) end if item:GetType() == "chain" and character:IsChainIgnored(item:GetID()) then self.Name:SetAlpha(0.5) elseif item:GetType() == "category" and character:IsCategoryIgnored(item:GetID()) then self.Name:SetAlpha(0.5) else self.Name:SetAlpha(1) end local texture, left, right, top, bottom = item:GetListImage() if texture ~= nil then self.Background:SetTexture(texture) self.Background:SetTexCoord(left, right, top, bottom) else self.Background:SetTexture("Interface\\Addons\\BtWQuests\\UI-CategoryButton") self.Background:SetTexCoord(0.0, 0.7353515625, 0.3515625, 0.46875) end self.Acive:SetShown(item:IsActive(character)) self.Tick:SetShown(item:IsCompleted(character)) self.Major:SetShown(item:IsMajor()) self.Major:SetAlpha(1) self.id = item:GetID(); end function BtWQuestsCategoryListItemMixin:OnEnter() BtWQuestsCategoryItemMixin.OnEnter(self) self.Ignore.texture:SetAlpha(0.75) end function BtWQuestsCategoryListItemMixin:OnLeave() BtWQuestsCategoryItemMixin.OnLeave(self) self.Ignore.texture:SetAlpha(0.0) end BtWQuestsCategoryGridItemMixin = Mixin({}, BtWQuestsCategoryItemMixin) function BtWQuestsCategoryGridItemMixin:OnEnter() BtWQuestsCategoryItemMixin.OnEnter(self) self.Major:SetAlpha(0) self.Ignore.texture:SetAlpha(0.75) end function BtWQuestsCategoryGridItemMixin:OnLeave() BtWQuestsCategoryItemMixin.OnLeave(self) self.Major:SetAlpha(1) self.Ignore.texture:SetAlpha(0.0) end BtWQuestsChainViewItemMixin = {} function BtWQuestsChainViewItemMixin:OnLoad() BtWQuestsChainItemMixin.OnLoad(self) self:RegisterForDrag("LeftButton") end function BtWQuestsChainViewItemMixin:GetChainView() return self:GetParent():GetParent() end function BtWQuestsChainViewItemMixin:GetTooltip() return self:GetChainView():GetTooltip() end function BtWQuestsChainViewItemMixin:OnDragStart() self:GetChainView():OnDragStart() end function BtWQuestsChainViewItemMixin:OnDragStop() self:GetChainView():OnDragStop() end function BtWQuestsChainViewItemMixin:OnMouseUp(button) if button == "RightButton" then BtWQuestsFrame:ZoomOut() end end BtWQuestsChainViewMixin = {} function BtWQuestsChainViewMixin:OnLoad() ScrollFrame_OnLoad(self) self.itemPool = CreateFramePool("BUTTON", self.Child, "BtWQuestsChainViewItemTemplate", BtWQuestsChainItemPool_HideAndClearAnchors); self:RegisterForDrag("LeftButton") end function BtWQuestsChainViewMixin:OnDragStart() self.scrollX, self.scrollY = self:GetHorizontalScroll(), self:GetVerticalScroll() self.mouseX, self.mouseY = GetCursorPosition() local scale = self:GetScrollChild():GetEffectiveScale() self.mouseX, self.mouseY = self.mouseX / scale, self.mouseY / scale self:SetScript("OnUpdate", BtWQuestsChainViewMixin.OnDrag) end function BtWQuestsChainViewMixin:OnDragStop() self:SetScript("OnUpdate", nil) end function BtWQuestsChainViewMixin:OnDrag() local mouseX, mouseY = GetCursorPosition() local scale = self:GetEffectiveScale() mouseX, mouseY = mouseX / scale, mouseY / scale local maxXScroll, maxYScroll = self:GetHorizontalScrollRange(), self:GetVerticalScrollRange() mouseX = min(max(mouseX - self.mouseX + self.scrollX, 0), maxXScroll) mouseY = min(max(mouseY - self.mouseY + self.scrollY, 0), maxYScroll) self:SetHorizontalScroll(mouseX) self:SetVerticalScroll(mouseY) end function BtWQuestsChainViewMixin:GetZoom() return 1 -- return self:GetScrollChild():GetScale() end function BtWQuestsChainViewMixin:SetZoom(value) -- return self:GetScrollChild():SetScale(value) end function BtWQuestsChainViewMixin:SetCharacter(name, realm) if type(name) == "string" then if realm ~= nil then name = name .. "-" .. realm end self.Character = BtWQuestsCharacters:GetCharacter(name) else self.Character = name end end function BtWQuestsChainViewMixin:GetCharacter() return self.Character end function BtWQuestsChainViewMixin:GetTooltip() return BtWQuestsTooltip end function BtWQuestsChainViewMixin:SetHideSpoilers(value) self.hideSpoilers = value end function BtWQuestsChainViewMixin:GetHideSpoilers() return self.hideSpoilers end function BtWQuestsChainViewMixin:SelectFromLink(...) -- return self:GetParent():GetParent():SelectFromLink(...) end function BtWQuestsChainViewMixin:SetChain(chainID, scrollTo, zoom) self.chainID = chainID self.itemPool:ReleaseAll() self.ItemButtons = {} self.rect = {}; self.scrollTo = scrollTo self.scrollToButton = nil self.scrollToButtonAside = nil self.lowestButton = nil self.lowestY = nil if zoom ~= nil then self:SetZoom(zoom) end self:AddButtons(chainID, 0, 0) do local Child = self:GetScrollChild(); local rect = self.rect; rect.left, rect.right = floor(rect.left or 0), ceil(rect.right or 0) rect.top, rect.bottom = floor(rect.top or 0), ceil(rect.bottom or 0) rect.top = max(rect.top, 0) local width = rect.right - rect.left; local height = (rect.bottom - rect.top); if width % 2 == 1 then if rect.left % 2 == 1 then rect.left = rect.left - 1; elseif rect.right % 2 == 1 then rect.right = rect.right + 1; end width = rect.right - rect.left; end while width < 6 do rect.left = rect.left - 1; rect.right = rect.right + 1; width = rect.right - rect.left; end if rect.left < 0 or rect.top > 0 then local hShift = -(rect.left) * CHAIN_GRID_HORIZONTAL_SIZE; local vShift = rect.top * CHAIN_GRID_VERTICAL_SIZE; for itemButton in self.itemPool:EnumerateActive() do local x, y = select(4, itemButton:GetPoint(1)); -- CENTER - Can no longer look up point by name itemButton:SetPoint( "CENTER", itemButton:GetParent(), "TOPLEFT", x + hShift, y + vShift ); end end Child:SetWidth(width * CHAIN_GRID_HORIZONTAL_SIZE + (CHAIN_GRID_HORIZONTAL_PADDING * 2)); Child:SetHeight(height * CHAIN_GRID_VERTICAL_SIZE + (CHAIN_GRID_VERTICAL_PADDING * 2)); end self:UpdateScrollChildRect() if type(scrollTo) == "table" and scrollTo.type == "coords" then local scale = self:GetZoom() -- self:SetHorizontalScroll(scrollTo.x / scale) self:SetVerticalScroll(scrollTo.y / scale) elseif scrollTo ~= false then if self.scrollToButton == nil then self.scrollToButton = self.scrollToButtonAside end -- if self.scrollToButton == nil then -- local buttons = self.ItemButtons[chainID] -- local index = 1 -- while buttons[index] and not buttons[index]:IsShown() do -- index = index + 1 -- end -- self.scrollToButton = buttons[index] -- end if self.scrollToButton then local scale = self:GetZoom() local x, y = select(4, self.scrollToButton:GetPoint(1)); -- CENTER - Can no longer look up point by name -- self:SetHorizontalScroll(x - (self:GetWidth() / scale) / 2) self:SetVerticalScroll(-y - (self:GetHeight() / scale) / 2) else self:SetVerticalScroll(0) end end end function BtWQuestsChainViewMixin:AddButtons(chainID, xOffset, yOffset, asideOverride, connectionsOverride, connectionsChainOverride) local character = self:GetCharacter() assert(character ~= nil, "Must set a character before setting a chain") local buttons = self.ItemButtons[chainID] if not buttons then buttons = {}; self.ItemButtons[chainID] = buttons; end local rect = self.rect; local chain = BtWQuestsDatabase:GetChainByID(chainID) -- Normally previous and embed are the same, but after embedding a chain, previous is the last spot of -- the embedded chain and embed is the first spot. local previousX, previousY, embedX, embedY = nil, 0, nil, 0 local index = 1 local item = chain:GetItem(index, character) while item do if item:IsValidForCharacter(character) then local x = item:GetX() local y = item:GetY() if x == nil then if y == nil then if previousX == nil then x = 0 y = 0 else x = embedX + 2 y = embedY if x > 6 then x = x - 8 y = y + 1 end end else x = previousX y = y end elseif y == nil then x = x if previousX ~= nil and x <= previousX then y = previousY + 1 else y = embedY end else x = x y = y end embedX, embedY = x, y previousX, previousY = x, y x = x + xOffset y = y + yOffset if item:GetType() == "chain" and item:IsEmbed() then local connections = item:GetConnections(); local connectionsOverride; if connections then connectionsOverride = {}; for i,itemConnections in pairs(connections) do local override = {}; for k,connection in ipairs(itemConnections) do override[k] = index + connection end connectionsOverride[i] = override; end end previousX, previousY = self:AddButtons(item:GetID(), x or 0, y or 0, item:IsAside(character), connectionsOverride, chain) else rect.left = rect.left and min(rect.left, x) or x; rect.right = rect.right and max(rect.right, x) or x; rect.top = rect.top and min(rect.top, y) or y; rect.bottom = rect.bottom and max(rect.bottom, y) or y; local itemButton = buttons[index] or self.itemPool:Acquire(); buttons[index] = itemButton itemButton:SetHideSpoilers(self:GetHideSpoilers()) itemButton:Set(item, character) -- Check if the item should be next itemButton.IsNextAnim:Stop() if itemButton.status == nil then-- and itemButton.previousButtons ~= nil then local available = true for i,previous in ipairs(itemButton.previousButtons or {}) do if previous.status ~= "complete" then available = false break end end if available then itemButton.ActiveTexture:Show() itemButton.IsNextAnim:Play() itemButton.Name:SetShown(true) itemButton.SpoilerName:SetShown(false) end itemButton.previousButtons = nil end itemButton:SetPoint( "CENTER", itemButton:GetParent(), "TOPLEFT", x * CHAIN_GRID_HORIZONTAL_SIZE + CHAIN_GRID_HORIZONTAL_PADDING, -(y * CHAIN_GRID_VERTICAL_SIZE + CHAIN_GRID_VERTICAL_PADDING) ); local connectionIndex = 1 local connectionItem = item:GetConnection(connectionIndex, character, connectionsOverride and connectionsOverride[index], connectionsChainOverride) while connectionItem do if connectionItem:IsValidForCharacter(character) then local connectionChainID = connectionItem:GetRoot():GetID(); local connectionIndex = connectionItem:GetIndex(); if not self.ItemButtons[connectionChainID] then self.ItemButtons[connectionChainID] = {}; end local connectionButton = self.ItemButtons[connectionChainID][connectionIndex] or self.itemPool:Acquire(); self.ItemButtons[connectionChainID][connectionIndex] = connectionButton -- Storing this so the connected items can check if they should be next if connectionButton.previousButtons == nil then connectionButton.previousButtons = {} end table.insert(connectionButton.previousButtons, itemButton) local lineContainer = itemButton.linePool:Acquire(); lineContainer.Background:SetStartPoint("CENTER", itemButton); lineContainer.Background:SetEndPoint("CENTER", connectionButton); lineContainer.Active:SetStartPoint("CENTER", itemButton); lineContainer.Active:SetEndPoint("CENTER", connectionButton); lineContainer.Complete:SetStartPoint("CENTER", itemButton); lineContainer.Complete:SetEndPoint("CENTER", connectionButton); -- lineContainer:SetAlpha(1) lineContainer.PulseAlpha:Stop() lineContainer.Active:Hide() lineContainer.Complete:Hide() if itemButton.status == "complete" then lineContainer.Complete:Show() elseif itemButton.status == "active" then -- lineContainer.Active:Show() end lineContainer.connection = connectionButton lineContainer:SetShown(itemButton:IsShown() and connectionItem:Visible(character)); end connectionIndex = connectionIndex + 1 connectionItem = item:GetConnection(connectionIndex, character, connectionsOverride and connectionsOverride[index], connectionsChainOverride) end if item:Visible(character) then if self.lowestY == nil or y > self.lowestY then self.lowestY = y self.lowestButton = itemButton end if self.scrollTo == nil and itemButton.status ~= "complete" then if asideOverride or item:IsAside(character) then if self.scrollToButtonAside == nil then self.scrollToButtonAside = itemButton end elseif self.scrollToButton == nil then self.scrollToButton = itemButton end elseif type(self.scrollTo) == "number" and index == self.scrollTo then self.scrollToButton = itemButton elseif type(self.scrollTo) == "table" and item:EqualsItem(self.scrollTo) then self.scrollToButton = itemButton end end end end index = index + 1 item = chain:GetItem(index, character) end return (previousX or 0) + xOffset, (previousY or 0) + yOffset end function BtWQuestsChainViewMixin:Update() self:UpdateChain(self.chainID) end function BtWQuestsChainViewMixin:UpdateChain(chainID, connectionsOverride, connectionsChainOverride) local character = self:GetCharacter() local buttons = self.ItemButtons[chainID] assert(buttons ~= nil, "Cannot update a chain that was never added") local chain = BtWQuestsDatabase:GetChainByID(chainID) local index = 1 local item = chain:GetItem(index, character) while item do if item:IsValidForCharacter(character) then if item:GetType() == "chain" and item:IsEmbed() then local connections = item:GetConnections(); local connectionsOverride; if connections then connectionsOverride = {}; for i,itemConnections in pairs(connections) do local override = {}; for k,connection in ipairs(itemConnections) do override[k] = index + connection end connectionsOverride[i] = override; end end self:UpdateChain(item:GetID(), connectionsOverride, chain) else local itemButton = buttons[index] assert(itemButton, "Chain item was never added in the first place") local status = itemButton.status itemButton:Update(item) -- Check if the item should be next itemButton.IsNextAnim:Stop() if itemButton.status == nil then-- and itemButton.previousButtons ~= nil then local available = true for i,previous in ipairs(itemButton.previousButtons or {}) do if previous.status ~= "complete" then available = false break end end if available then itemButton.ActiveTexture:Show() itemButton.IsNextAnim:Play() itemButton.Name:SetShown(true) itemButton.SpoilerName:SetShown(false) end itemButton.previousButtons = nil end local connectionIndex = 1 local connectionItem = item:GetConnection(connectionIndex, character, connectionsOverride and connectionsOverride[index], connectionsChainOverride) while connectionItem do if connectionItem:IsValidForCharacter(character) then local connectionChainID = connectionItem:GetRoot():GetID(); local connectionIndex = connectionItem:GetIndex(); local connectionButton = self.ItemButtons[connectionChainID][connectionIndex]; -- Storing this so the connected items can check if they should be next if connectionButton.previousButtons == nil then connectionButton.previousButtons = {} end table.insert(connectionButton.previousButtons, itemButton) end connectionIndex = connectionIndex + 1 connectionItem = item:GetConnection(connectionIndex, character, connectionsOverride and connectionsOverride[index], connectionsChainOverride) end for lineContainer in itemButton.linePool:EnumerateActive() do if itemButton.status == "complete" and status ~= "complete" then lineContainer.DefaultToCompleteAnim:Play() end lineContainer:SetShown(itemButton:IsShown() and lineContainer.connection:IsShown()) end end end index = index + 1 item = chain:GetItem(index, character) end end -- [[ Expansions View ]] BtWQuestsExpansionButtonMixin = {} function BtWQuestsExpansionButtonMixin:OnClick() return self.item:OnClick(self.character, self, BtWQuestsFrame, BtWQuestsFrame.Tooltip) end function BtWQuestsExpansionButtonMixin:Set(item, character) assert(character ~= nil); self.item = item self:SetText(item:GetName(character)) self.Subtext:SetText(item:GetSubtext(character, true)) self.Active:SetShown(item:IsActive(character)) self.character = character; end BtWQuestsExpansionMixin = {} function BtWQuestsExpansionMixin:OnLoad() self.buttonPool = CreateFramePool("BUTTON", self, "BtWQuestsExpansionButtonTemplate") end function BtWQuestsExpansionMixin:Set(item, character) self.item = item self.Name:SetText(item:GetName()) local texture, left, right, top, bottom = item:GetImage() if texture ~= nil then self.Background:SetTexture(texture) self.Background:SetTexCoord(left, right, top, bottom) else self.Background:SetTexture("Interface\\Addons\\BtWQuests\\UI-Expansion") self.Background:SetTexCoord(0.43359375, 0.66015625, 0.0, 0.8125) end self.buttonPool:ReleaseAll() self.AutoLoad:SetShown(item:SupportAutoLoad()) self.AutoLoad:SetChecked(item:IsAutoLoad()) if item:IsLoaded() then local items = item:GetMajorItems(character) local previous = self.ViewAll for i=#items,1,-1 do local button = self.buttonPool:Acquire() button:Set(items[i], character) button:SetPoint("BOTTOM", previous, "TOP", 0, 5) button:Show() previous = button end self.Load:Hide() self.ViewAll:Show() else self.Load:Show() self.ViewAll:Hide() end end -- [[ Navbar ]] BtWQuestsNavBarMixin = {} function BtWQuestsNavBarMixin:OnShow() if not self.Initialized then local homeData = { name = HOME, OnClick = BtWQuestsNavBarButtonMixin.OnClick } self.dropDown = CreateFrame("Frame", nil, self, "BtWQuestsNavBarDropDownTemplate") NavBar_Initialize(self, "BtWQuestsNavBarButtonTemplate", homeData, self.home, self.overflow) self.overflow:SetScript("OnClick", function (self, button) local dropDown = self:GetParent().dropDown if ( dropDown.buttonOwner ~= self ) then CloseDropDownMenus(); end dropDown.buttonOwner = self; dropDown:Toggle(self, 20, 3) end) self.Initialized = true end end function BtWQuestsNavBarMixin:EnableExpansions(value) self.enableExpansions = value end function BtWQuestsNavBarMixin:Reset() NavBar_Reset(self) end function BtWQuestsNavBarMixin:SetExpansion(id) local character = self:GetCharacter() NavBar_Reset(self) self:AddButtons("expansion", id, character) end function BtWQuestsNavBarMixin:SetCategory(id) local character = self:GetCharacter() NavBar_Reset(self) self:AddButtons("category", id, character) end function BtWQuestsNavBarMixin:SetChain(id) local character = self:GetCharacter() NavBar_Reset(self) self:AddButtons("chain", id, character) end function BtWQuestsNavBarMixin:AddButtons(type, id, character) local id, name, expansion, parent, _ = tonumber(id) local item if type == "expansion" then if not self.enableExpansions then return end item = BtWQuestsDatabase:GetExpansionByID(id) name = item:GetName() elseif type == "category" then item = BtWQuestsDatabase:GetCategoryByID(id) name, expansion, parent = item:GetName(), item:GetExpansion(), item:GetParent() elseif type == "chain" then item = BtWQuestsDatabase:GetChainByID(id) name, expansion, parent = item:GetName(), item:GetExpansion(), item:GetCategory() end if parent then self:AddButtons("category", parent, character) parent = { type = "category", id = parent, } elseif expansion then self:AddButtons("expansion", expansion, character) parent = { type = "expansion", id = expansion, } end self:AddButton(type, id, name, parent, character) end function BtWQuestsNavBarMixin:AddButton(type, id, name, parent) local buttonData = { type = type, id = tonumber(id), name = name, parent = parent, OnClick = BtWQuestsNavBarButtonMixin.OnClick, listFunc = BtWQuestsNavBarButtonMixin.GetList, } NavBar_AddButton(self, buttonData); end function BtWQuestsNavBarMixin:GoToItem(item) local BtWQuestsFrame = self:GetParent() if item.type == nil then if self.enableExpansions then BtWQuestsFrame:SelectExpansion() else BtWQuestsFrame:SelectExpansion(BtWQuestsFrame.expansionID or BtWQuestsDatabase:GetBestExpansionForCharacter(self:GetCharacter())) end elseif item.type == "expansion" then BtWQuestsFrame:SelectExpansion(item.id) elseif item.type == "category" then BtWQuestsFrame:SelectCategory(item.id) elseif item.type == "chain" then BtWQuestsFrame:SelectChain(item.id) end end function BtWQuestsNavBarMixin:GetCharacter() return self:GetParent():GetCharacter() end BtWQuestsNavBarButtonMixin = {} function BtWQuestsNavBarButtonMixin:GetList() local character = self:GetParent():GetCharacter() local item = self.data.parent local sisters = {} if item == nil then for i=0,LE_EXPANSION_LEVEL_CURRENT do if BtWQuestsDatabase:HasExpansion(i) then table.insert(sisters, { id = { type = "expansion", id = i }, text = BtWQuestsDatabase:GetExpansionByID(i):GetName(), func = function(button, item) self:GetParent():GoToItem(item) end, }) end end elseif item.type == "expansion" then local items = BtWQuestsDatabase:GetExpansionByID(item.id):GetItemList(character, true, false, false) for _,item in ipairs(items) do table.insert(sisters, { id = { type = item:GetType(), id = item:GetID() }, text = item:GetName(character), func = function(button, item) self:GetParent():GoToItem(item) end, }) end elseif item.type == "category" then local items = BtWQuestsDatabase:GetCategoryByID(item.id):GetItemList(character, true, false, false) for _,item in ipairs(items) do table.insert(sisters, { id = { type = item:GetType(), id = item:GetID() }, text = item:GetName(character), func = function(button, item) self:GetParent():GoToItem(item) end, }) end elseif item.type == "chain" then end return sisters end function BtWQuestsNavBarButtonMixin:OnClick() self:GetParent():GoToItem(self.data) end BtWQuestsNavBarDropDownMenuMixin = {} function BtWQuestsNavBarDropDownMenuMixin:OnLoad() self.displayMode = "MENU" end function BtWQuestsNavBarDropDownMenuMixin:Initialize() local navButton = self.buttonOwner; if not navButton or not navButton.listFunc then return; end local info = self:CreateInfo(); info.func = NavBar_DropDown_Click; info.owner = navButton; info.notCheckable = true; local list = navButton:listFunc(); if ( list ) then for i, entry in ipairs(list) do info.text = entry.text; info.arg1 = entry.id; info.arg2 = entry.func; self:AddButton(info); end end end -- [[ DropDown Menu ]] -- This is a simplified replacement for the built in drop down menus to prevent taint -- Most of this is a copy and paste from the built in system BtWQuestsDropDownMenuMixin = {} function BtWQuestsDropDownMenuMixin:SetDropDownWidth(width, padding) -- self.Middle:SetWidth(width) -- self:SetWidth(self.Left:GetWidth() + self.Right:GetWidth() + self.Middle:GetWidth()) self.Middle:SetWidth(width); local defaultPadding = 25; if ( padding ) then self:SetWidth(width + padding); else self:SetWidth(width + defaultPadding + defaultPadding); end if ( padding ) then self.Text:SetWidth(width); else self.Text:SetWidth(width - defaultPadding); end -- frame.noResize = 1; end function BtWQuestsDropDownMenuMixin:SetText(text) self.Text:SetText(text) end function BtWQuestsDropDownMenuMixin:GetText() return self.Text:GetText() end function BtWQuestsDropDownMenuMixin:JustifyText(justification) local text = self.Text text:ClearAllPoints() if justification == "LEFT" then text:SetPoint("LEFT", self.Left, "LEFT", 27, 2) text:SetJustifyH("LEFT") elseif justification == "RIGHT" then text:SetPoint("RIGHT", self.Right, "RIGHT", -43, 2) text:SetJustifyH("RIGHT") elseif justification == "CENTER" then text:SetPoint("CENTER", self.Middle, "CENTER", -5, 2) text:SetJustifyH("CENTER") end end function BtWQuestsDropDownMenuMixin:GetListFrame() local list = self.list if list == nil then list = CreateFrame("Button", nil, nil, "BtWQuestsDropDownListTemplate") list:SetFrameStrata("FULLSCREEN_DIALOG") list:SetToplevel(true) list:Hide() list:SetWidth(180) list:SetHeight(10) self.list = list self.buttonPool = CreateFramePool("BUTTON", list, "BtWQuestsDropDownButtonTemplate") local menu = self hooksecurefunc("ToggleDropDownMenu", function () menu:Close() end) hooksecurefunc("CloseDropDownMenus", function () if not list:IsMouseOver() then menu:Close() end end) end return list end function BtWQuestsDropDownMenuMixin:CreateInfo() local prefix = self.prefix or "BtWQuestsDropDown" local info = _G[prefix .. 'Info'] if info == nil then _G[prefix .. 'Info'] = {} return _G[prefix .. 'Info'] end table.wipe(info) return info end function BtWQuestsDropDownMenuMixin:GetButtonWidth(button) local minWidth = button.minWidth or 0; if button.customFrame and button.customFrame:IsShown() then return math.max(minWidth, button.customFrame:GetPreferredEntryWidth()); end if not button:IsShown() then return 0; end local width; local icon = button.Icon; local normalText = button.NormalText if ( button.iconOnly and icon ) then width = icon:GetWidth(); elseif ( normalText and normalText:GetText() ) then width = normalText:GetWidth() + 40; if ( button.icon ) then -- Add padding for the icon width = width + 10; end else return minWidth; end -- Add padding if has and expand arrow or color swatch if ( button.hasArrow or button.hasColorSwatch ) then width = width + 10; end if ( button.notCheckable ) then width = width - 30; end if ( button.padding ) then width = width + button.padding; end return math.max(minWidth, width); end function BtWQuestsDropDownMenuMixin:AddButton(info) local listFrame = self:GetListFrame() local button = self.buttonPool:Acquire() local index = self.buttonPool:GetNumActive() local normalText = button.NormalText local icon = button.Icon -- This button is used to capture the mouse OnEnter/OnLeave events if the dropdown button is disabled, since a disabled button doesn't receive any events -- This is used specifically for drop down menu time outs -- local invisibleButton = button.InvisibleButton button:SetWidth(listFrame:GetWidth() - 30) -- Default settings button:SetDisabledFontObject(GameFontDisableSmallLeft); -- invisibleButton:Hide(); button:Enable(); -- If not clickable then disable the button and set it white if ( info.notClickable ) then info.disabled = true; button:SetDisabledFontObject(GameFontHighlightSmallLeft); end -- Set the text color and disable it if its a title if ( info.isTitle ) then info.disabled = true; button:SetDisabledFontObject(GameFontNormalSmallLeft); end -- Disable the button if disabled and turn off the color code if ( info.disabled ) then button:Disable(); -- invisibleButton:Show(); info.colorCode = nil; end -- If there is a color for a disabled line, set it if( info.disablecolor ) then info.colorCode = info.disablecolor; end -- Configure button if ( info.text ) then -- look for inline color code this is only if the button is enabled if ( info.colorCode ) then button:SetText(info.colorCode..info.text.."|r"); else button:SetText(info.text); end -- Set icon if ( info.icon or info.mouseOverIcon ) then icon:SetSize(16,16); icon:SetTexture(info.icon); icon:ClearAllPoints(); icon:SetPoint("RIGHT"); if ( info.tCoordLeft ) then icon:SetTexCoord(info.tCoordLeft, info.tCoordRight, info.tCoordTop, info.tCoordBottom); else icon:SetTexCoord(0, 1, 0, 1); end icon:Show(); else icon:Hide(); end -- Check to see if there is a replacement font if ( info.fontObject ) then button:SetNormalFontObject(info.fontObject); button:SetHighlightFontObject(info.fontObject); else button:SetNormalFontObject(GameFontHighlightSmallLeft); button:SetHighlightFontObject(GameFontHighlightSmallLeft); end else button:SetText(""); icon:Hide(); end button.iconOnly = nil; button.icon = nil; button.iconInfo = nil; if (info.iconInfo) then icon.tFitDropDownSizeX = info.iconInfo.tFitDropDownSizeX; else icon.tFitDropDownSizeX = nil; end if (info.iconOnly and info.icon) then button.iconOnly = true; button.icon = info.icon; button.iconInfo = info.iconInfo; UIDropDownMenu_SetIconImage(icon, info.icon, info.iconInfo); icon:ClearAllPoints(); icon:SetPoint("LEFT"); end -- Pass through attributes button.func = info.func; button.owner = info.owner; button.hasOpacity = info.hasOpacity; button.opacity = info.opacity; button.opacityFunc = info.opacityFunc; button.cancelFunc = info.cancelFunc; button.swatchFunc = info.swatchFunc; button.keepShownOnClick = info.keepShownOnClick; button.tooltipTitle = info.tooltipTitle; button.tooltipText = info.tooltipText; button.tooltipInstruction = info.tooltipInstruction; button.tooltipWarning = info.tooltipWarning; button.arg1 = info.arg1; button.arg2 = info.arg2; button.hasArrow = info.hasArrow; button.hasColorSwatch = info.hasColorSwatch; button.notCheckable = info.notCheckable; button.menuList = info.menuList; button.tooltipWhileDisabled = info.tooltipWhileDisabled; button.noTooltipWhileEnabled = info.noTooltipWhileEnabled; button.tooltipOnButton = info.tooltipOnButton; button.noClickSound = info.noClickSound; button.padding = info.padding; button.icon = info.icon; button.mouseOverIcon = info.mouseOverIcon; button.deleteFunc = info.deleteFunc button.hasDelete = info.hasDelete if ( info.value ) then button.value = info.value; elseif ( info.text ) then button.value = info.text; else button.value = nil; end -- If not checkable move everything over to the left to fill in the gap where the check would be local xPos = 5; local yPos = -((index - 1) * UIDROPDOWNMENU_BUTTON_HEIGHT) - UIDROPDOWNMENU_BORDER_HEIGHT; local displayInfo = normalText; if (info.iconOnly) then displayInfo = icon; end displayInfo:ClearAllPoints(); if ( info.notCheckable ) then if ( info.justifyH and info.justifyH == "CENTER" ) then displayInfo:SetPoint("CENTER", button, "CENTER", -7, 0); else displayInfo:SetPoint("LEFT", button, "LEFT", 0, 0); end xPos = xPos + 10; else xPos = xPos + 12; displayInfo:SetPoint("LEFT", button, "LEFT", 20, 0); end if ( info.leftPadding ) then xPos = xPos + info.leftPadding; end button:SetPoint("TOPLEFT", button:GetParent(), "TOPLEFT", xPos, yPos) if not info.notCheckable then local check = button.Check local uncheck = button.UnCheck if ( info.disabled ) then check:SetDesaturated(true); check:SetAlpha(0.5); uncheck:SetDesaturated(true); uncheck:SetAlpha(0.5); else check:SetDesaturated(false); check:SetAlpha(1); uncheck:SetDesaturated(false); uncheck:SetAlpha(1); end if info.customCheckIconAtlas or info.customCheckIconTexture then check:SetTexCoord(0, 1, 0, 1); uncheck:SetTexCoord(0, 1, 0, 1); if info.customCheckIconAtlas then check:SetAtlas(info.customCheckIconAtlas); uncheck:SetAtlas(info.customUncheckIconAtlas or info.customCheckIconAtlas); else check:SetTexture(info.customCheckIconTexture); uncheck:SetTexture(info.customUncheckIconTexture or info.customCheckIconTexture); end elseif info.isNotRadio then check:SetTexCoord(0.0, 0.5, 0.0, 0.5); check:SetTexture("Interface\\Common\\UI-DropDownRadioChecks"); uncheck:SetTexCoord(0.5, 1.0, 0.0, 0.5); uncheck:SetTexture("Interface\\Common\\UI-DropDownRadioChecks"); else check:SetTexCoord(0.0, 0.5, 0.5, 1.0); check:SetTexture("Interface\\Common\\UI-DropDownRadioChecks"); uncheck:SetTexCoord(0.5, 1.0, 0.5, 1.0); uncheck:SetTexture("Interface\\Common\\UI-DropDownRadioChecks"); end -- Checked can be a function now local checked = info.checked; if ( type(checked) == "function" ) then checked = checked(button); end -- Show the check if checked if ( checked ) then button:LockHighlight(); check:Show(); uncheck:Hide(); else button:UnlockHighlight(); check:Hide(); uncheck:Show(); end else button.Check:Hide(); button.UnCheck:Hide(); end button.checked = info.checked; -- If has a colorswatch, show it and vertex color it local colorSwatch = button.ColorSwatch if ( info.hasColorSwatch ) then button.ColorSwatch.NormalTexture:SetVertexColor(info.r, info.g, info.b); button.r = info.r; button.g = info.g; button.b = info.b; colorSwatch:Show(); else colorSwatch:Hide(); end local deleteButton = button.DeleteButton if info.hasDelete then deleteButton:Show() else deleteButton:Hide() end UIDropDownMenu_CheckAddCustomFrame(listFrame, button, info); button:SetShown(button.customFrame == nil); button.minWidth = info.minWidth; local width = max(self:GetButtonWidth(button), info.minWidth or 0); --Set maximum button width if ( width > listFrame.maxWidth ) then listFrame.maxWidth = width; end -- Set the height of the listframe listFrame:SetHeight((index * UIDROPDOWNMENU_BUTTON_HEIGHT) + (UIDROPDOWNMENU_BORDER_HEIGHT * 2)); button:Show() end function BtWQuestsDropDownMenuMixin:Toggle(anchorName, xOffset, yOffset) local list = self:GetListFrame() if list:IsShown() and self.anchorName == anchorName then self:Close() else self.anchorName = anchorName self:Open(anchorName, xOffset, yOffset) end end function BtWQuestsDropDownMenuMixin:Open(anchorName, xOffset, yOffset) CloseDropDownMenus() local list = self:GetListFrame() -- Set the dropdownframe scale local uiScale; local uiParentScale = UIParent:GetScale(); if GetCVar("useUIScale") == "1" then uiScale = tonumber(GetCVar("uiscale")) if uiParentScale < uiScale then uiScale = uiParentScale end else uiScale = uiParentScale end list:SetScale(uiScale) list:ClearAllPoints() local point, relativeTo, relativePoint if ( not anchorName ) then -- See if the anchor was set manually using setanchor if ( self.xOffset ) then xOffset = self.xOffset; end if ( self.yOffset ) then yOffset = self.yOffset; end if ( self.point ) then point = self.point; end if ( self.relativeTo ) then relativeTo = self.relativeTo; else relativeTo = self.Left end if ( self.relativePoint ) then relativePoint = self.relativePoint; end elseif ( anchorName == "cursor" ) then relativeTo = nil; local cursorX, cursorY = GetCursorPosition(); cursorX = cursorX/uiScale; cursorY = cursorY/uiScale; if ( not xOffset ) then xOffset = 0; end if ( not yOffset ) then yOffset = 0; end xOffset = cursorX + xOffset; yOffset = cursorY + yOffset; else -- See if the anchor was set manually using setanchor if ( self.xOffset ) then xOffset = self.xOffset; end if ( self.yOffset ) then yOffset = self.yOffset; end if ( self.point ) then point = self.point; end if ( self.relativeTo ) then relativeTo = self.relativeTo; else relativeTo = anchorName; end if ( self.relativePoint ) then relativePoint = self.relativePoint; end end if not point then point = "TOPLEFT" end if not relativePoint then relativePoint = "BOTTOMLEFT" end if not xOffset or not yOffset then xOffset = 8 yOffset = 22 end list:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset); if self.displayMode == "MENU" then list.Backdrop:Hide() list.MenuBackdrop:Show() else list.Backdrop:Show() list.MenuBackdrop:Hide() end list.maxWidth = 0 self.buttonPool:ReleaseAll() self:Initialize() list:SetWidth(list.maxWidth + 25) for button in self.buttonPool:EnumerateActive() do button:SetWidth(list.maxWidth); end list:Show() local offLeft = list:GetLeft()/uiScale; local offRight = (GetScreenWidth() - list:GetRight())/uiScale; local offTop = (GetScreenHeight() - list:GetTop())/uiScale; local offBottom = list:GetBottom()/uiScale; local xAddOffset, yAddOffset = 0, 0; if ( offLeft < 0 ) then xAddOffset = -offLeft; elseif ( offRight < 0 ) then xAddOffset = offRight; end if ( offTop < 0 ) then yAddOffset = offTop; elseif ( offBottom < 0 ) then yAddOffset = -offBottom; end list:ClearAllPoints(); if ( anchorName == "cursor" ) then list:SetPoint(point, relativeTo, relativePoint, xOffset + xAddOffset, yOffset + yAddOffset); else list:SetPoint(point, relativeTo, relativePoint, xOffset + xAddOffset, yOffset + yAddOffset); end end function BtWQuestsDropDownMenuMixin:Close() self:GetListFrame():Hide() end -- [[ Character Dropdown ]] BtWQuestsCharacterDropDownMixin = {} function BtWQuestsCharacterDropDownMixin:OnLoad() self:SetDropDownWidth(156, 23 * 2); self.xOffset = 8 self.yOffset = 15 -- self:JustifyText("LEFT"); -- if not self.Initialized then -- UIDropDownMenu_SetWidth(self, 156, 23 * 2); -- UIDropDownMenu_SetInitializeFunction(self, self.Initialize); -- -- UIDropDownMenu_Initialize(self, self.Initialize); -- self.xOffset = 8 -- self.yOffset = 15 -- self.Initialized = true -- end end function BtWQuestsCharacterDropDownMixin:Initialize() local function Select (button) self:GetParent():SelectCharacter(button.value) end local name = UnitName("player") local realm = GetRealmName() local player = name .. "-" .. realm local currentName, currentRealm = self:GetParent():GetCharacter():GetFullName() local current = currentName .. "-" .. currentRealm if C_QuestSession.HasJoined() then local info = self:CreateInfo(); info.text = BtWQuests.L["Party Sync"] info.value = "-partysync" info.func = Select info.checked = "-partysync" == current self:AddButton(info) end local info = self:CreateInfo(); info.text = RAID_CLASS_COLORS[select(2,UnitClass("player"))]:WrapTextInColorCode(player .. " (" .. UnitLevel("player") .. ")") -- info.text = player info.value = player info.func = Select info.checked = player == current info.deleteFunc = function (button, ...) BtWQuestsCharacters:RemoveCharacter(button.value) end self:AddButton(info) info.hasDelete = true for _,character,data in BtWQuestsCharacters:ipairs() do if character ~= player then info.text = RAID_CLASS_COLORS[data:GetClassString()]:WrapTextInColorCode(character .. " (" .. data:GetLevel() .. ")") -- info.text = character info.value = character info.func = Select info.checked = character == current self:AddButton(info) end end end -- [[ Expansion Dropdown ]] BtWQuestsExpansionDropDownMixin = {} function BtWQuestsExpansionDropDownMixin:OnLoad() self:SetDropDownWidth(156); self:JustifyText("LEFT"); -- if not self.Initialized then -- UIDropDownMenu_SetWidth(self, 156); -- UIDropDownMenu_JustifyText(self, "LEFT"); -- UIDropDownMenu_SetInitializeFunction(self, self.Initialize); -- -- UIDropDownMenu_Initialize(self, self.Initialize); -- self.Initialized = true -- end end function BtWQuestsExpansionDropDownMixin:Initialize(level) local function Select (button) self:GetParent():SelectExpansion(button.value) end local info = self:CreateInfo() local current = self:GetParent():GetExpansion() for i=0,LE_EXPANSION_LEVEL_CURRENT do if BtWQuestsDatabase:HasExpansion(i) then info.text = BtWQuestsDatabase:GetExpansionByID(i) info.value = i; info.func = Select info.checked = i == current; self:AddButton(info) elseif i == current then info.text = _G['BTWQUESTS_EXPANSION_NAME' .. i] info.value = i; info.func = Select info.checked = i == current; self:AddButton(info) end end end -- [[ Tooltip ]] BtWQuestsTooltipMixin = {} function BtWQuestsTooltipMixin:OnLoad() GameTooltip_OnLoad(self) if not TooltipDataProcessor or not TooltipDataProcessor.AddTooltipPostCall then self:SetScript("OnTooltipSetQuest", self.OnSetQuest) end end function BtWQuestsTooltipMixin:OnSetQuest() local quest = BtWQuestsDatabase:GetQuestByID(self.questID) if quest == nil then return end if not self.character:IsPartySync() or not C_QuestLog.IsQuestReplayable(self.questID) then self:AddRewards(quest, self.character) end end function BtWQuestsTooltipMixin:AddRewards(item, character) local rewards = item:GetRewards() if not rewards or #rewards == 0 then return end local addedRewards for _,reward in ipairs(rewards) do reward = reward:GetVariation(character) or reward; if reward:IsValidForCharacter(character) and reward:Visible(character) then if not addedRewards then self:AddLine(" ") self:AddLine(L["BTWQUESTS_TOOLTIP_REWARDS"]) addedRewards = true end self:AddLine(" - " .. reward:GetName(character, "reward"), 1, 1, 1) end end end function BtWQuestsTooltipMixin:SetChain(chainID, character) local chainID = tonumber(chainID) local chain = BtWQuestsDatabase:GetChainByID(chainID); self:ClearLines() self:AddDoubleLine(chain:GetName(character)) if chain:IsActive(character) then self:AddLine(GREEN_FONT_COLOR_CODE..L["BTWQUESTS_QUEST_CHAIN_ACTIVE"]..FONT_COLOR_CODE_CLOSE) end local prerequisites, hasLowPrio = chain:GetPrerequisites() if prerequisites then local addedPrerequisite for _,prerequisite in ipairs(prerequisites) do prerequisite = prerequisite:GetVariation(character) or prerequisite; if prerequisite:IsValidForCharacter(character) and prerequisite:Visible(character, IsModifiedClick("SHIFT")) then if not addedPrerequisite then self:AddLine(" ") self:AddLine(L["BTWQUESTS_TOOLTIP_PREREQUISITES"]) addedPrerequisite = true end if prerequisite:IsCompleted(character) then self:AddLine(" - " .. prerequisite:GetName(character, "prerequisite"), 0.5, 0.5, 0.5) else self:AddLine(" - " .. prerequisite:GetName(character, "prerequisite"), 1, 1, 1) end end end end self:AddRewards(chain, character) if IsModifiedClick("SHIFT") then local restrictions = chain:GetRestrictions() if restrictions then local addedRestrictions for _,restriction in ipairs(restrictions) do restriction = restriction:GetVariation(character) or restriction; if not addedRestrictions then self:AddLine(" ") self:AddLine(L["BTWQUESTS_TOOLTIP_RESTRICTIONS"]) addedRestrictions = true end if restriction:IsCompleted(character) then self:AddLine(" - " .. restriction:GetName(character, "restriction"), 0.5, 0.5, 0.5) else self:AddLine(" - " .. restriction:GetName(character, "restriction"), 1, 1, 1) end end end end self:Show(); end local IsUnitOnQuest = C_QuestLog.IsUnitOnQuest if not IsUnitOnQuest then function IsUnitOnQuest(unit, questID) return IsUnitOnQuestByQuestID(questID, unit) end end -- Custom function for displaying an active quest showing completed requirements function BtWQuestsTooltipMixin:SetActiveQuest(id, character) local id = tonumber(id) self.character = character self.questID = id local quest = BtWQuestsDatabase:GetQuestByID(id) local questLogIndex = GetLogIndexForQuestID(id) local isComplete = IsQuestComplete(id); local isFailed = IsQuestFailed(id); local _, objectiveText = GetQuestLogQuestText(questLogIndex); self:ClearLines() self:SetText(quest:GetName()) if character:IsQuestActive(id) then if character:IsPlayer() and C_QuestLog.IsQuestReplayable and C_QuestLog.IsQuestReplayable(id) then GameTooltip_AddInstructionLine(self, QuestUtils_GetReplayQuestDecoration(id)..QUEST_SESSION_QUEST_TOOLTIP_IS_REPLAY, false); elseif character:IsPlayer() and C_QuestLog.IsQuestDisabledForSession and C_QuestLog.IsQuestDisabledForSession(id) then GameTooltip_AddColoredLine(self, QuestUtils_GetDisabledQuestDecoration(id)..QUEST_SESSION_ON_HOLD_TOOLTIP_TITLE, DISABLED_FONT_COLOR, false); else self:AddLine(GREEN_FONT_COLOR_CODE..QUEST_TOOLTIP_ACTIVE..FONT_COLOR_CODE_CLOSE) end end if isFailed then QuestUtils_AddQuestTagLineToTooltip(self, FAILED, "FAILED", nil, RED_FONT_COLOR); end if isComplete then local completionText = GetQuestLogCompletionText(questLogIndex) or QUEST_WATCH_QUEST_READY; self:AddLine(" ") self:AddLine(completionText, 1, 1, 1, true); else if objectiveText then self:AddLine(" ") self:AddLine(objectiveText, 1, 1, 1, true) end local numRequirements = character:GetNumQuestLeaderBoards(id); local addedTitle for index = 1,numRequirements do local name, _, completed = character:GetQuestLogLeaderBoard(index, id); if name then if not addedTitle then self:AddLine(" ") self:AddLine(QUEST_TOOLTIP_REQUIREMENTS) addedTitle = true end if completed then self:AddLine(" - " .. name, 0.5, 0.5, 0.5) else self:AddLine(" - " .. name, 1, 1, 1) end end end end local partyMembersOnQuest = 0; for i=1, GetNumSubgroupMembers() do if IsUnitOnQuest("party"..i, i) then -- Found at least one party member who is also on the quest, set it up! self:AddLine(" "); self:AddLine(PARTY_QUEST_STATUS_ON); local omitTitle = true; local ignoreActivePlayer = true; self:SetQuestPartyProgress(id, omitTitle, ignoreActivePlayer); break; end end self:OnSetQuest() self:Show() end -- Custom function for displaying quests not in the log, used for bcc and before SetHyperlink function BtWQuestsTooltipMixin:SetQuest(id, character) local id = tonumber(id) self.character = character self.questID = id local quest = BtWQuestsDatabase:GetQuestByID(id) self:ClearLines() self:SetText(quest:GetName()) -- if objectiveText then -- self:AddLine(" ") -- self:AddLine(objectiveText, 1, 1, 1, true) -- end local objectives = C_QuestLog.GetQuestObjectives(id); if objectives then local addedTitle for _,objective in ipairs(objectives) do if objective then if not addedTitle then self:AddLine(" ") self:AddLine(QUEST_TOOLTIP_REQUIREMENTS) addedTitle = true end self:AddLine(" - " .. objective.text, 1, 1, 1) end end end for i=1, GetNumSubgroupMembers() do if IsUnitOnQuest("party"..i, i) then -- Found at least one party member who is also on the quest, set it up! self:AddLine(" "); self:AddLine(PARTY_QUEST_STATUS_ON); local omitTitle = true; local ignoreActivePlayer = true; self:SetQuestPartyProgress(id, omitTitle, ignoreActivePlayer); break; end end self:OnSetQuest() self:Show() end if TooltipDataProcessor and TooltipDataProcessor.AddTooltipPostCall then TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Quest, function (self, data) if self.OnSetQuest then self:OnSetQuest(); end end) end -- Doing this because TSM and Auctioneer tainted GameTooltip.SetHyperlink without checking if their variables exist local dummpGameTooltip = CreateFrame("GameTooltip", "BtWQuestsDummyTooltip", UIParent, "GameTooltipTemplate") dummpGameTooltip:Hide() function BtWQuestsTooltipMixin:SetHyperlink(link, character) local _, _, color, linkstring, name = string.find(link, "^|cff(%x%x%x%x%x%x)|H([^|]+)|h%[(.*)%]|h|r$") linkstring = linkstring or link local _, _, type, text = string.find(linkstring, "([^:]+):([^|]+)") if type == "quest" then local _, _, id = string.find(text, "^(%d+)") id = tonumber(id); if character:IsQuestActive(id) then self:SetActiveQuest(id, character) else self.character = character self.questID = id self:SetQuest(id, character) if QuestEventListener then QuestEventListener:AddCallback(id, function() if self.questID == id then dummpGameTooltip.SetHyperlink(self, link) end end) end end elseif type == "btwquests" then local _, _, subtype, id = string.find(text, "^([^:]*):(%d+)") if subtype == "chain" then self:SetChain(id, character) end else dummpGameTooltip.SetHyperlink(self, link) end end -- [[ Search ]] local MIN_CHARACTER_SEARCH = 3 BTWQUESTS_NUM_SEARCH_PREVIEWS = 5; BTWQUESTS_SHOW_ALL_SEARCH_RESULTS_INDEX = BTWQUESTS_NUM_SEARCH_PREVIEWS + 1; BtWQuestsSearchBoxMixin = {} function BtWQuestsSearchBoxMixin:GetViewFrame() -- Should be the BtWQuestsFrame return self:GetParent() end function BtWQuestsSearchBoxMixin:GetPreviewFrame() return self:GetViewFrame().SearchPreview end function BtWQuestsSearchBoxMixin:GetResultsFrame() return self:GetViewFrame().SearchResults end function BtWQuestsSearchBoxMixin:GetCharacter() return self:GetViewFrame():GetCharacter() end function BtWQuestsSearchBoxMixin:GetTooltip() return BtWQuestsTooltip end function BtWQuestsSearchBoxMixin:SetSearch(query) local start = debugprofilestop() self.query = query if not self.results then self.results = {}; end wipe(self.results); BtWQuestsDatabase:Search(self.results, query, self:GetCharacter()) -- print (string.format("BtWQuests search found %d in %fms", #self.results, debugprofilestop() - start)) end function BtWQuestsSearchBoxMixin:ClearSearch() self.query = nil self.results = {} end function BtWQuestsSearchBoxMixin:HidePreview() local frame = self:GetPreviewFrame() if frame then frame:Hide() end end function BtWQuestsSearchBoxMixin:HideResults() local frame = self:GetResultsFrame() if frame then frame:Hide() end end function BtWQuestsSearchBoxMixin:UpdateResults() local resultsFrame = self:GetResultsFrame() local previewFrame = self:GetPreviewFrame() if resultsFrame and (resultsFrame:IsShown() or not previewFrame) then resultsFrame:UpdateResults(self.query, self.results) else previewFrame:UpdateResults(self.query, self.results) end end function BtWQuestsSearchBoxMixin:ShowFullSearch() local resultsFrame = self:GetResultsFrame() local previewFrame = self:GetPreviewFrame() if resultsFrame then if previewFrame then previewFrame:Hide() end resultsFrame:Show() self:UpdateResults() self:ClearFocus() end end function BtWQuestsSearchBoxMixin:OnLoad() SearchBoxTemplate_OnLoad(self) end function BtWQuestsSearchBoxMixin:OnShow() self:SetFrameLevel(self:GetParent():GetFrameLevel() + 10) end function BtWQuestsSearchBoxMixin:OnHide() end function BtWQuestsSearchBoxMixin:OnTextChanged() SearchBoxTemplate_OnTextChanged(self) local text = self:GetText(); self:SetSearch(text) self:UpdateResults() end function BtWQuestsSearchBoxMixin:OnEnterPressed() local previewFrame = self:GetPreviewFrame() if previewFrame then previewFrame:OpenSelection(self) end end function BtWQuestsSearchBoxMixin:OnKeyDown(key) local previewFrame = self:GetPreviewFrame() if previewFrame then if key == "UP" then previewFrame:MoveSelection(-1) elseif key == "DOWN" then previewFrame:MoveSelection(1) end end end function BtWQuestsSearchBoxMixin:OnFocusLost() SearchBoxTemplate_OnEditFocusLost(self); if not self:GetPreviewFrame():IsMouseOver() then self:HidePreview() end end function BtWQuestsSearchBoxMixin:OnFocusGained() SearchBoxTemplate_OnEditFocusGained(self) if self:GetNumResults() == 0 then self:HidePreview() self:HideResults() return end self:SetSearch(self:GetText()) local resultsFrame = self:GetResultsFrame() local previewFrame = self:GetPreviewFrame() if previewFrame then if resultsFrame then resultsFrame:Hide() end -- self:SetPreviewSelection(1) previewFrame:UpdateResults(self.query, self.results) end end function BtWQuestsSearchBoxMixin:GetNumResults() return #self.results end BtWQuestsSearchPreviewMixin = {} function BtWQuestsSearchPreviewMixin:OnLoad() self:SetSelection(1) end function BtWQuestsSearchPreviewMixin:UpdateResults(query, results) local numResults = #results if numResults == 0 then self:Hide() end for index = 1, BTWQUESTS_NUM_SEARCH_PREVIEWS do local button = self.Results[index] if index <= numResults then button.Name:SetText(results[index].name); button.link = results[index].item.link; button.tooltip = results[index].item.tooltip; button.scrollTo = results[index].item.scrollTo; button:SetID(index) button:Show() else button:Hide() end end self:Show() self.ShowAllResults:Hide(); -- self.searchBox.searchProgress:Hide(); if numResults > BTWQUESTS_NUM_SEARCH_PREVIEWS then self.ShowAllResults.text:SetText(string.format(ENCOUNTER_JOURNAL_SHOW_SEARCH_RESULTS, numResults)); self.ShowAllResults:Show(); end self:FixBottomBorder() end function BtWQuestsSearchPreviewMixin:OpenSelection(SearchBox) if self.selectedIndex > BTWQUESTS_SHOW_ALL_SEARCH_RESULTS_INDEX or self.selectedIndex < 0 then return; elseif self.selectedIndex == BTWQUESTS_SHOW_ALL_SEARCH_RESULTS_INDEX then if self.ShowAllResults:IsShown() then self.ShowAllResults:Click(); end else local result = self.Results[self.selectedIndex]; if result:IsShown() then result:Click(); end end self:Hide() end function BtWQuestsSearchPreviewMixin:FixBottomBorder() local lastShownButton = nil if self.ShowAllResults:IsShown() then lastShownButton = self.ShowAllResults else for index = 1, BTWQUESTS_NUM_SEARCH_PREVIEWS do local button = self.Results[index] if button:IsShown() then lastShownButton = button; end end end if lastShownButton ~= nil then self:SetHeight(self:GetTop() - lastShownButton:GetBottom()) self.botRightCorner:SetPoint("BOTTOM", lastShownButton, "BOTTOM", 0, -8) self.botLeftCorner:SetPoint("BOTTOM", lastShownButton, "BOTTOM", 0, -8) else self:Hide() end end function BtWQuestsSearchPreviewMixin:SetSelection(selectedIndex) local numShown = 0; for index = 1, BTWQUESTS_NUM_SEARCH_PREVIEWS do self.Results[index].selectedTexture:Hide(); if self.Results[index]:IsShown() then numShown = numShown + 1; end end if self.ShowAllResults:IsShown() then numShown = numShown + 1; end self.ShowAllResults.selectedTexture:Hide(); if numShown == 0 then selectedIndex = 1; elseif selectedIndex > numShown then -- Wrap under to the beginning. selectedIndex = 1; elseif selectedIndex < 1 then -- Wrap over to the end; selectedIndex = numShown; end self.selectedIndex = selectedIndex; if selectedIndex == BTWQUESTS_SHOW_ALL_SEARCH_RESULTS_INDEX then self.ShowAllResults.selectedTexture:Show(); else self.Results[selectedIndex].selectedTexture:Show(); end end function BtWQuestsSearchPreviewMixin:GetSelection() return self.selectedIndex end function BtWQuestsSearchPreviewMixin:MoveSelection(value) return self:SetSelection(self.selectedIndex + value) end BtWQuestsSearchResultsMixin = {} function BtWQuestsSearchResultsMixin:OnLoad() local this = self local scrollFrame = self.scrollFrame scrollFrame.update = function () this:UpdateSearch() end scrollFrame.scrollBar.doNotHide = true HybridScrollFrame_CreateButtons(scrollFrame, "BtWQuestsSearchResultFullTemplate", 0, 0) end function BtWQuestsSearchResultsMixin:UpdateResults(query, results) self.query = query self.results = results self:UpdateSearch() end function BtWQuestsSearchResultsMixin:UpdateSearch() local scrollFrame = self.scrollFrame local query = self.query local results = self.results local offset = HybridScrollFrame_GetOffset(scrollFrame) local buttons = scrollFrame.buttons local button, index local numResults = #results self.TitleText:SetText(string.format(ENCOUNTER_JOURNAL_SEARCH_RESULTS, query, numResults)); for i=1,#buttons do button = buttons[i]; index = offset + i; if index <= numResults then button.Name:SetText(results[index].name) button.resultType:SetText(results[index].item.type) button.path:SetText(results[index].item.path or "test") button.link = results[index].item.link; button.tooltip = results[index].item.tooltip; button.scrollTo = results[index].item.scrollTo; button:SetID(index) button:Show(); else button:Hide(); end end local totalHeight = numResults * 49; HybridScrollFrame_Update(scrollFrame, totalHeight, 370); end BtWQuestsSearchResultMixin = {} function BtWQuestsSearchResultMixin:GetResultsFrame() -- Gets the preview or full results frame end function BtWQuestsSearchResultMixin:GetViewFrame() -- Normally would get BtWQuestsFrame end function BtWQuestsSearchResultMixin:OnEnter() local viewFrame = self:GetViewFrame() if self.tooltip or self.link then BtWQuestsTooltip:SetPoint("TOPLEFT", self, "TOPRIGHT") BtWQuestsTooltip:SetOwner(self, "ANCHOR_PRESERVE"); BtWQuestsTooltip:SetHyperlink(self.tooltip or self.link, viewFrame:GetCharacter()) end end function BtWQuestsSearchResultMixin:OnLeave() BtWQuestsTooltip:Hide(); end function BtWQuestsSearchResultMixin:OnClick() local viewFrame = self:GetViewFrame() if viewFrame:SelectFromLink(self.link, self.scrollTo) then BtWQuestsTooltip:Hide(); end self:GetResultsFrame():Hide() PlaySound(SOUNDKIT.IG_SPELLBOOK_OPEN); end BtWQuestsSearchResultPreviewMixin = {} function BtWQuestsSearchResultPreviewMixin:GetResultsFrame() -- Gets the preview or full results frame return self:GetParent() end function BtWQuestsSearchResultPreviewMixin:GetViewFrame() -- Normally would get BtWQuestsFrame return self:GetParent():GetParent() end function BtWQuestsSearchResultPreviewMixin:OnEnter() BtWQuestsSearchResultMixin.OnEnter(self) self:GetParent():SetSelection(self:GetID()) end BtWQuestsSearchResultFullMixin = {} function BtWQuestsSearchResultFullMixin:GetResultsFrame() -- Gets the preview or full results frame return self:GetParent():GetParent():GetParent() end function BtWQuestsSearchResultFullMixin:GetViewFrame() -- Normally would get BtWQuestsFrame return self:GetParent():GetParent():GetParent():GetParent() end