Files
andrew6180 1e9fa2aaca init
2023-04-16 00:31:14 -07:00

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