670 lines
31 KiB
Lua
670 lines
31 KiB
Lua
setfenv(1, VoiceOver)
|
|
SoundQueueUI = {}
|
|
SoundQueueUI.__index = SoundQueueUI
|
|
|
|
local LibDataBroker = LibStub("LibDataBroker-1.1")
|
|
local LibDBIcon = LibStub("LibDBIcon-1.0")
|
|
|
|
local PORTRAIT_SIZE = 120
|
|
local PORTRAIT_ATLAS_SIZE = 512
|
|
local PORTRAIT_ATLAS_BORDER_SIZE = 416
|
|
local PORTRAIT_ATLAS_VIEWPORT_SIZE = 348
|
|
local PORTRAIT_BORDER_SCALE = PORTRAIT_SIZE / PORTRAIT_ATLAS_VIEWPORT_SIZE
|
|
local PORTRAIT_BORDER_SIZE = PORTRAIT_ATLAS_BORDER_SIZE * PORTRAIT_BORDER_SCALE
|
|
local PORTRAIT_BORDER_OUTSET = 34 * PORTRAIT_BORDER_SCALE
|
|
local PORTRAIT_LINE_WIDTH = 56 * PORTRAIT_BORDER_SCALE
|
|
local FRAME_WIDTH_WITHOUT_PORTRAIT = 300
|
|
local HIDE_GOSSIP_OPTIONS = true -- Disable to allow gossip options to show up in the button list, like quests
|
|
local WAIT_FOR_ANIMATION_FINISH_BEFORE_IDLE = true
|
|
|
|
do
|
|
local font = CreateFont("VoiceOverNameFont")
|
|
font:SetFont(GameFontNormal:GetFont(), 19, "")
|
|
font:SetShadowColor(0, 0, 0)
|
|
font:SetShadowOffset(1, -1)
|
|
font:SetJustifyH("LEFT")
|
|
font:SetJustifyV("TOP")
|
|
end
|
|
do
|
|
local font = CreateFont("VoiceOverButtonFont")
|
|
font:SetFont(GameFontNormal:GetFont(), 16, "")
|
|
font:SetShadowColor(0, 0, 0)
|
|
font:SetShadowOffset(1, -1)
|
|
end
|
|
|
|
function SoundQueueUI:new(soundQueue)
|
|
local self = {}
|
|
setmetatable(self, SoundQueueUI)
|
|
|
|
self.soundQueue = soundQueue
|
|
|
|
self:InitDisplay()
|
|
self:InitPortraitLine()
|
|
self:InitPortrait()
|
|
self:InitMover()
|
|
self:InitMinimapButton()
|
|
|
|
self:RefreshConfig()
|
|
|
|
return self
|
|
end
|
|
|
|
function SoundQueueUI:InitDisplay()
|
|
local soundQueueUI = self
|
|
|
|
self.frame = CreateFrame("Frame", "VoiceOverFrame", UIParent)
|
|
function self.frame:Reset()
|
|
self:SetWidth(PORTRAIT_SIZE + FRAME_WIDTH_WITHOUT_PORTRAIT)
|
|
self:SetHeight(PORTRAIT_SIZE)
|
|
self:ClearAllPoints()
|
|
self:SetPoint("BOTTOM", 0, 280)
|
|
end
|
|
self.frame:Reset()
|
|
self.frame:SetMovable(true) -- Allow the frame to be moved
|
|
self.frame:SetResizable(true) -- Allow the frame to be resized
|
|
self.frame:SetClampedToScreen(true) -- Prevent from being dragged off-screen
|
|
self.frame:SetUserPlaced(true)
|
|
self.frame:SetFrameStrata(Addon.db.profile.SoundQueueUI.FrameStrata)
|
|
|
|
-- Create a background gradient behind the queue container
|
|
self.frame.background = self.frame:CreateTexture(nil, "BACKGROUND")
|
|
self.frame.background:SetPoint("RIGHT")
|
|
self.frame.background:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\BackgroundGradient]])
|
|
|
|
-- Create a button to resize the main frame
|
|
self.frame.resizer = CreateFrame("Button", nil, self.frame)
|
|
self.frame.resizer:SetPoint("BOTTOMRIGHT")
|
|
self.frame.resizer:SetSize(16, 16)
|
|
self.frame.resizer:SetNormalTexture([[Interface\AddOns\AI_VoiceOver\Textures\SizeGrabber-Up]])
|
|
self.frame.resizer:SetPushedTexture([[Interface\AddOns\AI_VoiceOver\Textures\SizeGrabber-Down]])
|
|
self.frame.resizer:SetHighlightTexture([[Interface\AddOns\AI_VoiceOver\Textures\SizeGrabber-Highlight]])
|
|
self.frame.resizer:HookScript("OnEnter", function() SetCursor([[Interface\Cursor\UI-Cursor-SizeRight]]) end)
|
|
self.frame.resizer:HookScript("OnLeave", function() SetCursor(nil) end)
|
|
self.frame.resizer:HookScript("OnMouseDown", function()
|
|
self.frame.resizer:GetHighlightTexture():Hide()
|
|
self.frame:StartSizing("BOTTOMRIGHT")
|
|
end)
|
|
self.frame.resizer:HookScript("OnMouseUp", function()
|
|
self.frame.resizer:GetHighlightTexture():Show()
|
|
self.frame:StopMovingOrSizing()
|
|
end)
|
|
|
|
-- Creature queue buttons container
|
|
self.frame.container = CreateFrame("Frame", nil, self.frame)
|
|
self.frame.container:SetPoint("RIGHT")
|
|
self.frame.container.buttons = {}
|
|
function self.frame.container.buttons:Update()
|
|
for _, button in ipairs(self) do
|
|
button:Update()
|
|
end
|
|
end
|
|
|
|
-- Create NPC name text
|
|
local SKIP_GOSSIP_BUTTON_OFFSET = -5
|
|
self.frame.container.name = self.frame.container:CreateFontString(nil, "ARTWORK", "VoiceOverNameFont")
|
|
self.frame.container.name:SetPoint("TOPLEFT")
|
|
self.frame.container.name:SetWordWrap(false)
|
|
self.frame.container.name:SetTextColor(214 / 255, 214 / 255, 214 / 255)
|
|
function self.frame.container.name:Update()
|
|
self:SetWidth(0)
|
|
self:SetText(self:GetText())
|
|
self:SetWidth(math.min(self:GetParent():GetWidth() - (soundQueueUI.frame.container.stopGossip:IsShown() and 32 + SKIP_GOSSIP_BUTTON_OFFSET or 0), self:GetStringWidth()))
|
|
end
|
|
|
|
-- Create Stop Gossip button
|
|
self.frame.container.stopGossip = CreateFrame("Button", nil, self.frame.container)
|
|
self.frame.container.stopGossip:SetSize(32, 32)
|
|
self.frame.container.stopGossip:SetPoint("BOTTOMLEFT", self.frame.container.name, "RIGHT", SKIP_GOSSIP_BUTTON_OFFSET, 0)
|
|
function self.frame.container.stopGossip:SetGossipCount(gossipCount)
|
|
local texture = gossipCount > 1 and [[Interface\AddOns\AI_VoiceOver\Textures\StopGossipMore]] or [[Interface\AddOns\AI_VoiceOver\Textures\StopGossip]]
|
|
self:SetShown(gossipCount > 0)
|
|
self:EnableMouse(soundQueueUI.soundQueue:CanBePaused() or gossipCount > 1)
|
|
self:SetHighlightTexture(texture, "ADD")
|
|
self:SetNormalTexture(texture)
|
|
self:SetPushedTexture(texture)
|
|
|
|
self.tooltip = soundQueueUI.soundQueue:CanBePaused() and (gossipCount > 1 and "Next Gossip" or "Stop Gossip") or "Skip Remaining Gossips"
|
|
if GameTooltip:GetOwner() == self then
|
|
GameTooltip:SetText(self.tooltip)
|
|
GameTooltip:Show()
|
|
end
|
|
end
|
|
self.frame.container.stopGossip:SetGossipCount(0)
|
|
self.frame.container.stopGossip:GetHighlightTexture():SetAlpha(0.5)
|
|
self.frame.container.stopGossip:GetPushedTexture():SetAlpha(0.5)
|
|
self.frame.container.stopGossip:HookScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_NONE")
|
|
GameTooltip:SetPoint("LEFT", self, "RIGHT")
|
|
GameTooltip:SetText(self.tooltip)
|
|
GameTooltip:Show()
|
|
end)
|
|
self.frame.container.stopGossip:HookScript("OnLeave", GameTooltip_Hide)
|
|
self.frame.container.stopGossip:HookScript("OnClick", function()
|
|
PlaySound(SOUNDKIT.CHAT_SCROLL_BUTTON)
|
|
if soundQueueUI.soundQueue:CanBePaused() then
|
|
-- Skip current
|
|
local soundData = self.soundQueue.sounds[1]
|
|
if soundData and Enums.SoundEvent:IsGossipEvent(soundData.event) then
|
|
self.soundQueue:RemoveSoundFromQueue(soundData)
|
|
end
|
|
else
|
|
-- Skip all remaining
|
|
local soundData = self.soundQueue.sounds[2]
|
|
while soundData and Enums.SoundEvent:IsGossipEvent(soundData.event) do
|
|
self.soundQueue:RemoveSoundFromQueue(soundData)
|
|
soundData = self.soundQueue.sounds[2]
|
|
end
|
|
end
|
|
end)
|
|
|
|
self.frame:HookScript("OnSizeChanged", function()
|
|
self.frame.container.name:Update()
|
|
self.frame.container.buttons:Update()
|
|
end)
|
|
end
|
|
|
|
function SoundQueueUI:InitPortraitLine()
|
|
-- Create a vertical line that will be visible instead of the portrait if the player turned the portrait off
|
|
self.frame.portraitLine = self.frame:CreateTexture(nil, "BORDER")
|
|
self.frame.portraitLine:SetPoint("TOPLEFT", -PORTRAIT_LINE_WIDTH / 2 + 2, PORTRAIT_BORDER_OUTSET)
|
|
self.frame.portraitLine:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMLEFT", PORTRAIT_LINE_WIDTH / 2 + 2, -PORTRAIT_BORDER_OUTSET)
|
|
self.frame.portraitLine:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.portraitLine:SetTexCoord(456 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE, 0, PORTRAIT_ATLAS_BORDER_SIZE / PORTRAIT_ATLAS_SIZE)
|
|
|
|
-- Create a play/pause button on the vertical line that will be visible if the player turned the portrait off
|
|
self.frame.miniPause = CreateFrame("Button", nil, self.frame)
|
|
self.frame.miniPause:SetSize(26, 26)
|
|
--self.frame.miniPause:SetPoint("CENTER", self.frame.container.name, "LEFT", -20 + 2, 0) -- Use this to make the button be placed next to NPC name instead of always centered
|
|
self.frame.miniPause:SetPoint("CENTER", self.frame.container, "LEFT", -20 + 2, 0)
|
|
self.frame.miniPause:SetNormalTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.miniPause:GetNormalTexture():ClearAllPoints()
|
|
self.frame.miniPause:GetNormalTexture():SetPoint("CENTER")
|
|
self.frame.miniPause:GetNormalTexture():SetSize(14, 14)
|
|
self.frame.miniPause:SetPushedTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.miniPause:GetPushedTexture():ClearAllPoints()
|
|
self.frame.miniPause:GetPushedTexture():SetPoint("CENTER")
|
|
self.frame.miniPause:GetPushedTexture():SetSize(12, 12)
|
|
self.frame.miniPause.background = self.frame.miniPause:CreateTexture(nil, "BACKGROUND")
|
|
self.frame.miniPause.background:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SettingsButton]])
|
|
self.frame.miniPause.background:SetPoint("CENTER")
|
|
self.frame.miniPause.background:SetSize(32, 32)
|
|
function self.frame.miniPause:Update()
|
|
if Addon.db.char.IsPaused then
|
|
self:GetNormalTexture():SetTexCoord(0 / PORTRAIT_ATLAS_SIZE, 93 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetPushedTexture():SetTexCoord(0 / PORTRAIT_ATLAS_SIZE, 93 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetNormalTexture():SetAlpha(MouseIsOver(self) and 1 or 0.75)
|
|
else
|
|
self:GetNormalTexture():SetTexCoord(93 / PORTRAIT_ATLAS_SIZE, 186 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetPushedTexture():SetTexCoord(93 / PORTRAIT_ATLAS_SIZE, 186 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetNormalTexture():SetAlpha(MouseIsOver(self) and 1 or 0.75)
|
|
end
|
|
end
|
|
self.frame.miniPause:Update()
|
|
self.frame.miniPause:HookScript("OnEnter", function(self)
|
|
self:GetNormalTexture():SetAlpha(1)
|
|
end)
|
|
self.frame.miniPause:HookScript("OnLeave", function(self)
|
|
self:GetNormalTexture():SetAlpha(0.75)
|
|
end)
|
|
self.frame.miniPause:HookScript("OnClick", function()
|
|
PlaySound(SOUNDKIT.CHAT_SCROLL_BUTTON)
|
|
self.soundQueue:TogglePauseQueue()
|
|
end)
|
|
end
|
|
|
|
local function ShouldShowBookForGUID(guid)
|
|
local type = guid and Utils:GetGUIDType(guid)
|
|
if not type then
|
|
return true -- A fallback in case the GUID is missing
|
|
elseif type == Enums.GUID.Item then
|
|
return true -- Maybe display the item icon in the future
|
|
elseif type == Enums.GUID.GameObject then
|
|
return true -- Maybe display the object model in the future
|
|
end
|
|
return false
|
|
end
|
|
|
|
function SoundQueueUI:InitPortrait()
|
|
local soundQueueUI = self
|
|
|
|
-- Create a container frame for the portrait
|
|
self.frame.portrait = CreateFrame("Frame", nil, self.frame)
|
|
self.frame.portrait:SetPoint("TOPLEFT")
|
|
self.frame.portrait:SetSize(PORTRAIT_SIZE, PORTRAIT_SIZE)
|
|
function self.frame.portrait:Configure(soundData)
|
|
if not self:IsShown() then
|
|
return
|
|
end
|
|
|
|
if not soundData then
|
|
self.model:Hide()
|
|
self.book:Hide()
|
|
elseif ShouldShowBookForGUID(soundData.unitGUID) then
|
|
self.model:Hide()
|
|
self.book:Show()
|
|
else
|
|
self.model:Show()
|
|
self.book:Hide()
|
|
|
|
local creatureID = Utils:GetIDFromGUID(soundData.unitGUID)
|
|
|
|
if creatureID ~= self.model.oldCreatureID then
|
|
self.model:SetCreature(creatureID)
|
|
self.model:SetCustomCamera(0)
|
|
|
|
self.model.animation = 60
|
|
self.model.animDuration = nil
|
|
self.model.animDelay = soundData.delay
|
|
self.model.animtimer = nil
|
|
|
|
self.model.oldCreatureID = creatureID
|
|
elseif self.model.wasPaused then
|
|
self.model.animation = 60
|
|
self.model.animDelay = soundData.delay
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Create a background behind the model
|
|
self.frame.portrait.background = self.frame.portrait:CreateTexture(nil, "BACKGROUND")
|
|
self.frame.portrait.background:SetAllPoints()
|
|
self.frame.portrait.background:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameBackground]])
|
|
|
|
-- Create a 3D model
|
|
self.frame.portrait.model = CreateFrame("DressUpModel", nil, self.frame.portrait)
|
|
self.frame.portrait.model:SetAllPoints()
|
|
self.frame.portrait.model:HookScript("OnHide", function(self)
|
|
self:ClearModel()
|
|
self.oldCreatureID = nil
|
|
self.animation = nil
|
|
self.animDuration = nil
|
|
self.animDelay = nil
|
|
self.animtimer = nil
|
|
end)
|
|
self.frame.portrait.model:HookScript("OnUpdate", function(self, elapsed)
|
|
-- Refresh camera and animation in case the model wasn't loaded instantly
|
|
self:SetCustomCamera(0)
|
|
if self.animation and not self.animDuration then
|
|
self.animDuration = Utils:GetModelAnimationDuration(self:GetModelFileID(), self.animation)
|
|
end
|
|
-- Wait out the delay, if any
|
|
if self.animDelay and not Addon.db.char.IsPaused then
|
|
self.animDelay = self.animDelay - elapsed
|
|
if self.animDelay < 0 then
|
|
self.animDelay = nil
|
|
else
|
|
return
|
|
end
|
|
end
|
|
local isPaused = not soundQueueUI.soundQueue:IsPlaying()
|
|
if not WAIT_FOR_ANIMATION_FINISH_BEFORE_IDLE and self.animation and self.animation ~= 0 and not self.animDelay and isPaused then
|
|
-- Switch to idle animation as soon as the VO is paused
|
|
self.animation = 0
|
|
self.animtimer = nil
|
|
self:SetAnimation(self.animation)
|
|
end
|
|
-- Loop the animation when the timer has reached the animation duration
|
|
if self.animation and GetTime() - (self.animtimer or 0) >= (self.animDuration or 2) then
|
|
if isPaused then
|
|
if WAIT_FOR_ANIMATION_FINISH_BEFORE_IDLE and self.animation ~= 0 and not self.animDelay then
|
|
-- Switch to idle animation after the current animation is finished
|
|
self.animation = 0
|
|
self.animtimer = nil
|
|
self:SetAnimation(self.animation)
|
|
end
|
|
else
|
|
-- Restart the current animation
|
|
self.animtimer = GetTime()
|
|
self:SetAnimation(self.animation)
|
|
end
|
|
end
|
|
self.wasPaused = isPaused
|
|
end)
|
|
|
|
-- Create a book icon replacement when the 3D portrait is unavailable
|
|
self.frame.portrait.book = self.frame.portrait:CreateTexture(nil, "ARTWORK")
|
|
self.frame.portrait.book:SetAllPoints()
|
|
self.frame.portrait.book:SetTexture([[Interface\Icons\INV_Misc_Book_09]])
|
|
self.frame.portrait.book:Hide()
|
|
|
|
-- Create a play/pause button with a semi-transparent background (mimicing the portrait frame's background to create an illusion of the 3D model becoming semi-transparent)
|
|
self.frame.portrait.pause = CreateFrame("Button", nil, self.frame.portrait)
|
|
self.frame.portrait.pause:SetFrameLevel(self.frame.portrait.model:GetFrameLevel() + 1)
|
|
self.frame.portrait.pause:SetAllPoints()
|
|
self.frame.portrait.pause.background = self.frame.portrait.pause:CreateTexture(nil, "BACKGROUND")
|
|
self.frame.portrait.pause.background:SetAllPoints()
|
|
self.frame.portrait.pause.background:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameBackground]])
|
|
self.frame.portrait.pause.background:SetAlpha(0.75)
|
|
self.frame.portrait.pause:SetNormalTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.portrait.pause:GetNormalTexture():ClearAllPoints()
|
|
self.frame.portrait.pause:GetNormalTexture():SetPoint("CENTER")
|
|
self.frame.portrait.pause:GetNormalTexture():SetSize(32, 32)
|
|
self.frame.portrait.pause:SetPushedTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.portrait.pause:GetPushedTexture():ClearAllPoints()
|
|
self.frame.portrait.pause:GetPushedTexture():SetPoint("CENTER")
|
|
self.frame.portrait.pause:GetPushedTexture():SetSize(28, 28)
|
|
function self.frame.portrait.pause:Update()
|
|
if Addon.db.char.IsPaused then
|
|
if soundQueueUI.soundQueue:IsPlaying() then
|
|
self.background:Hide()
|
|
else
|
|
self.background:Show()
|
|
end
|
|
self:GetNormalTexture():SetTexCoord(0 / PORTRAIT_ATLAS_SIZE, 93 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetPushedTexture():SetTexCoord(0 / PORTRAIT_ATLAS_SIZE, 93 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetNormalTexture():SetAlpha(MouseIsOver(self) and 1 or 0.75)
|
|
else
|
|
self.background:Hide()
|
|
self:GetNormalTexture():SetTexCoord(93 / PORTRAIT_ATLAS_SIZE, 186 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetPushedTexture():SetTexCoord(93 / PORTRAIT_ATLAS_SIZE, 186 / PORTRAIT_ATLAS_SIZE, 419 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self:GetNormalTexture():SetAlpha(MouseIsOver(self) and 1 or 0)
|
|
end
|
|
end
|
|
self.frame.portrait.pause:Update()
|
|
self.frame.portrait.pause:HookScript("OnEnter", function(self)
|
|
self:GetNormalTexture():SetAlpha(1)
|
|
end)
|
|
self.frame.portrait.pause:HookScript("OnLeave", function(self)
|
|
self:GetNormalTexture():SetAlpha(Addon.db.char.IsPaused and 0.75 or 0)
|
|
end)
|
|
self.frame.portrait.pause:HookScript("OnClick", function()
|
|
PlaySound(SOUNDKIT.CHAT_SCROLL_BUTTON)
|
|
self.soundQueue:TogglePauseQueue()
|
|
end)
|
|
|
|
-- Create an overlay frame above the 3D model to contain the border and any other button that might be placed on the border (like the mover)
|
|
self.frame.portrait.border = CreateFrame("Frame", nil, self.frame.portrait) -- Separate frame to ensure that all contained frames will be drawn over the model
|
|
self.frame.portrait.border:SetFrameLevel(self.frame.portrait.pause:GetFrameLevel() + 1)
|
|
self.frame.portrait.border:SetAllPoints()
|
|
self.frame.portrait.border.texture = self.frame.portrait.border:CreateTexture(nil, "BORDER")
|
|
self.frame.portrait.border.texture:SetSize(PORTRAIT_BORDER_SIZE, PORTRAIT_BORDER_SIZE)
|
|
self.frame.portrait.border.texture:SetPoint("TOPLEFT", -PORTRAIT_BORDER_OUTSET, PORTRAIT_BORDER_OUTSET)
|
|
self.frame.portrait.border.texture:SetPoint("BOTTOMRIGHT", PORTRAIT_BORDER_OUTSET, -PORTRAIT_BORDER_OUTSET)
|
|
self.frame.portrait.border.texture:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.portrait.border.texture:SetTexCoord(0, PORTRAIT_ATLAS_BORDER_SIZE / PORTRAIT_ATLAS_SIZE, 0, PORTRAIT_ATLAS_BORDER_SIZE / PORTRAIT_ATLAS_SIZE)
|
|
end
|
|
|
|
function SoundQueueUI:InitMover()
|
|
-- Create a button that lets the player drag the frame around
|
|
self.frame.mover = CreateFrame("Button", nil, self.frame.portrait.border)
|
|
self.frame.mover:SetSize(26, 26)
|
|
self.frame.mover:SetPoint("CENTER", self.frame.portrait.border, "BOTTOMLEFT", 5, 6)
|
|
self.frame.mover:SetNormalTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.mover:GetNormalTexture():SetTexCoord(462 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE, 462 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self.frame.mover:GetNormalTexture():ClearAllPoints()
|
|
self.frame.mover:GetNormalTexture():SetPoint("CENTER")
|
|
self.frame.mover:GetNormalTexture():SetSize(16, 16)
|
|
self.frame.mover:SetPushedTexture([[Interface\AddOns\AI_VoiceOver\Textures\PortraitFrameAtlas]])
|
|
self.frame.mover:GetPushedTexture():SetTexCoord(462 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE, 462 / PORTRAIT_ATLAS_SIZE, 512 / PORTRAIT_ATLAS_SIZE)
|
|
self.frame.mover:GetPushedTexture():ClearAllPoints()
|
|
self.frame.mover:GetPushedTexture():SetPoint("CENTER")
|
|
self.frame.mover:GetPushedTexture():SetSize(14, 14)
|
|
self.frame.mover.background = self.frame.mover:CreateTexture(nil, "BACKGROUND")
|
|
self.frame.mover.background:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SettingsButton]])
|
|
self.frame.mover.background:SetPoint("CENTER")
|
|
self.frame.mover.background:SetSize(32, 32)
|
|
self.frame.mover:HookScript("OnEnter", function(self)
|
|
if Addon.db.profile.SoundQueueUI.LockFrame then return end
|
|
SetCursor([[Interface\Cursor\UI-Cursor-Move]])
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetText("Move the Frame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
|
|
GameTooltip:AddLine("Frame position can be locked in settings.", NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
self.frame.mover:HookScript("OnLeave", function(self)
|
|
SetCursor(nil)
|
|
GameTooltip_Hide(self)
|
|
end)
|
|
self.frame.mover:HookScript("OnMouseDown", function()
|
|
if Addon.db.profile.SoundQueueUI.LockFrame then return end
|
|
self.frame:StartMoving()
|
|
end)
|
|
self.frame.mover:HookScript("OnMouseUp", function()
|
|
if Addon.db.profile.SoundQueueUI.LockFrame then return end
|
|
self.frame:StopMovingOrSizing()
|
|
end)
|
|
end
|
|
|
|
function SoundQueueUI:InitMinimapButton()
|
|
local buttons =
|
|
{
|
|
{ "LeftButton", "Left Click" },
|
|
{ "MiddleButton", "Middle Click" },
|
|
{ "RightButton", "Right Click" },
|
|
}
|
|
local object = LibDataBroker:NewDataObject("VoiceOver", {
|
|
type = "launcher",
|
|
text = "VoiceOver",
|
|
icon = [[Interface\AddOns\AI_VoiceOver\Textures\MinimapButton]],
|
|
|
|
OnClick = function(self, button)
|
|
local command = Addon.db.profile.MinimapButton.Commands[button]
|
|
if command and command ~= "" then
|
|
local handler = Options.table.args.SlashCommands.args[command]
|
|
if handler and handler.func then
|
|
PlaySound(SOUNDKIT.CHAT_SCROLL_BUTTON)
|
|
handler.func()
|
|
end
|
|
end
|
|
end,
|
|
|
|
OnTooltipShow = function(tooltip)
|
|
tooltip:SetText("VoiceOver")
|
|
for _, info in ipairs(buttons) do
|
|
local button, text = unpack(info)
|
|
local command = Addon.db.profile.MinimapButton.Commands[button]
|
|
if command and command ~= "" then
|
|
local handler = Options.table.args.SlashCommands.args[command]
|
|
if handler and handler.name then
|
|
tooltip:AddLine(format("%s%s:|r %s", GRAY_FONT_COLOR_CODE, text, handler.name))
|
|
end
|
|
end
|
|
end
|
|
tooltip:Show()
|
|
end,
|
|
})
|
|
LibDBIcon:Register("VoiceOver", object, Addon.db.profile.MinimapButton.LibDBIcon)
|
|
end
|
|
|
|
function SoundQueueUI:RefreshConfig()
|
|
if Addon.db.profile.SoundQueueUI.HidePortrait then
|
|
if self.frame.portrait:IsShown() then
|
|
self.frame:SetWidth(self.frame:GetWidth() - PORTRAIT_SIZE)
|
|
end
|
|
self.frame:SetResizeBounds(100, PORTRAIT_SIZE, 10000, PORTRAIT_SIZE)
|
|
|
|
self.frame.portraitLine:Show()
|
|
self.frame.portrait:Hide()
|
|
self.frame.miniPause:Show()
|
|
|
|
self.frame.container:SetPoint("LEFT", 20, 0)
|
|
self.frame.background:SetPoint("TOPLEFT")
|
|
self.frame.background:SetPoint("BOTTOMLEFT")
|
|
|
|
self.frame.mover:SetParent(self.frame)
|
|
self.frame.mover:SetPoint("CENTER", self.frame, "BOTTOMLEFT", 2, 6)
|
|
else
|
|
if not self.frame.portrait:IsShown() then
|
|
self.frame:SetWidth(self.frame:GetWidth() + PORTRAIT_SIZE)
|
|
end
|
|
self.frame:SetResizeBounds(PORTRAIT_SIZE + 100, PORTRAIT_SIZE, 10000, PORTRAIT_SIZE)
|
|
|
|
self.frame.portraitLine:Hide()
|
|
self.frame.portrait:Show()
|
|
self.frame.miniPause:Hide()
|
|
|
|
self.frame.container:SetPoint("LEFT", self.frame.portrait, "RIGHT", 15, 0)
|
|
self.frame.background:SetPoint("TOPLEFT", self.frame.portrait, "TOPRIGHT")
|
|
self.frame.background:SetPoint("BOTTOMLEFT", self.frame.portrait, "BOTTOMRIGHT")
|
|
|
|
self.frame.mover:SetParent(self.frame.portrait.border)
|
|
self.frame.mover:SetPoint("CENTER", self.frame.portrait.border, "BOTTOMLEFT", 5, 6)
|
|
end
|
|
|
|
self.frame.mover:SetShown(not Addon.db.profile.SoundQueueUI.LockFrame)
|
|
self.frame.resizer:SetShown(not Addon.db.profile.SoundQueueUI.LockFrame)
|
|
self.frame:SetScale(Addon.db.profile.SoundQueueUI.FrameScale)
|
|
|
|
self:UpdateSoundQueueDisplay()
|
|
LibDBIcon:Refresh("VoiceOver", Addon.db.profile.MinimapButton.LibDBIcon)
|
|
end
|
|
|
|
function SoundQueueUI:CreateButton(i)
|
|
local soundQueueUI = self
|
|
|
|
local button = CreateFrame("Button", nil, self.frame.container)
|
|
self.frame.container.buttons[i] = button
|
|
|
|
button:SetID(i)
|
|
button:SetHeight(20)
|
|
|
|
button.textWidget = button:CreateFontString(nil, "OVERLAY", "VoiceOverButtonFont")
|
|
button.textWidget:SetJustifyH("LEFT")
|
|
button.textWidget:SetWordWrap(false)
|
|
|
|
button.iconWidget = button:CreateTexture(nil, "ARTWORK")
|
|
button.iconWidget:SetSize(16, 16)
|
|
button.iconWidget:SetPoint("CENTER", button, "LEFT", 16 / 2, 0)
|
|
|
|
function button:Configure(soundData)
|
|
self.soundData = soundData
|
|
self:Update()
|
|
end
|
|
function button:Update(pushed, hovered)
|
|
if pushed == nil then pushed = self.pushed else self.pushed = pushed end
|
|
if hovered == nil then hovered = self.hovered else self.hovered = hovered end
|
|
local soundData = self.soundData
|
|
if not soundData then
|
|
self:Hide()
|
|
return
|
|
end
|
|
self:Show()
|
|
local soundDataBeingPlayed = soundQueueUI.soundQueue.sounds[1]
|
|
local isBeingPlayed = soundData == soundDataBeingPlayed
|
|
local buttonIndex = self:GetID()
|
|
|
|
if isBeingPlayed then
|
|
self:SetAlpha(1)
|
|
self.textWidget:SetShadowColor(0, 0, 0, 1)
|
|
self:SetPoint("TOPLEFT", soundQueueUI.frame.container.name, "BOTTOMLEFT", 0, -2)
|
|
self:EnableMouse(soundQueueUI.soundQueue:CanBePaused())
|
|
else
|
|
local isCollapsedGossipBeingPlayed = soundDataBeingPlayed and Enums.SoundEvent:IsGossipEvent(soundDataBeingPlayed.event) and (HIDE_GOSSIP_OPTIONS or not soundDataBeingPlayed.title)
|
|
local queuePosition = buttonIndex - (isCollapsedGossipBeingPlayed and 0 or 1)
|
|
local alpha = math.max(0.1, math.min(1, 1 - (queuePosition - 1) / 3))
|
|
self:SetAlpha(alpha)
|
|
self.textWidget:SetShadowColor(0, 0, 0, 0.5 + 0.5 * alpha) -- Technically isn't necessary, but it looks better this way
|
|
self:SetPoint("TOPLEFT", soundQueueUI.frame.container.buttons[buttonIndex - 1] or soundQueueUI.frame.container.name, "BOTTOMLEFT", 0, queuePosition == 1 and -8 or -2)
|
|
self:EnableMouse(true)
|
|
end
|
|
|
|
self.textWidget:ClearAllPoints()
|
|
self.textWidget:SetPoint("LEFT", 16 + 5, 0)
|
|
self.textWidget:SetText(soundData.title)
|
|
self:SetWidth(math.min(self:GetParent():GetWidth(), 16 + 5 + self.textWidget:GetWidth()))
|
|
self.textWidget:SetPoint("RIGHT")
|
|
|
|
if hovered then
|
|
local r, g, b = 225 / 255, 20 / 255, 8 / 255
|
|
if pushed then
|
|
r, g, b = r * 0.75, g * 0.75, b * 0.75
|
|
end
|
|
self:SetAlpha(1)
|
|
self.textWidget:SetTextColor(r, g, b)
|
|
self.textWidget:SetShadowColor(0, 0, 0, 1)
|
|
self.iconWidget:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SoundQueueBulletDelete]])
|
|
self.iconWidget:SetSize(14, 14)
|
|
else
|
|
if isBeingPlayed then
|
|
local event = soundData.event
|
|
if Enums.SoundEvent:IsQuestEvent(event) then
|
|
self.textWidget:SetTextColor(245 / 255, 204 / 255, 24 / 255)
|
|
if event == Enums.SoundEvent.QuestAccept then
|
|
self.iconWidget:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SoundQueueBulletAccept]])
|
|
elseif event == Enums.SoundEvent.QuestProgress then
|
|
self.iconWidget:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SoundQueueBulletProgress]])
|
|
elseif event == Enums.SoundEvent.QuestComplete then
|
|
self.iconWidget:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SoundQueueBulletComplete]])
|
|
end
|
|
elseif Enums.SoundEvent:IsGossipEvent(event) then
|
|
self.textWidget:SetTextColor(1, 1, 1)
|
|
self.iconWidget:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SoundQueueBulletGossip]])
|
|
end
|
|
self.iconWidget:SetSize(14, 14)
|
|
else
|
|
self.textWidget:SetTextColor(123 / 255, 147 / 255, 167 / 255)
|
|
self.iconWidget:SetTexture([[Interface\AddOns\AI_VoiceOver\Textures\SoundQueueBulletQueue]])
|
|
self.iconWidget:SetSize(22, 22)
|
|
end
|
|
end
|
|
end
|
|
|
|
button:HookScript("OnClick", function(self) soundQueueUI.soundQueue:RemoveSoundFromQueue(self.soundData) end)
|
|
button:HookScript("OnMouseDown", function(self) self:Update(true) end)
|
|
button:HookScript("OnMouseUp", function(self) self:Update(false) end)
|
|
button:HookScript("OnEnter", function(self) self:Update(nil, true) end)
|
|
button:HookScript("OnLeave", function(self) self:Update(nil, false) end)
|
|
button:Update()
|
|
|
|
return button
|
|
end
|
|
|
|
function SoundQueueUI:UpdateSoundQueueDisplay()
|
|
self.frame:SetShown(not Addon.db.profile.SoundQueueUI.HideFrame and #self.soundQueue.sounds > 0)
|
|
|
|
self:UpdatePauseDisplay()
|
|
|
|
self.frame.portrait:Configure(self.soundQueue.sounds[1])
|
|
|
|
self.frame.container:Show()
|
|
self.frame.container:SetHeight(self.frame:GetHeight())
|
|
local gossipCount
|
|
local lastButtonIndex = 0
|
|
local lastContent
|
|
local nameSet
|
|
for i, soundData in ipairs(self.soundQueue.sounds) do
|
|
if not nameSet then
|
|
nameSet = true
|
|
self.frame.container.name:SetText(soundData.name)
|
|
lastContent = self.frame.container.name
|
|
end
|
|
if not Enums.SoundEvent:IsGossipEvent(soundData.event) or (not HIDE_GOSSIP_OPTIONS and soundData.title) then
|
|
if not gossipCount then
|
|
gossipCount = i - 1
|
|
end
|
|
lastButtonIndex = lastButtonIndex + 1
|
|
local button = self.frame.container.buttons[lastButtonIndex] or self:CreateButton(lastButtonIndex)
|
|
button:Configure(soundData)
|
|
lastContent = button
|
|
end
|
|
if lastButtonIndex == 4 then
|
|
break
|
|
end
|
|
end
|
|
for i = lastButtonIndex + 1, #self.frame.container.buttons do
|
|
self.frame.container.buttons[i]:Configure(nil)
|
|
end
|
|
|
|
self.frame.container.stopGossip:SetGossipCount(gossipCount or #self.soundQueue.sounds)
|
|
self.frame.container.name:Update()
|
|
|
|
-- Align the container vertically to the middle
|
|
if lastContent then
|
|
local contentTop = self.frame.container.name:GetTop()
|
|
local contentBottom = lastContent:GetBottom()
|
|
self.frame.container:SetHeight(contentTop - contentBottom)
|
|
else
|
|
self.frame.container:Hide()
|
|
end
|
|
-- Refresh again after updating layout (same frame in modern WoW, next frame in old WoW) to update name truncation and button hover state depending on the new button positions after realignment
|
|
Addon:ScheduleTimer(function()
|
|
self.frame.container.buttons:Update()
|
|
self.frame.container.name:Update()
|
|
end, 0)
|
|
end
|
|
|
|
function SoundQueueUI:UpdatePauseDisplay()
|
|
self.frame.miniPause:Update()
|
|
self.frame.portrait.pause:Update()
|
|
end
|