local API, Titles, _, L = ImmersionAPI, {}, ... L.TitlesMixin = Titles -- Upvalue for update scripts local GetScaledCursorPosition, UIParent = GetScaledCursorPosition, UIParent local NORMAL_QUEST_DISPLAY = NORMAL_QUEST_DISPLAY:gsub(0, 'f') local TRIVIAL_QUEST_DISPLAY = TRIVIAL_QUEST_DISPLAY:gsub(0, 'f') -- Priority local P_COMPLETE_QUEST = 1 local P_AVAILABLE_QUEST = 2 local P_AVAILABLE_GOSSIP = 3 local P_INCOMPLETE_QUEST = 4 -- Animation divisor local ANI_DIVISOR = 10 ---------------------------------- -- Display ---------------------------------- function Titles:AdjustHeight(newHeight) self.offset = 0 if ( ANI_DIVISOR == 0 ) then self:SetHeight(1) self:OnUpdateOffset() return elseif ( ANI_DIVISOR == 1 ) then self:SetHeight(newHeight) self:OnUpdateOffset() return end self:SetScript('OnUpdate', function(self) local height = self:GetHeight() local diff = newHeight - height if abs(newHeight - height) < 0.5 then self:SetHeight(newHeight) self:SetScript('OnUpdate', nil) else self:SetHeight(height + ( diff / ANI_DIVISOR ) ) end self:OnUpdateOffset() end) end function Titles:OnUpdateOffset() local anchor, relativeRegion, relativeKey, x, y, offset if not self.ignoreAtCursor and L('gossipatcursor') then local posX, posY = GetScaledCursorPosition() local uiX, uiY = UIParent:GetCenter() x, y = (posX - uiX), (posY - uiY) anchor, relativeRegion, relativeKey, offset = 'CENTER', UIParent, 'CENTER', 0 else anchor, relativeRegion, relativeKey, x, y = self:GetPoint() offset = (self.offset or 0) + L('titleoffsetY') end local diff = ( y - offset ) if ( offset == 0 ) or abs( y - offset ) < 0.3 then self:SetPoint(anchor, relativeRegion, relativeKey, x, offset) if self:GetScript('OnUpdate') == self.OnUpdateOffset then self:SetScript('OnUpdate', nil) end else self:SetPoint(anchor, relativeRegion, relativeKey, x, offset + (ANI_DIVISOR > 1 and (diff / ANI_DIVISOR) or 0)) end end function Titles:StopMoving() self:StopMovingOrSizing() local centerX, centerY = self:GetCenter() local scaleOffset = self:GetScale() * self:GetParent():GetScale() local uiX, uiY = GetScreenWidth() / 2 / scaleOffset, GetScreenHeight() / 2 / scaleOffset local newHorzVal, newVertVal = (centerX - uiX), (centerY - uiY) -- Horizontal clip fix if self:GetLeft() < 0 then newHorzVal = (self:GetWidth() / 2) - (GetScreenWidth() / 2) + 16 elseif ( GetScreenWidth() - self:GetRight() ) < 0 then newHorzVal = (GetScreenWidth() / 2) - (self:GetWidth() / 2) - 16 end -- Vertical clip fix if self:GetBottom() < 0 then newVertVal = (self:GetHeight() / 2) - (GetScreenHeight() / 2) + 16 elseif ( GetScreenHeight() - self:GetTop() ) < 0 then newVertVal = (GetScreenHeight() / 2) - (self:GetHeight() / 2) - 16 end self:ClearAllPoints() self:SetPoint('CENTER', UIParent, newHorzVal, newVertVal) L.Set('titleoffset', newHorzVal) L.Set('titleoffsetY', newVertVal) end function Titles:OnScroll(delta) self.offset = self.offset and self.offset + (-delta * 40) or (-delta * 40) self.ignoreAtCursor = true self:SetScript('OnUpdate', self.OnUpdateOffset) end function Titles:ResetPosition() self.offset = 0 self.ignoreAtCursor = false end function Titles:OnEvent(event, ...) if self[event] then self[event](self, ...) else self:Hide() end end function Titles:OnHide() for i, button in pairs(self.Buttons) do button:UnlockHighlight() button:Hide() end wipe(self.Active) self.numActive = 0 self.idx = 1 end function Titles:GetNumActive() return self.numActive or 0 end function Titles:GetButton(index) local button = self.Buttons[index] if not button then button = L.Create({ type = 'Button', name = 'TitleButton', index = index, parent = self, inherit = 'ImmersionTitleButtonTemplate', mixins = {L.ButtonMixin, L.ScalerMixin}, backdrop = L.Backdrops.GOSSIP_TITLE_BG, }) button:Init(index) self.Buttons[index] = button end button:Show() return button end function Titles:UpdateActive() local newHeight, numActive = 0, 0 wipe(self.Active) for i, button in pairs(self.Buttons) do if button:IsShown() then newHeight = newHeight + button:GetHeight() numActive = numActive + 1 self.Active[i] = button end end ANI_DIVISOR = L('anidivisor') self.ignoreAtCursor = false self.numActive = numActive self:ResetPosition() self:AdjustHeight(newHeight) if self.SetFocus then local _, bestOptionIndex = self:GetBestOption() self:SetFocus(bestOptionIndex) end end function Titles:GetBestOption() local numActive = self:GetNumActive() if numActive > 0 then local option = self.Buttons[1] for i=2, numActive do option = option:ComparePriority(self.Buttons[i]) end return option, option.idx end end ---------------------------------- -- Gossip ---------------------------------- function Titles:GOSSIP_SHOW() self.idx = 1 self.type = 'Gossip' self:Show() self:UpdateAvailableQuests(API:GetGossipAvailableQuests()) self:UpdateActiveQuests(API:GetGossipActiveQuests()) self:UpdateGossipOptions(API:GetGossipOptions()) for i = self.idx, #self.Buttons do self.Buttons[i]:Hide() end self:UpdateActive() end function Titles:UpdateAvailableQuests(data) for i, quest in ipairs(data) do local button = self:GetButton(self.idx) ---------------------------------- local typeOfQ = (quest.isTrivial and TRIVIAL_QUEST_DISPLAY) button:SetFormattedText(typeOfQ or NORMAL_QUEST_DISPLAY, quest.title) ---------------------------------- local icon, useAtlas = API:GetQuestIconOffer(quest) button:SetIcon(icon, typeOfQ and 0.5, useAtlas) ---------------------------------- button:SetPriority(P_AVAILABLE_QUEST) ---------------------------------- button:SetID(API.IsWoW10 and quest.questID or i) button.type = 'Available' ---------------------------------- self.idx = self.idx + 1 end end function Titles:UpdateActiveQuests(data) self.hasActiveQuests = (#data > 0) for i, quest in ipairs(data) do local button = self:GetButton(self.idx) ---------------------------------- local typeOfQ = (quest.isTrivial and TRIVIAL_QUEST_DISPLAY) button:SetFormattedText(typeOfQ or NORMAL_QUEST_DISPLAY, quest.title) ---------------------------------- local icon, useAtlas = API:GetQuestIconActive(quest) button:SetIcon(icon, typeOfQ and 0.5, useAtlas) ---------------------------------- button:SetPriority(quest.isComplete and P_COMPLETE_QUEST or P_INCOMPLETE_QUEST) ---------------------------------- button:SetID(API.IsWoW10 and quest.questID or i) button:SetType('Active') ---------------------------------- self.idx = self.idx + 1 end end function Titles:UpdateGossipOptions(data) for i, option in ipairs(data) do local button = self:GetButton(self.idx) ---------------------------------- button:SetText(option.name) button:SetGossipIcon(option.type or option.icon) button:SetPriority(P_AVAILABLE_GOSSIP) ---------------------------------- button:SetID(API:GetGossipOptionID(option)) button:SetType('Gossip') ---------------------------------- self.idx = self.idx + 1 end end function Titles:UNIT_QUEST_LOG_CHANGED() if self:IsVisible() then if ( self.type == 'Gossip' and self.hasActiveQuests ) then self:Hide() self:GOSSIP_SHOW() elseif ( self.type == 'Quests' ) then self:Hide() self:QUEST_GREETING() end end end ---------------------------------- -- Quest ---------------------------------- function Titles:QUEST_GREETING() self.idx = 1 self.type = 'Quests' self:Show() self:UpdateActiveGreetingQuests(API:GetNumActiveQuests()) self:UpdateAvailableGreetingQuests(API:GetNumAvailableQuests()) for i = self.idx, #self.Buttons do self.Buttons[i]:Hide() end self:UpdateActive() end function Titles:UpdateActiveGreetingQuests(numActiveQuests) for i=1, numActiveQuests do local button = self:GetButton(self.idx) local title, isComplete = GetActiveTitle(i) ---------------------------------- local qType = ( IsActiveQuestTrivial(i) and TRIVIAL_QUEST_DISPLAY ) button:SetFormattedText(qType or NORMAL_QUEST_DISPLAY, title) ---------------------------------- local icon = ( isComplete and API:IsActiveQuestLegendary(i) and 'ActiveLegendaryQuestIcon' ) or ( isComplete and 'ActiveQuestIcon') or ( 'InCompleteQuestIcon' ) button:SetGossipQuestIcon(icon, qType and 0.75) button:SetPriority(isComplete and P_COMPLETE_QUEST or P_INCOMPLETE_QUEST) ---------------------------------- button:SetID(i) button.type = 'ActiveQuest' ---------------------------------- self.idx = self.idx + 1 end end function Titles:UpdateAvailableGreetingQuests(numAvailableQuests) for i=1, numAvailableQuests do local button = self:GetButton(self.idx) local title = GetAvailableTitle(i) local isTrivial, frequency, isRepeatable, isLegendary, questID = API:GetAvailableQuestInfo(i) ---------------------------------- local qType = ( isTrivial and TRIVIAL_QUEST_DISPLAY ) button:SetFormattedText(qType or NORMAL_QUEST_DISPLAY, title) ---------------------------------- local icon = ( isLegendary and 'AvailableLegendaryQuestIcon' ) or ( frequency == LE_QUEST_FREQUENCY_DAILY and 'DailyQuestIcon') or ( frequency == LE_QUEST_FREQUENCY_WEEKLY and 'DailyQuestIcon' ) or ( isRepeatable and 'DailyActiveQuestIcon' ) or ( 'AvailableQuestIcon' ) button:SetGossipQuestIcon(icon, qType and 0.5) button:SetPriority(P_AVAILABLE_QUEST) ---------------------------------- button:SetID(i) button.type = 'AvailableQuest' ---------------------------------- self.idx = self.idx + 1 end end