-- TalkingHeadFrame Revamp: Less intrudingIsWorldQuest
local _ , addon = ...
local API = addon.API ;
local L = addon.L ;
local FADE_OUT_AFTER_FINISH = 0.5 ;
local QUEST_DESCRIPTION_GRADIENT_LENGTH = 30 ;
local TEXT_WIDTH = 512 ;
local LINE_SPACING = 2 ;
local DEFAULT_POSITION_Y = 336 ;
local SPEECH_FORMAT_GENRIC = " |cffffd100%s: |r%s " ;
local SPEECH_FORMAT_PVP = " |cffff2020%s: |r%s " ;
local FadeFrame = API.UIFrameFade ;
local Lerp = API.Lerp ;
local Round = API.Round ;
local strlenutf8 = strlenutf8 ;
local ceil = math.ceil ;
local max = math.max ;
local format = string.format ;
local PlaySound = PlaySound ;
local StopSound = StopSound ;
local GetCurrentLineInfo = C_TalkingHead.GetCurrentLineInfo ;
local IsWorldQuest = C_QuestLog.IsWorldQuest ;
local IsQuestTask = C_QuestLog.IsQuestTask ;
local IsInInstance = IsInInstance ;
--local SetPortraitTextureFromCreatureDisplayID = SetPortraitTextureFromCreatureDisplayID;
local DB ;
local PVP_CREATURE_DISPLAYID = {
[ 108418 ] = true ,
[ 118482 ] = true , --Ruffious
} ;
local NewTalkingHead = CreateFrame ( " Frame " , nil , UIParent ) ;
NewTalkingHead : Hide ( ) ;
NewTalkingHead : SetFrameStrata ( " FULLSCREEN " ) ; --LOW
NewTalkingHead : SetFrameLevel ( 980 ) ;
NewTalkingHead : SetSize ( TEXT_WIDTH , 32 ) ;
--[[cause taint "UIParentBottomManagedFrameTemplate"
NewTalkingHead.layoutIndex = 1208 ;
NewTalkingHead.hideWhenActionBarIsOverriden = false ;
NewTalkingHead.align = " center " ;
--]]
addon.TalkingHead = NewTalkingHead ;
local function SetFontShadow ( fontString )
--Game Bug: Shadow is removed upon SetAlphaGradient
fontString : SetShadowColor ( 0 , 0 , 0 , 1 ) ;
fontString : SetShadowOffset ( 1 , - 1 ) ;
end
local function SetupFontString ( fontString )
fontString : SetJustifyH ( " CENTER " ) ;
fontString : SetJustifyV ( " TOP " ) ;
fontString : SetSpacing ( LINE_SPACING ) ;
SetFontShadow ( fontString ) ;
end
local function FadeOutAfter_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
if self.t >= self.fadeOutDelay then
self : FadeOutText ( true ) ;
end
end
local function FadeIn_TypeWriter_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
self.fadingProgress = self.fadingProgress + ( elapsed * self.gradientCPS ) ;
self.gradientLength = self.gradientLength + 10 * elapsed ;
if self.gradientLength > QUEST_DESCRIPTION_GRADIENT_LENGTH then
self.gradientLength = QUEST_DESCRIPTION_GRADIENT_LENGTH ;
end
if not self.LineText : SetAlphaGradient ( self.fadingProgress , self.gradientLength ) then
self : SetScript ( " OnUpdate " , FadeOutAfter_OnUpdate ) ;
return true
end
if self.t < self.backgroundFadeDuration then
self.Background : SetAlpha ( Lerp ( 0 , 1 , self.t / self.backgroundFadeDuration ) ) ;
end
end
local function FadeIn_InstantText_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
self.fadingProgress = self.fadingProgress + 4 * elapsed ;
if self.fadingProgress >= 1 then
self : SetScript ( " OnUpdate " , FadeOutAfter_OnUpdate ) ;
self.fadingProgress = 1 ;
self.LineText : SetAlpha ( 1 ) ;
self.Background : SetAlpha ( 1 ) ;
return true
end
self.LineText : SetAlpha ( self.fadingProgress ) ;
self.Background : SetAlpha ( self.fadingProgress ) ;
end
local function FadeOut_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
if self.t >= 0 then
self.textAlpha = self.textAlpha - 2 * elapsed ;
if self.textAlpha <= 0 then
self.textAlpha = 0 ;
self : Hide ( ) ;
self.isFadingOut = false ;
self : SetScript ( " OnUpdate " , nil ) ;
end
self.LineText : SetAlpha ( self.textAlpha ) ;
self.Background : SetAlpha ( self.textAlpha ) ;
end
end
function NewTalkingHead : SetText ( text )
self.LineText : SetText ( text ) ;
self.LineText : Show ( ) ;
local textWidth = self.LineText : GetWrappedWidth ( ) ;
local textHeight = self.LineText : GetHeight ( ) - ( self.fontHeight + LINE_SPACING ) ;
local numLines = self.LineText : GetNumLines ( ) + 1 ;
self.Background : ClearAllPoints ( ) ;
self.Background : SetPoint ( " CENTER " , self , " TOP " , 0 , - 0.5 * ( numLines * ( self.fontHeight + LINE_SPACING ) - LINE_SPACING ) ) ;
self.Background : SetSize ( textWidth + 32 , textHeight + 32 ) ;
self : UpdateFrameSize ( ) ;
end
function NewTalkingHead : FadeInText ( speakerName , text , voiceoverDuration , hideName , isFinalLine , displayInfo )
if not ( text and speakerName and voiceoverDuration ) then return end ;
if not hideName then
local speechFormat ;
--print(displayInfo, speakerName); --debug
if displayInfo and PVP_CREATURE_DISPLAYID [ displayInfo ] then
speechFormat = SPEECH_FORMAT_PVP ;
else
speechFormat = SPEECH_FORMAT_GENRIC ;
end
text = format ( speechFormat , speakerName , text ) ;
end
local numChars = strlenutf8 ( text ) ;
if numChars == 0 or voiceoverDuration == 0 then return end ;
numChars = numChars + 15 ;
text = " \n " .. text ;
self : SetText ( text ) ;
self.gradientCPS = ceil ( numChars / voiceoverDuration ) + 10 ;
self.fadingProgress = 0 ;
self.backgroundFadeDuration = max ( voiceoverDuration - 1 , 1 ) ;
self.t = 0 ;
self.gradientLength = QUEST_DESCRIPTION_GRADIENT_LENGTH ;
if isFinalLine then
self.fadeOutDelay = voiceoverDuration + 1 ;
else
self.fadeOutDelay = voiceoverDuration ;
end
self.isFadingOut = false ;
if self.instantText then
self.LineText : SetAlpha ( 0 ) ;
self.Background : SetAlpha ( 0 ) ;
self : SetScript ( " OnUpdate " , FadeIn_InstantText_OnUpdate ) ;
else
self.LineText : SetAlpha ( 1 ) ;
self.LineText : SetAlphaGradient ( 0 , QUEST_DESCRIPTION_GRADIENT_LENGTH ) ;
self.Background : SetAlpha ( 0 ) ;
self : SetScript ( " OnUpdate " , FadeIn_TypeWriter_OnUpdate ) ;
end
FadeFrame ( self , 0 , 1 ) ;
end
function NewTalkingHead : FadeOutText ( noDelay )
if self : IsShown ( ) then
if not self.isFadingOut then
self.textAlpha = self.LineText : GetAlpha ( ) ;
self.t = ( noDelay and 0 ) or - 1 ;
self : SetScript ( " OnUpdate " , FadeOut_OnUpdate ) ;
end
else
self.isFadingOut = false ;
self.LineText : Hide ( ) ;
self.LineText : SetAlpha ( 0 ) ;
self.textAlpha = 0 ;
self : SetScript ( " OnUpdate " , nil ) ;
end
end
function NewTalkingHead : SetFontHeightByPercentage ( percentage )
if not percentage then
percentage = 100 ;
end
if percentage < 100 then
percentage = 100 ;
elseif percentage > 120 then
percentage = 120 ;
end
local font , baseFontHeight = QuestFont : GetFont ( ) ;
local fontHeight = Round ( percentage * 0.01 * baseFontHeight ) ;
self.fontHeight = fontHeight ;
local style , gray ;
if DB.TalkingHead_TextOutline then
style = " OUTLINE " ;
gray = 0.898 ; --VERY_LIGHT_GRAY_COLOR
else
style = " " ;
gray = 1 ;
end
self.LineText : SetFont ( font , fontHeight , style ) ;
self.LineText : SetTextColor ( gray , gray , gray ) ;
SetupFontString ( self.LineText ) ;
DB.TalkingHead_FontSize = percentage ;
end
function NewTalkingHead : LoadPosition ( )
self : ClearAllPoints ( ) ;
if DB.TalkingHead_PositionX and DB.TalkingHead_PositionY then
if DB.TalkingHead_PositionX > 0 then
self : SetPoint ( " TOPLEFT " , UIParent , " BOTTOMLEFT " , DB.TalkingHead_PositionX , DB.TalkingHead_PositionY ) ;
else
self : SetPoint ( " TOP " , UIParent , " BOTTOM " , 0 , DB.TalkingHead_PositionY ) ;
end
else
self : SetPoint ( " TOP " , UIParent , " BOTTOM " , 0 , DEFAULT_POSITION_Y ) ;
end
end
function NewTalkingHead : Init ( )
DB = PlumberDB ;
self : LoadPosition ( ) ;
local _ , fontHeight = QuestFont : GetFont ( ) ;
self.baseFontHeight = Round ( fontHeight + 0.5 ) ;
self.fontHeight = self.baseFontHeight ;
self.LineText = NewTalkingHead : CreateFontString ( nil , " OVERLAY " , " QuestFont " ) ;
self.LineText : SetPoint ( " TOP " , self , " TOP " , 0 , 0 ) ;
self.LineText : SetWidth ( TEXT_WIDTH ) ;
self.LineText : SetAlpha ( 0 ) ;
self : SetFontHeightByPercentage ( DB.TalkingHead_FontSize ) ;
self.Background = self : CreateTexture ( nil , " BACKGROUND " ) ;
self.Background : SetTexture ( " Interface/AddOns/Plumber/Art/Frame/SubtitleShadow_NineSlice " ) ;
self.Background : SetTextureSliceMargins ( 30 , 30 , 30 , 30 ) ;
self.Background : SetTextureSliceMode ( 0 ) ;
self.Background : SetSize ( 128 , 32 ) ;
self.Background : SetPoint ( " CENTER " , self , " TOP " , 0 , 0 ) ;
--[[
self.Portrait = self : CreateTexture ( nil , " BACKGROUND " , nil , - 1 ) ;
self.Portrait : SetSize ( 115 , 115 ) ;
self.Portrait : SetPoint ( " CENTER " , self , " CENTER " , 0 , - 6 ) ;
--]]
self : OnSettingsChanged ( ) ;
self.Init = function ( ) end ;
end
function NewTalkingHead : WorldMapOnShow ( )
if not self.enabled then return end ;
if self.belowWorldMap then
if self : IsShown ( ) then
self : SetFrameStrata ( " MEDIUM " ) ;
end
end
end
function NewTalkingHead : WorldMapOnHide ( )
if not self.enabled then return end ;
if self.belowWorldMap then
if self : IsShown ( ) then
self : SetFrameStrata ( " FULLSCREEN " ) ;
end
end
end
function NewTalkingHead : EnableTalkingHead ( )
if self.enabled then return end ;
if self.blizzardTalkingHeadEnabled == nil then
self.blizzardTalkingHeadEnabled = TalkingHeadFrame : IsEventRegistered ( " TALKINGHEAD_REQUESTED " ) ;
end
TalkingHeadFrame : UnregisterEvent ( " TALKINGHEAD_REQUESTED " ) ;
self.enabled = true ;
self : Init ( ) ;
self : RegisterEvent ( " TALKINGHEAD_REQUESTED " ) ;
self : RegisterEvent ( " TALKINGHEAD_CLOSE " ) ;
self : RegisterEvent ( " LOADING_SCREEN_ENABLED " ) ;
self : RegisterEvent ( " PLAYER_ENTERING_WORLD " ) ;
self : SetScript ( " OnEvent " , self.OnEvent ) ;
end
function NewTalkingHead : DisableTalkingHead ( )
if self.enabled then
if self.blizzardTalkingHeadEnabled then
TalkingHeadFrame : RegisterEvent ( " TALKINGHEAD_REQUESTED " ) ;
end
self.blizzardTalkingHeadEnabled = nil ;
self.enabled = false ;
self : UnregisterEvent ( " TALKINGHEAD_REQUESTED " ) ;
self : UnregisterEvent ( " TALKINGHEAD_CLOSE " ) ;
self : UnregisterEvent ( " SOUNDKIT_FINISHED " ) ;
self : UnregisterEvent ( " LOADING_SCREEN_ENABLED " ) ;
self : UnregisterEvent ( " PLAYER_ENTERING_WORLD " ) ;
self : UnregisterEvent ( " QUEST_ACCEPTED " ) ;
self : UnregisterEvent ( " QUEST_TURNED_IN " ) ;
self : OnTalkingHeadClose ( ) ;
self : SetScript ( " OnEvent " , nil ) ;
end
end
function NewTalkingHead : TryDisable ( )
--Disable if not used in any other modules
if not DB then DB = PlumberDB end ;
if DB.TalkingHead_MasterSwitch then return end ;
self : DisableTalkingHead ( ) ;
end
function NewTalkingHead : OnTalkingHeadRequested ( )
if self.voHandle then
StopSound ( self.voHandle ) ;
self.voHandle = nil ;
end
local displayInfo , cameraID , vo , duration , lineNumber , numLines , name , text , isNewTalkingHead , textureKit = GetCurrentLineInfo ( ) ;
--print(name, displayInfo, vo, duration) --Debug
if displayInfo and displayInfo ~= 0 and duration then
local success , voHandle = PlaySound ( vo , " Talking Head " , true , true ) ;
if success then
self : RegisterEvent ( " SOUNDKIT_FINISHED " ) ;
self.voHandle = voHandle ;
end
--lineNumber start from 0
local isFinalLine = lineNumber and numLines and ( lineNumber + 1 == numLines ) ;
if self.shouldMuteLine then
if isFinalLine then
self.shouldMuteLine = nil ;
else
self : MuteNextLine ( duration ) ;
end
return
end
if self.hideInInstance and self.inInstance then
return
end
duration = duration - FADE_OUT_AFTER_FINISH ; --reserved for fade-out between line
local hideName = ( lineNumber ~= 0 ) and ( name and name == self.lastName ) ;
self.lastName = name ;
self : FadeInText ( name , text , duration , hideName , isFinalLine , displayInfo ) ;
--SetPortraitTextureFromCreatureDisplayID(self.Portrait, displayInfo);
end
end
function NewTalkingHead : FadeOutFrame ( )
FadeFrame ( self , 0.5 , 0 ) ;
end
function NewTalkingHead : OnTalkingHeadClose ( )
self : FadeOutFrame ( ) ;
self.lastName = nil ;
end
function NewTalkingHead : CloseImmediately ( )
if self.voHandle then
StopSound ( self.voHandle ) ;
end
FadeFrame ( self , 0 , 0 ) ;
self.lastName = nil ;
end
local function ShouldMuteText ( questID )
--Sometimes TALKINGHEAD_REQUESTED fires before QUEST_ACCEPTED, and we won't be able to mute it
--Sira Moonwarden's WQ returns wrong type?
return questID and ( IsWorldQuest ( questID ) or IsQuestTask ( questID ) )
end
function NewTalkingHead : OnEvent ( event , ... )
if self.isEditing then return end ;
if event == " TALKINGHEAD_REQUESTED " then
self : OnTalkingHeadRequested ( ) ;
elseif event == " TALKINGHEAD_CLOSE " then
--This event will triggered automatically, not closed by the user
self : OnTalkingHeadClose ( ) ;
elseif event == " SOUNDKIT_FINISHED " then
self : UnregisterEvent ( event ) ;
local voHandle = ...
if self.voHandle == voHandle then
self.voHandle = nil ;
end
elseif event == " LOADING_SCREEN_ENABLED " then
self : CloseImmediately ( ) ;
elseif event == " PLAYER_ENTERING_WORLD " then
self.inInstance = IsInInstance ( ) ;
elseif event == " QUEST_ACCEPTED " then
local questID = ...
if ShouldMuteText ( questID ) then
self : MuteNextLine ( ) ;
end
elseif event == " QUEST_TURNED_IN " then
local questID = ...
if ShouldMuteText ( questID ) then
self : MuteNextLine ( ) ;
end
end
end
function NewTalkingHead : OnSettingsChanged ( )
if not DB then DB = PlumberDB ; end ;
if not DB then return end ;
if DB.TalkingHead_InstantText then
self.instantText = true ;
else
self.instantText = false ;
end
if DB.TalkingHead_HideInInstance then
self.hideInInstance = true ;
else
self.hideInInstance = false ;
end
if DB.TalkingHead_HideWorldQuest then
self : RegisterEvent ( " QUEST_ACCEPTED " ) ;
self : RegisterEvent ( " QUEST_TURNED_IN " ) ;
else
self : UnregisterEvent ( " QUEST_ACCEPTED " ) ;
self : UnregisterEvent ( " QUEST_TURNED_IN " ) ;
self.shouldMuteLine = nil ;
end
if DB.TalkingHead_BelowWorldMap then
self.belowWorldMap = true ;
if not self.worldmapHooked then
self.worldmapHooked = true ;
if WorldMapFrame and WorldMapFrame.RegisterCallback then
EventRegistry : RegisterCallback ( " WorldMapOnShow " , self.WorldMapOnShow , self ) ;
WorldMapFrame : RegisterCallback ( " WorldMapOnHide " , self.WorldMapOnHide , self ) ;
end
end
else
self.belowWorldMap = false ;
end
end
---- Edit Mode
function NewTalkingHead : EnterEditMode ( )
if not self.enabled then return end ;
self : Init ( ) ;
if not self.Selection then
local uiName = " Simple Talking Head " ;
local hideLabel = true ;
self.Selection = addon.CreateEditModeSelection ( self , uiName , hideLabel ) ;
end
self.isEditing = true ;
self : SetScript ( " OnUpdate " , nil ) ;
FadeFrame ( self , 0 , 1 ) ;
self.Selection : ShowHighlighted ( ) ;
self : ShowExampleText ( ) ;
end
function NewTalkingHead : ExitEditMode ( )
if self.Selection then
self.Selection : Hide ( ) ;
end
self : ShowOptions ( false ) ;
self.isEditing = false ;
self : CloseImmediately ( ) ;
end
local function FadeIn_TypeWriter_NoAutoHide_OnUpdate ( self , elapsed )
if FadeIn_TypeWriter_OnUpdate ( self , elapsed ) then
self : SetScript ( " OnUpdate " , nil ) ;
end
end
local function FadeIn_InstantText_NoAutoHide_OnUpdate ( self , elapsed )
if FadeIn_InstantText_OnUpdate ( self , elapsed ) then
self : SetScript ( " OnUpdate " , nil ) ;
end
end
function NewTalkingHead : ShowExampleText ( animate )
local exampleText = format ( SPEECH_FORMAT_GENRIC , " The Speaker " , " Time is an illusion that helps things make sense. So we are always living in the present tense. " ) ;
self : SetText ( " \n " .. exampleText ) ;
self.LineText : SetAlpha ( 1 ) ;
if animate then
self.fadingProgress = 0 ;
self.t = 0 ;
if self.instantText then
self : SetScript ( " OnUpdate " , FadeIn_InstantText_NoAutoHide_OnUpdate ) ;
else
local numChars = strlenutf8 ( exampleText ) ;
local voiceoverDuration = 3 ;
self.gradientCPS = ceil ( numChars / voiceoverDuration ) + 10 ;
self.fadingProgress = 0 ;
self.backgroundFadeDuration = max ( voiceoverDuration - 1 , 1 ) ;
self.gradientLength = QUEST_DESCRIPTION_GRADIENT_LENGTH ;
self : SetScript ( " OnUpdate " , FadeIn_TypeWriter_NoAutoHide_OnUpdate ) ;
end
end
end
function NewTalkingHead : IsFocused ( )
return ( self : IsShown ( ) and self : IsMouseOver ( ) ) or ( self.OptionFrame and self.OptionFrame : IsShown ( ) and self.OptionFrame : IsMouseOver ( ) )
end
local function Options_FontSizeSlider_OnValueChanged ( value )
NewTalkingHead : SetFontHeightByPercentage ( value ) ;
NewTalkingHead : UpdateFrameSize ( ) ;
end
local function Options_FontSizeSlider_FormatValue ( value )
return format ( " %.0f%% " , value ) ;
end
local function Options_InstantText_OnClick ( self , state )
NewTalkingHead : OnSettingsChanged ( ) ;
NewTalkingHead : ShowExampleText ( true ) ;
end
local function Options_TextOutline_OnClick ( self , state )
NewTalkingHead : SetFontHeightByPercentage ( DB.TalkingHead_FontSize ) ;
end
local function Options_HideInInstance_OnClick ( self , state )
NewTalkingHead : OnSettingsChanged ( ) ;
end
local function Options_HideWorldQuest_OnClick ( self , state )
NewTalkingHead : OnSettingsChanged ( ) ;
end
local function Options_BelowWorldMap_OnClick ( self , state )
NewTalkingHead : OnSettingsChanged ( ) ;
if WorldMapFrame : IsVisible ( ) then
NewTalkingHead : WorldMapOnShow ( ) ;
else
NewTalkingHead : SetFrameStrata ( " FULLSCREEN " ) ;
end
end
local function Options_ResetPosition_ShouldEnable ( self )
if DB.TalkingHead_PositionX and DB.TalkingHead_PositionY then
return true
else
return false
end
end
local function Options_ResetPosition_OnClick ( self )
self : Disable ( ) ;
DB.TalkingHead_PositionX = nil ;
DB.TalkingHead_PositionY = nil ;
NewTalkingHead : LoadPosition ( ) ;
end
local OPTIONS_SCHEMATIC = {
title = L [ " EditMode TalkingHead " ] ,
widgets = {
{ type = " Checkbox " , label = L [ " TalkingHead Option InstantText " ] , onClickFunc = Options_InstantText_OnClick , dbKey = " TalkingHead_InstantText " } ,
{ type = " Checkbox " , label = L [ " TalkingHead Option TextOutline " ] , onClickFunc = Options_TextOutline_OnClick , dbKey = " TalkingHead_TextOutline " } ,
{ type = " Slider " , label = L [ " Font Size " ] , minValue = 100 , maxValue = 120 , valueStep = 10 , onValueChangedFunc = Options_FontSizeSlider_OnValueChanged , formatValueFunc = Options_FontSizeSlider_FormatValue , dbKey = " TalkingHead_FontSize " } ,
{ type = " Divider " } ,
{ type = " Header " , label = L [ " TalkingHead Option Condition Header " ] } ;
{ type = " Checkbox " , label = L [ " TalkingHead Option Condition Instance " ] , onClickFunc = Options_HideInInstance_OnClick , dbKey = " TalkingHead_HideInInstance " , tooltip = L [ " TalkingHead Option Condition Instance Tooltip " ] } ,
{ type = " Checkbox " , label = L [ " TalkingHead Option Condition WorldQuest " ] , onClickFunc = Options_HideWorldQuest_OnClick , dbKey = " TalkingHead_HideWorldQuest " , tooltip = L [ " TalkingHead Option Condition WorldQuest Tooltip " ] } ,
{ type = " Divider " } ,
{ type = " Checkbox " , label = L [ " TalkingHead Option Below WorldMap " ] , onClickFunc = Options_BelowWorldMap_OnClick , dbKey = " TalkingHead_BelowWorldMap " , tooltip = L [ " TalkingHead Option Below WorldMap Tooltip " ] } ,
{ type = " Divider " } ,
{ type = " UIPanelButton " , label = L [ " Reset To Default Position " ] , onClickFunc = Options_ResetPosition_OnClick , stateCheckFunc = Options_ResetPosition_ShouldEnable , widgetKey = " ResetButton " } ,
}
} ;
function NewTalkingHead : CreateOptions ( )
self.OptionFrame = addon.SetupSettingsDialog ( self , OPTIONS_SCHEMATIC ) ;
end
function NewTalkingHead : ShowOptions ( state )
if state then
self : CreateOptions ( ) ;
self.OptionFrame : Show ( ) ;
if self.OptionFrame . requireResetPosition then
self.OptionFrame . requireResetPosition = false ;
self.OptionFrame : ClearAllPoints ( ) ;
self.OptionFrame : SetPoint ( " LEFT " , UIParent , " CENTER " , TEXT_WIDTH * 0.5 , 0 ) ;
end
else
if self.OptionFrame then
self.OptionFrame : HideOption ( self ) ;
end
if not API.IsInEditMode ( ) then
self : CloseImmediately ( ) ;
end
end
end
function NewTalkingHead : ToggleOptions ( )
self : ShowOptions ( self.OptionFrame and self.OptionFrame : IsShown ( ) ) ;
NewTalkingHead : EnterEditMode ( )
end
function NewTalkingHead : OnDragStart ( )
self : SetMovable ( true ) ;
self : SetDontSavePosition ( true ) ;
self : SetClampedToScreen ( true ) ;
self : StartMoving ( ) ;
end
function NewTalkingHead : OnDragStop ( )
self : StopMovingOrSizing ( ) ;
local centerX = self : GetCenter ( ) ;
local uiCenter = UIParent : GetCenter ( ) ;
local left = self : GetLeft ( ) ;
local top = self : GetTop ( ) ;
left = Round ( left ) ;
top = Round ( top ) ;
self : ClearAllPoints ( ) ;
--Convert anchor and save position
if math.abs ( uiCenter - centerX ) <= 48 then
--Snap to centeral line
self : SetPoint ( " TOP " , UIParent , " BOTTOM " , 0 , top ) ;
DB.TalkingHead_PositionX = - 1 ;
else
self : SetPoint ( " TOPLEFT " , UIParent , " BOTTOMLEFT " , left , top ) ;
DB.TalkingHead_PositionX = left ;
end
DB.TalkingHead_PositionY = top ;
if self.OptionFrame and self.OptionFrame : IsOwner ( self ) then
local button = self.OptionFrame : FindWidget ( " ResetButton " ) ;
if button then
button : Enable ( ) ;
end
end
end
function NewTalkingHead : UpdateFrameSize ( )
local height = ( self.LineText : GetHeight ( ) or 0 ) + self.fontHeight ;
self : SetHeight ( height ) ;
end
local MuteDelay ;
local function MuteDelay_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
if self.t > self.duration then
self.t = nil ;
self : SetScript ( " OnUpdate " , nil ) ;
NewTalkingHead.shouldMuteLine = nil ;
end
end
function NewTalkingHead : MuteNextLine ( duration )
--Sound is still played, just no text
--Doesn't always work when you accept multiple WQ at the same location
if not MuteDelay then
MuteDelay = CreateFrame ( " Frame " ) ;
end
if ( not duration ) or duration <= 0.5 then
duration = 0.5 ;
end
if MuteDelay.t then
MuteDelay.duration = ( MuteDelay.duration or 0 ) + duration + 0.5 ;
else
MuteDelay.t = 0 ;
MuteDelay.duration = duration ;
end
MuteDelay : SetScript ( " OnUpdate " , MuteDelay_OnUpdate ) ;
self.shouldMuteLine = true ;
end
do
local function EnableModule ( state )
if state then
NewTalkingHead : EnableTalkingHead ( ) ;
else
NewTalkingHead : DisableTalkingHead ( ) ;
end
end
local function OptionToggle_OnClick ( self , button )
if NewTalkingHead.OptionFrame and NewTalkingHead.OptionFrame : IsShown ( ) then
NewTalkingHead : ShowOptions ( false ) ;
NewTalkingHead : ExitEditMode ( ) ;
else
NewTalkingHead : EnterEditMode ( ) ;
NewTalkingHead : ShowOptions ( true ) ;
end
end
local moduleData = {
name = addon.L [ " ModuleName TalkingHead " ] ,
dbKey = " TalkingHead_MasterSwitch " ,
description = addon.L [ " ModuleDescription TalkingHead " ] ,
toggleFunc = EnableModule ,
categoryID = 2 ,
uiOrder = 3 ,
moduleAddedTime = 1704423300 ,
optionToggleFunc = OptionToggle_OnClick ,
visibleInEditMode = true ,
enterEditMode = function ( )
NewTalkingHead : EnterEditMode ( ) ;
end ,
exitEditMode = function ( )
NewTalkingHead : ExitEditMode ( ) ;
end ,
} ;
addon.ControlCenter : AddModule ( moduleData ) ;
end