---@type detailsframework
local detailsFramework = _G [ " DetailsFramework " ]
if ( not detailsFramework or not DetailsFrameworkCanLoad ) then
return
end
local _
local type = type
local floor = math.floor
local GetTime = GetTime
---@class df_timebar : statusbar, df_scripthookmixin, df_widgets
---@field type string
---@field dframework boolean
---@field statusBar df_timebar_statusbar
---@field widget statusbar
---@field direction string
---@field HookList table
---@field tooltip string
---@field locked boolean
---@field HasTimer fun(self:df_timebar):boolean return if the timer bar is active showing a timer
---@field SetTimer fun(self:df_timebar, currentTime:number, startTime:number|boolean|nil, endTime:number|nil)
---@field StartTimer fun(self:df_timebar, currentTime:number, startTime:number, endTime:number)
---@field StopTimer fun(self:df_timebar)
---@field ShowSpark fun(self:df_timebar, state:boolean, alpha:number|nil, color:string|nil)
---@field ShowTimer fun(self:df_timebar, bShowTimer:boolean)
---@field SetIcon fun(self:df_timebar, texture:string, L:number|nil, R:number|nil, T:number|nil, B:number|nil)
---@field SetIconSize fun(self:df_timebar, width:number, height:number)
---@field SetTexture fun(self:df_timebar, texture:texturepath|textureid)
---@field SetColor fun(self:df_timebar, color:any, green:number|nil, blue:number|nil, alpha:number|nil)
---@field SetLeftText fun(self:df_timebar, text:string)
---@field SetRightText fun(self:df_timebar, text:string)
---@field SetFont fun(self:df_timebar, font:string|nil, size:number|nil, color:any, outline:string|boolean|nil, shadowColor:any, shadowX:number?, shadowY:number?)
---@field SetThrottle fun(self:df_timebar, seconds:number)
---@field SetDirection fun(self:df_timebar, direction:string)
---@field SetBackgroundColor fun(self:df_timebar, color:any, green:number|nil, blue:number|nil, alpha:number|nil)
---@class df_timebar_statusbar : statusbar
---@field MyObject df_timebar
---@field hasTimer boolean
---@field startTime number
---@field endTime number
---@field timeLeft1 number
---@field timeLeft2 number
---@field throttle number
---@field isUsingThrottle boolean
---@field showTimer boolean
---@field amountThrottle number
---@field sparkAlpha number
---@field sparkColorR number
---@field sparkColorG number
---@field sparkColorB number
---@field dontShowSpark boolean
---@field direction string
---@field spark texture
---@field icon texture
---@field leftText fontstring
---@field rightText fontstring
---@field backgroundTexture texture
---@field barTexture texture
local APITimeBarFunctions
do
local metaPrototype = {
WidgetType = " timebar " ,
dversion = detailsFramework.dversion ,
}
--check if there's a metaPrototype already existing
if ( _G [ detailsFramework.GlobalWidgetControlNames [ " timebar " ] ] ) then
--get the already existing metaPrototype
local oldMetaPrototype = _G [ detailsFramework.GlobalWidgetControlNames [ " timebar " ] ]
--check if is older
if ( ( not oldMetaPrototype.dversion ) or ( oldMetaPrototype.dversion < detailsFramework.dversion ) ) then
--the version is older them the currently loading one
--copy the new values into the old metatable
for funcName , _ in pairs ( metaPrototype ) do
oldMetaPrototype [ funcName ] = metaPrototype [ funcName ]
end
end
else
--first time loading the framework
_G [ detailsFramework.GlobalWidgetControlNames [ " timebar " ] ] = metaPrototype
end
end
local TimeBarMetaFunctions = _G [ detailsFramework.GlobalWidgetControlNames [ " timebar " ] ]
detailsFramework : Mixin ( TimeBarMetaFunctions , detailsFramework.ScriptHookMixin )
--methods
TimeBarMetaFunctions.SetMembers = TimeBarMetaFunctions.SetMembers or { }
TimeBarMetaFunctions.GetMembers = TimeBarMetaFunctions.GetMembers or { }
TimeBarMetaFunctions.__index = function ( table , key )
local func = TimeBarMetaFunctions.GetMembers [ key ]
if ( func ) then
return func ( table , key )
end
local fromMe = rawget ( table , key )
if ( fromMe ) then
return fromMe
end
return TimeBarMetaFunctions [ key ]
end
TimeBarMetaFunctions.__newindex = function ( table , key , value )
local func = TimeBarMetaFunctions.SetMembers [ key ]
if ( func ) then
return func ( table , value )
else
return rawset ( table , key , value )
end
end
--scripts
local OnEnterFunc = function ( statusBar )
local kill = statusBar.MyObject : RunHooksForWidget ( " OnEnter " , statusBar , statusBar.MyObject )
if ( kill ) then
return
end
if ( statusBar.MyObject . tooltip ) then
GameCooltip2 : Reset ( )
GameCooltip2 : AddLine ( statusBar.MyObject . tooltip )
GameCooltip2 : ShowCooltip ( statusBar , " tooltip " )
end
end
local OnLeaveFunc = function ( statusBar )
local kill = statusBar.MyObject : RunHooksForWidget ( " OnLeave " , statusBar , statusBar.MyObject )
if ( kill ) then
return
end
if ( statusBar.MyObject . tooltip ) then
GameCooltip2 : Hide ( )
end
end
local OnHideFunc = function ( statusBar )
local kill = statusBar.MyObject : RunHooksForWidget ( " OnHide " , statusBar , statusBar.MyObject )
if ( kill ) then
return
end
end
local OnShowFunc = function ( statusBar )
local kill = statusBar.MyObject : RunHooksForWidget ( " OnShow " , statusBar , statusBar.MyObject )
if ( kill ) then
return
end
end
local OnMouseDownFunc = function ( statusBar , mouseButton )
local kill = statusBar.MyObject : RunHooksForWidget ( " OnMouseDown " , statusBar , statusBar.MyObject )
if ( kill ) then
return
end
end
local OnMouseUpFunc = function ( statusBar , mouseButton )
local kill = statusBar.MyObject : RunHooksForWidget ( " OnMouseUp " , statusBar , statusBar.MyObject )
if ( kill ) then
return
end
end
--timer functions
function TimeBarMetaFunctions : SetIconSize ( width , height )
if ( width and not height ) then
self.statusBar . icon : SetWidth ( width )
elseif ( not width and height ) then
self.statusBar . icon : SetHeight ( height )
elseif ( width and height ) then
self.statusBar . icon : SetSize ( width , height )
end
end
function TimeBarMetaFunctions : SetIcon ( texture , L , R , T , B )
if ( texture ) then
self.statusBar . icon : Show ( )
self.statusBar . icon : ClearAllPoints ( )
self.statusBar . icon : SetPoint ( " left " , self.statusBar , " left " , 2 , 0 )
self.statusBar . icon : SetSize ( self.statusBar : GetHeight ( ) - 2 , self.statusBar : GetHeight ( ) - 2 )
self.statusBar . leftText : ClearAllPoints ( )
self.statusBar . leftText : SetPoint ( " left " , self.statusBar . icon , " right " , 2 , 0 )
self.statusBar . icon : SetTexture ( texture )
if ( L ) then
self.statusBar . icon : SetTexCoord ( L , R , T , B )
end
else
self.statusBar . icon : Hide ( )
self.statusBar . leftText : ClearAllPoints ( )
self.statusBar . leftText : SetPoint ( " left " , self.statusBar , " left " , 2 , 0 )
end
end
function TimeBarMetaFunctions : GetIcon ( )
return self.statusBar . icon
end
function TimeBarMetaFunctions : SetTexture ( texture )
self.statusBar . barTexture : SetTexture ( texture )
end
function TimeBarMetaFunctions : SetColor ( color , green , blue , alpha )
local r , g , b , a = detailsFramework : ParseColors ( color , green , blue , alpha )
self.statusBar . barTexture : SetVertexColor ( r , g , b , a )
end
function TimeBarMetaFunctions : SetLeftText ( text )
self.statusBar . leftText : SetText ( text )
end
function TimeBarMetaFunctions : SetRightText ( text )
self.statusBar . rightText : SetText ( text )
end
function TimeBarMetaFunctions : SetFont ( font , size , color , outline , shadowColor , shadowX , shadowY )
if ( font ) then
detailsFramework : SetFontFace ( self.statusBar . leftText , font )
detailsFramework : SetFontFace ( self.statusBar . rightText , font )
end
if ( size ) then
detailsFramework : SetFontSize ( self.statusBar . leftText , size )
detailsFramework : SetFontSize ( self.statusBar . rightText , size )
end
if ( color ) then
detailsFramework : SetFontColor ( self.statusBar . leftText , color )
detailsFramework : SetFontColor ( self.statusBar . rightText , color )
end
if ( outline ) then
detailsFramework : SetFontOutline ( self.statusBar . leftText , outline )
detailsFramework : SetFontOutline ( self.statusBar . rightText , outline )
end
if ( shadowColor ) then
self.statusBar . leftText : SetShadowColor ( detailsFramework : ParseColors ( shadowColor ) )
self.statusBar . rightText : SetShadowColor ( detailsFramework : ParseColors ( shadowColor ) )
end
if ( shadowX and shadowY ) then
self.statusBar . leftText : SetShadowOffset ( shadowX , shadowY )
self.statusBar . rightText : SetShadowOffset ( shadowX , shadowY )
end
end
--set background texture color
function TimeBarMetaFunctions : SetBackgroundColor ( color , green , blue , alpha )
local r , g , b , a = detailsFramework : ParseColors ( color , green , blue , alpha )
self.statusBar . backgroundTexture : SetVertexColor ( r , g , b , a )
end
---set a throttle for the timer bar, the timer will only update every X seconds
---calling without parameters will disable the throttle
---@param seconds number|nil the amount of seconds to throttle the timer
function TimeBarMetaFunctions : SetThrottle ( seconds )
if ( seconds and seconds > 0 ) then
self.statusBar . isUsingThrottle = true
self.statusBar . amountThrottle = seconds
else
self.statusBar . isUsingThrottle = false
end
end
---accept 'left' 'right' or nil, if ommited will default to right
---@param direction "left"|"right"|nil the direction of the timer bar
function TimeBarMetaFunctions : SetDirection ( direction )
direction = direction or " right "
self.direction = direction
end
function TimeBarMetaFunctions : HasTimer ( )
return self.statusBar . hasTimer
end
function TimeBarMetaFunctions : StopTimer ( )
if ( self.statusBar . hasTimer ) then
self.statusBar . hasTimer = nil
local kill = self : RunHooksForWidget ( " OnTimerEnd " , self.statusBar , self )
if ( kill ) then
return
end
end
local statusBar = self.statusBar
statusBar : SetScript ( " OnUpdate " , nil )
statusBar : SetMinMaxValues ( 0 , 100 )
statusBar : SetValue ( 100 )
statusBar.rightText : SetText ( " " )
statusBar.spark : Hide ( )
end
function TimeBarMetaFunctions : ShowTimer ( bShowTimer )
if ( bShowTimer ) then
self.statusBar . showTimer = true
else
self.statusBar . showTimer = nil
end
end
function TimeBarMetaFunctions : ShowSpark ( state , alpha , color )
if ( type ( state ) == " boolean " and state == false ) then
self.statusBar . dontShowSpark = true
else
self.statusBar . dontShowSpark = nil
end
if ( alpha ) then
self.statusBar . sparkAlpha = alpha
else
self.statusBar . sparkAlpha = nil
end
if ( color ) then
local r , g , b = detailsFramework : ParseColors ( color )
if ( r and g and b ) then
self.statusBar . sparkColorR = r
self.statusBar . sparkColorG = g
self.statusBar . sparkColorB = b
end
else
self.statusBar . sparkColorR = nil
self.statusBar . sparkColorG = nil
self.statusBar . sparkColorB = nil
end
end
---@param self df_timebar_statusbar
---@param deltaTime number
local OnUpdateFunc = function ( self , deltaTime )
if ( self.isUsingThrottle ) then
self.throttle = self.throttle + deltaTime
if ( self.throttle < self.amountThrottle ) then
return
end
self.throttle = 0
end
local timeNow = GetTime ( )
self : SetValue ( timeNow )
--adjust the spark
local spark = self.spark
local startTime , endTime = self : GetMinMaxValues ( )
if ( not self.dontShowSpark ) then
if ( endTime - startTime > 0 ) then
local pct = abs ( ( timeNow - endTime ) / ( endTime - startTime ) )
pct = abs ( 1 - pct )
local sparkOffset = - 16
if ( self.direction ~= " right " ) then
--moving from right to left, so invert the pct
pct = abs ( 1 - pct )
sparkOffset = - 14
end
spark : SetPoint ( " left " , self , " left " , ( self : GetWidth ( ) * pct ) + sparkOffset , 0 )
spark : Show ( )
else
spark : Hide ( )
end
end
if ( self.showTimer ) then
local timeLeft = floor ( endTime - timeNow ) + 1
local formatedTimeLeft = detailsFramework : IntegerToTimer ( timeLeft )
self.rightText : SetText ( formatedTimeLeft )
end
--check if finished
if ( timeNow >= self.endTime ) then
self.MyObject : StopTimer ( )
end
self.MyObject : RunHooksForWidget ( " OnUpdate " , self , self , deltaTime )
end
---start a timer on the timebar
---calling without parameters will stop the timer
---@param self df_timebar
---@param currentTime number the time in seconds if startTime is a boolean true. GetTime() when start and end time are passed
---@param startTime number|boolean|nil GetTime() when the timer started. if passed true: startTime and endTime are GetTime() and GetTime() + currentTime, currenTime is the time in seconds
---@param endTime number|nil GetTime() when the timer will end. ignored if startTime is a boolean true
function TimeBarMetaFunctions : SetTimer ( currentTime , startTime , endTime )
self.statusBar : Show ( )
if ( not currentTime or currentTime == 0 ) then
self : StopTimer ( )
return
end
if ( startTime and endTime ) then
if ( self.statusBar . hasTimer and currentTime == self.statusBar . timeLeft1 ) then
--it is the same timer called again
return
end
self.statusBar . startTime = tonumber ( startTime ) or 0 --fit the number type
self.statusBar . endTime = endTime
else
local bForceNewTimer = type ( startTime ) == " boolean " and startTime
if ( self.statusBar . hasTimer and currentTime == self.statusBar . timeLeft2 and not bForceNewTimer ) then
--it is the same timer called again
return
end
self.statusBar . startTime = GetTime ( )
self.statusBar . endTime = GetTime ( ) + currentTime
self.statusBar . timeLeft2 = currentTime
end
self.statusBar : SetMinMaxValues ( self.statusBar . startTime , self.statusBar . endTime )
if ( self.direction == " right " ) then
self.statusBar : SetReverseFill ( false )
else
self.statusBar : SetReverseFill ( true )
end
if ( self.statusBar . dontShowSpark ) then
self.statusBar . spark : Hide ( )
else
self.statusBar . spark : Show ( )
self.statusBar . spark : SetHeight ( self.statusBar : GetHeight ( ) + 26 )
if ( self.statusBar . sparkAlpha ) then
self.statusBar . spark : SetAlpha ( self.statusBar . sparkAlpha )
else
self.statusBar . spark : SetAlpha ( 1 )
end
if ( self.statusBar . sparkColorR ) then
self.statusBar . spark : SetVertexColor ( self.statusBar . sparkColorR , self.statusBar . sparkColorG , self.statusBar . sparkColorB )
else
self.statusBar . spark : SetVertexColor ( 1 , 1 , 1 )
end
end
self.statusBar . hasTimer = true
self.statusBar . direction = self.direction
self.statusBar . throttle = 0
self.statusBar : SetScript ( " OnUpdate " , OnUpdateFunc )
local kill = self : RunHooksForWidget ( " OnTimerStart " , self.statusBar , self )
if ( kill ) then
return
end
end
---create a time bar widget, a timebar is a statubar that can have a timer and a spark
---@param parent frame the parent frame
---@param texture texturepath|textureid the texture of the bar
---@param width number? the width of the bar, default is 150
---@param height number? the height of the bar, default is 20
---@param value number? the initial value of the bar, default is 0
---@param member string? the name of the member in the parent frame
---@param name string? the name of the widget
---@return df_timebar
function detailsFramework : CreateTimeBar ( parent , texture , width , height , value , member , name )
if ( not name ) then
name = " DetailsFrameworkBarNumber " .. detailsFramework.BarNameCounter
detailsFramework.BarNameCounter = detailsFramework.BarNameCounter + 1
elseif ( not parent ) then
error ( " Details! FrameWork: parent not found. " , 2 )
end
if ( name : find ( " $parent " ) ) then
local parentName = detailsFramework : GetParentName ( parent )
name = name : gsub ( " $parent " , parentName )
end
local timeBar = {
type = " timebar " ,
dframework = true
}
if ( member ) then
parent [ member ] = timeBar
end
---@diagnostic disable-next-line: undefined-field
if ( parent.dframework ) then
---@diagnostic disable-next-line: undefined-field
parent = parent.widget
end
value = value or 0
width = width or 150
height = height or 20
timeBar.locked = false
timeBar.statusBar = CreateFrame ( " statusbar " , name , parent , " BackdropTemplate " )
timeBar.widget = timeBar.statusBar
detailsFramework : Mixin ( timeBar.statusBar , detailsFramework.WidgetFunctions )
timeBar.statusBar . MyObject = timeBar
timeBar.direction = " right "
if ( not APITimeBarFunctions ) then
APITimeBarFunctions = true
local idx = getmetatable ( timeBar.statusBar ) . __index
for funcName , funcAddress in pairs ( idx ) do
if ( not TimeBarMetaFunctions [ funcName ] ) then
TimeBarMetaFunctions [ funcName ] = function ( object , ... )
local x = loadstring ( " return _G[' " .. object.statusBar : GetName ( ) .. " ']: " .. funcName .. " (...) " )
if ( x ) then
return x ( ... )
end
end
end
end
end
--create widgets
timeBar.statusBar : SetWidth ( width )
timeBar.statusBar : SetHeight ( height )
timeBar.statusBar : SetFrameLevel ( parent : GetFrameLevel ( ) + 1 )
timeBar.statusBar : SetMinMaxValues ( 0 , 100 )
timeBar.statusBar : SetValue ( value or 100 )
timeBar.statusBar : EnableMouse ( false )
timeBar.statusBar . backgroundTexture = timeBar.statusBar : CreateTexture ( nil , " border " )
timeBar.statusBar . backgroundTexture : SetColorTexture ( .9 , .9 , .9 , 1 )
timeBar.statusBar . backgroundTexture : SetVertexColor ( .1 , .1 , .1 , .6 )
timeBar.statusBar . backgroundTexture : SetAllPoints ( )
timeBar.statusBar . barTexture = timeBar.statusBar : CreateTexture ( nil , " artwork " )
timeBar.statusBar . barTexture : SetTexture ( texture or [[Interface\WorldStateFrame\WORLDSTATEFINALSCORE-HIGHLIGHT]] )
timeBar.statusBar : SetStatusBarTexture ( timeBar.statusBar . barTexture )
timeBar.statusBar . spark = timeBar.statusBar : CreateTexture ( nil , " overlay " , nil , 7 )
timeBar.statusBar . spark : SetTexture ( [[Interface\CastingBar\UI-CastingBar-Spark]] )
timeBar.statusBar . spark : SetBlendMode ( " ADD " )
timeBar.statusBar . spark : Hide ( )
timeBar.statusBar . icon = timeBar.statusBar : CreateTexture ( nil , " overlay " , nil , 5 )
timeBar.statusBar . icon : SetPoint ( " left " , timeBar.statusBar , " left " , 2 , 0 )
timeBar.statusBar . leftText = timeBar.statusBar : CreateFontString ( " $parentLeftText " , " overlay " , " GameFontNormal " , 4 )
timeBar.statusBar . leftText : SetPoint ( " left " , timeBar.statusBar . icon , " right " , 2 , 0 )
timeBar.statusBar . rightText = timeBar.statusBar : CreateFontString ( nil , " overlay " , " GameFontNormal " , 4 )
timeBar.statusBar . rightText : SetPoint ( " right " , timeBar.statusBar , " right " , - 2 , 0 )
timeBar.statusBar . rightText : SetJustifyH ( " left " )
--hooks
timeBar.HookList = {
OnEnter = { } ,
OnLeave = { } ,
OnHide = { } ,
OnShow = { } ,
OnUpdate = { } ,
OnMouseDown = { } ,
OnMouseUp = { } ,
OnTimerStart = { } ,
OnTimerEnd = { } ,
}
timeBar.statusBar : SetScript ( " OnEnter " , OnEnterFunc )
timeBar.statusBar : SetScript ( " OnLeave " , OnLeaveFunc )
timeBar.statusBar : SetScript ( " OnHide " , OnHideFunc )
timeBar.statusBar : SetScript ( " OnShow " , OnShowFunc )
timeBar.statusBar : SetScript ( " OnMouseDown " , OnMouseDownFunc )
timeBar.statusBar : SetScript ( " OnMouseUp " , OnMouseUpFunc )
--set class
setmetatable ( timeBar , TimeBarMetaFunctions )
return timeBar
end