local detailsFramework = _G [ " DetailsFramework " ]
if ( not detailsFramework or not DetailsFrameworkCanLoad ) then
return
end
local _
--lua locals
local rawset = rawset --lua local
local rawget = rawget --lua local
local setmetatable = setmetatable --lua local
local unpack = table.unpack or unpack --lua local
local type = type --lua local
local floor = math.floor --lua local
local loadstring = loadstring --lua local
local IS_WOW_PROJECT_MAINLINE = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE
local IS_WOW_PROJECT_NOT_MAINLINE = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE
local IS_WOW_PROJECT_CLASSIC_ERA = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
if IS_WOW_PROJECT_CLASSIC_ERA then
UnitCastingInfo = CastingInfo
UnitChannelInfo = ChannelInfo
end
local PixelUtil = PixelUtil or DFPixelUtil
local UnitGroupRolesAssigned = detailsFramework.UnitGroupRolesAssigned
local cleanfunction = function ( ) end
local APIFrameFunctions
do
local metaPrototype = {
WidgetType = " panel " ,
dversion = detailsFramework.dversion ,
}
--check if there's a metaPrototype already existing
if ( _G [ detailsFramework.GlobalWidgetControlNames [ " panel " ] ] ) then
--get the already existing metaPrototype
local oldMetaPrototype = _G [ detailsFramework.GlobalWidgetControlNames [ " panel " ] ]
--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 [ " panel " ] ] = metaPrototype
end
end
local PanelMetaFunctions = _G [ detailsFramework.GlobalWidgetControlNames [ " panel " ] ]
detailsFramework : Mixin ( PanelMetaFunctions , detailsFramework.ScriptHookMixin )
--default options for the frame layout
local default_framelayout_options = {
amount_per_line = 4 ,
start_x = 2 ,
start_y = - 2 ,
is_vertical = false ,
grow_right = true , --on vertical (if not grow next line left)
grow_down = true , --on horizontal (if not grow next line up)
anchor_to_child = false , --if true set the point to the previous frame instead of coordinate
anchor_point = " topleft " ,
anchor_relative = " topleft " ,
offset_x = 100 ,
offset_y = 20 ,
width = 0 , --if bigger than 0, it will set the value
height = 0 ,
break_if_hidden = true , --stop if encounters a hidden frame
}
--mixin for frame layout
detailsFramework.LayoutFrame = {
AnchorTo = function ( self , anchor , point , x , y )
if ( point == " top " ) then
self : ClearAllPoints ( )
self : SetPoint ( " bottom " , anchor , " top " , x or 0 , y or 0 )
elseif ( point == " bottom " ) then
self : ClearAllPoints ( )
self : SetPoint ( " top " , anchor , " bottom " , x or 0 , y or 0 )
elseif ( point == " left " ) then
self : ClearAllPoints ( )
self : SetPoint ( " right " , anchor , " left " , x or 0 , y or 0 )
elseif ( point == " right " ) then
self : ClearAllPoints ( )
self : SetPoint ( " left " , anchor , " right " , x or 0 , y or 0 )
end
end ,
ArrangeFrames = function ( self , frameList , options )
if ( not frameList ) then
frameList = { self : GetChildren ( ) }
end
options = options or { }
detailsFramework.table . deploy ( options , default_framelayout_options )
local breakLine = options.amount_per_line + 1
local currentX , currentY = options.start_x , options.start_y
local offsetX , offsetY = options.offset_x , options.offset_y
local anchorPoint = options.anchor_point
local anchorAt = options.anchor_relative
local latestFrame = self
local firstRowFrame = frameList [ 1 ]
if ( options.is_vertical ) then
for i = 1 , # frameList do
local thisFrame = frameList [ i ]
if ( options.break_if_hidden and not thisFrame : IsShown ( ) ) then
break
end
thisFrame : ClearAllPoints ( )
if ( options.anchor_to_child ) then
if ( i == breakLine ) then
if ( options.grow_right ) then
thisFrame : SetPoint ( " topleft " , firstRowFrame , " topright " , offsetX , 0 )
else
thisFrame : SetPoint ( " topright " , firstRowFrame , " topleft " , - offsetX , 0 )
end
firstRowFrame = thisFrame
latestFrame = thisFrame
breakLine = breakLine + options.amount_per_line
else
thisFrame : SetPoint ( anchorPoint , latestFrame , i == 1 and " topleft " or anchorAt , offsetX , i == 1 and 0 or offsetY )
latestFrame = thisFrame
end
else
if ( i == breakLine ) then
if ( options.grow_right ) then
currentX = currentX + offsetX
else
currentX = currentX - offsetX
end
currentY = options.start_y
firstRowFrame = thisFrame
breakLine = breakLine + options.amount_per_line
end
thisFrame : SetPoint ( anchorPoint , self , anchorAt , currentX , currentY )
currentY = currentY - offsetY
end
end
else
for i = 1 , # frameList do
local thisFrame = frameList [ i ]
if ( options.break_if_hidden and not thisFrame : IsShown ( ) ) then
break
end
thisFrame : ClearAllPoints ( )
if ( options.anchor_to_child ) then
if ( i == breakLine ) then
if ( options.grow_down ) then
thisFrame : SetPoint ( " topleft " , firstRowFrame , " bottomleft " , 0 , - offsetY )
else
thisFrame : SetPoint ( " bottomleft " , firstRowFrame , " topleft " , 0 , offsetY )
end
firstRowFrame = thisFrame
latestFrame = thisFrame
breakLine = breakLine + options.amount_per_line
else
thisFrame : SetPoint ( anchorPoint , latestFrame , i == 1 and " topleft " or anchorAt , i == 1 and 0 or offsetX , offsetY )
latestFrame = thisFrame
end
else
if ( i == breakLine ) then
if ( options.grow_down ) then
currentY = currentY - offsetY
else
currentY = currentY + offsetY
end
currentX = options.start_x
firstRowFrame = thisFrame
breakLine = breakLine + options.amount_per_line
end
thisFrame : SetPoint ( anchorPoint , self , anchorAt , currentX , currentY )
currentX = currentX + offsetX
end
end
end
end
}
------------------------------------------------------------------------------------------------------------
--metatables
PanelMetaFunctions.__call = function ( _table , value )
--nothing to do
return true
end
------------------------------------------------------------------------------------------------------------
--members
--tooltip
local gmember_tooltip = function ( _object )
return _object : GetTooltip ( )
end
--shown
local gmember_shown = function ( _object )
return _object : IsShown ( )
end
--backdrop color
local gmember_color = function ( _object )
return _object.frame : GetBackdropColor ( )
end
--backdrop table
local gmember_backdrop = function ( _object )
return _object.frame : GetBackdrop ( )
end
--frame width
local gmember_width = function ( _object )
return _object.frame : GetWidth ( )
end
--frame height
local gmember_height = function ( _object )
return _object.frame : GetHeight ( )
end
--locked
local gmember_locked = function ( _object )
return rawget ( _object , " is_locked " )
end
PanelMetaFunctions.GetMembers = PanelMetaFunctions.GetMembers or { }
PanelMetaFunctions.GetMembers [ " tooltip " ] = gmember_tooltip
PanelMetaFunctions.GetMembers [ " shown " ] = gmember_shown
PanelMetaFunctions.GetMembers [ " color " ] = gmember_color
PanelMetaFunctions.GetMembers [ " backdrop " ] = gmember_backdrop
PanelMetaFunctions.GetMembers [ " width " ] = gmember_width
PanelMetaFunctions.GetMembers [ " height " ] = gmember_height
PanelMetaFunctions.GetMembers [ " locked " ] = gmember_locked
PanelMetaFunctions.__index = function ( object , key )
local func = PanelMetaFunctions.GetMembers [ key ]
if ( func ) then
return func ( object , key )
end
local fromMe = rawget ( object , key )
if ( fromMe ) then
return fromMe
end
return PanelMetaFunctions [ key ]
end
--tooltip
local smember_tooltip = function ( _object , _value )
return _object : SetTooltip ( _value )
end
--show
local smember_show = function ( _object , _value )
if ( _value ) then
return _object : Show ( )
else
return _object : Hide ( )
end
end
--hide
local smember_hide = function ( _object , _value )
if ( not _value ) then
return _object : Show ( )
else
return _object : Hide ( )
end
end
--backdrop color
local smember_color = function ( _object , _value )
local _value1 , _value2 , _value3 , _value4 = detailsFramework : ParseColors ( _value )
return _object : SetBackdropColor ( _value1 , _value2 , _value3 , _value4 )
end
--frame width
local smember_width = function ( _object , _value )
return _object.frame : SetWidth ( _value )
end
--frame height
local smember_height = function ( _object , _value )
return _object.frame : SetHeight ( _value )
end
--locked
local smember_locked = function ( _object , _value )
if ( _value ) then
_object.frame : SetMovable ( false )
return rawset ( _object , " is_locked " , true )
else
_object.frame : SetMovable ( true )
rawset ( _object , " is_locked " , false )
return
end
end
--backdrop
local smember_backdrop = function ( _object , _value )
return _object.frame : SetBackdrop ( _value )
end
--close with right button
local smember_right_close = function ( _object , _value )
return rawset ( _object , " rightButtonClose " , _value )
end
PanelMetaFunctions.SetMembers = PanelMetaFunctions.SetMembers or { }
PanelMetaFunctions.SetMembers [ " tooltip " ] = smember_tooltip
PanelMetaFunctions.SetMembers [ " show " ] = smember_show
PanelMetaFunctions.SetMembers [ " hide " ] = smember_hide
PanelMetaFunctions.SetMembers [ " color " ] = smember_color
PanelMetaFunctions.SetMembers [ " backdrop " ] = smember_backdrop
PanelMetaFunctions.SetMembers [ " width " ] = smember_width
PanelMetaFunctions.SetMembers [ " height " ] = smember_height
PanelMetaFunctions.SetMembers [ " locked " ] = smember_locked
PanelMetaFunctions.SetMembers [ " close_with_right " ] = smember_right_close
PanelMetaFunctions.__newindex = function ( _table , _key , _value )
local func = PanelMetaFunctions.SetMembers [ _key ]
if ( func ) then
return func ( _table , _value )
else
return rawset ( _table , _key , _value )
end
end
------------------------------------------------------------------------------------------------------------
--methods
--right click to close
function PanelMetaFunctions : CreateRightClickLabel ( textType , width , height , showCloseText )
local text
width = width or 20
height = height or 20
if ( showCloseText ) then
text = showCloseText
else
if ( textType ) then
textType = string.lower ( textType )
if ( textType == " short " ) then
text = " close window "
elseif ( textType == " medium " ) then
text = " close window "
elseif ( textType == " large " ) then
text = " close window "
end
else
text = " close window "
end
end
return detailsFramework : NewLabel ( self , _ , " $parentRightMouseToClose " , nil , " |TInterface \\ TUTORIALFRAME \\ UI-TUTORIAL-FRAME: " .. width .. " : " .. height .. " :0:1:512:512:8:70:328:409|t " .. text )
end
--show & hide
function PanelMetaFunctions : Show ( )
self.frame : Show ( )
end
function PanelMetaFunctions : Hide ( )
self.frame : Hide ( )
end
-- setpoint
function PanelMetaFunctions : SetPoint ( v1 , v2 , v3 , v4 , v5 )
v1 , v2 , v3 , v4 , v5 = detailsFramework : CheckPoints ( v1 , v2 , v3 , v4 , v5 , self )
if ( not v1 ) then
print ( " Invalid parameter for SetPoint " )
return
end
return self.widget : SetPoint ( v1 , v2 , v3 , v4 , v5 )
end
-- sizes
function PanelMetaFunctions : SetSize ( w , h )
if ( w ) then
self.frame : SetWidth ( w )
end
if ( h ) then
self.frame : SetHeight ( h )
end
end
-- clear
function PanelMetaFunctions : HideWidgets ( )
for widgetName , widgetSelf in pairs ( self ) do
if ( type ( widgetSelf ) == " table " and widgetSelf.dframework ) then
widgetSelf : Hide ( )
end
end
end
-- backdrop
function PanelMetaFunctions : SetBackdrop ( background , edge , tilesize , edgesize , tile , left , right , top , bottom )
if ( type ( background ) == " boolean " and not background ) then
return self.frame : SetBackdrop ( nil )
elseif ( type ( background ) == " table " ) then
self.frame : SetBackdrop ( background )
else
local currentBackdrop = self.frame : GetBackdrop ( ) or { edgeFile = " Interface \\ DialogFrame \\ UI-DialogBox-Border " , bgFile = " Interface \\ DialogFrame \\ UI-DialogBox-Background " , tile = true , tileSize = 16 , edgeSize = 16 , insets = { left = 1 , right = 0 , top = 0 , bottom = 0 } }
currentBackdrop.bgFile = background or currentBackdrop.bgFile
currentBackdrop.edgeFile = edgeFile or currentBackdrop.edgeFile
currentBackdrop.tileSize = tilesize or currentBackdrop.tileSize
currentBackdrop.edgeSize = edgesize or currentBackdrop.edgeSize
currentBackdrop.tile = tile or currentBackdrop.tile
currentBackdrop.insets . left = left or currentBackdrop.insets . left
currentBackdrop.insets . right = left or currentBackdrop.insets . right
currentBackdrop.insets . top = left or currentBackdrop.insets . top
currentBackdrop.insets . bottom = left or currentBackdrop.insets . bottom
self.frame : SetBackdrop ( currentBackdrop )
end
end
-- backdropcolor
function PanelMetaFunctions : SetBackdropColor ( color , arg2 , arg3 , arg4 )
if ( arg2 ) then
self.frame : SetBackdropColor ( color , arg2 , arg3 , arg4 or 1 )
else
local _value1 , _value2 , _value3 , _value4 = detailsFramework : ParseColors ( color )
self.frame : SetBackdropColor ( _value1 , _value2 , _value3 , _value4 )
end
end
-- border color
function PanelMetaFunctions : SetBackdropBorderColor ( color , arg2 , arg3 , arg4 )
if ( arg2 ) then
return self.frame : SetBackdropBorderColor ( color , arg2 , arg3 , arg4 )
end
local _value1 , _value2 , _value3 , _value4 = detailsFramework : ParseColors ( color )
self.frame : SetBackdropBorderColor ( _value1 , _value2 , _value3 , _value4 )
end
-- tooltip
function PanelMetaFunctions : SetTooltip ( tooltip )
if ( tooltip ) then
return rawset ( self , " have_tooltip " , tooltip )
else
return rawset ( self , " have_tooltip " , nil )
end
end
function PanelMetaFunctions : GetTooltip ( )
return rawget ( self , " have_tooltip " )
end
-- frame levels
function PanelMetaFunctions : GetFrameLevel ( )
return self.widget : GetFrameLevel ( )
end
function PanelMetaFunctions : SetFrameLevel ( level , frame )
if ( not frame ) then
return self.widget : SetFrameLevel ( level )
else
local framelevel = frame : GetFrameLevel ( frame ) + level
return self.widget : SetFrameLevel ( framelevel )
end
end
-- frame stratas
function PanelMetaFunctions : SetFrameStrata ( )
return self.widget : GetFrameStrata ( )
end
function PanelMetaFunctions : SetFrameStrata ( strata )
if ( type ( strata ) == " table " ) then
self.widget : SetFrameStrata ( strata : GetFrameStrata ( ) )
else
self.widget : SetFrameStrata ( strata )
end
end
------------------------------------------------------------------------------------------------------------
--scripts
local OnEnter = function ( frame )
local capsule = frame.MyObject
local kill = capsule : RunHooksForWidget ( " OnEnter " , frame , capsule )
if ( kill ) then
return
end
if ( frame.MyObject . have_tooltip ) then
GameCooltip2 : Reset ( )
GameCooltip2 : SetType ( " tooltip " )
GameCooltip2 : SetColor ( " main " , " transparent " )
GameCooltip2 : AddLine ( frame.MyObject . have_tooltip )
GameCooltip2 : SetOwner ( frame )
GameCooltip2 : ShowCooltip ( )
end
end
local OnLeave = function ( frame )
local capsule = frame.MyObject
local kill = capsule : RunHooksForWidget ( " OnLeave " , frame , capsule )
if ( kill ) then
return
end
if ( frame.MyObject . have_tooltip ) then
GameCooltip2 : ShowMe ( false )
end
end
local OnHide = function ( frame )
local capsule = frame.MyObject
local kill = capsule : RunHooksForWidget ( " OnHide " , frame , capsule )
if ( kill ) then
return
end
end
local OnShow = function ( frame )
local capsule = frame.MyObject
local kill = capsule : RunHooksForWidget ( " OnShow " , frame , capsule )
if ( kill ) then
return
end
end
local OnMouseDown = function ( frame , button )
local capsule = frame.MyObject
local kill = capsule : RunHooksForWidget ( " OnMouseDown " , frame , button , capsule )
if ( kill ) then
return
end
if ( frame.MyObject . container == UIParent ) then
if ( not frame.isLocked and frame : IsMovable ( ) ) then
frame.isMoving = true
frame : StartMoving ( )
end
elseif ( not frame.MyObject . container.isLocked and frame.MyObject . container : IsMovable ( ) ) then
if ( not frame.isLocked and frame : IsMovable ( ) ) then
frame.MyObject . container.isMoving = true
frame.MyObject . container : StartMoving ( )
end
end
end
local OnMouseUp = function ( frame , button )
local capsule = frame.MyObject
local kill = capsule : RunHooksForWidget ( " OnMouseUp " , frame , button , capsule )
if ( kill ) then
return
end
if ( button == " RightButton " and frame.MyObject . rightButtonClose ) then
frame.MyObject : Hide ( )
end
if ( frame.MyObject . container == UIParent ) then
if ( frame.isMoving ) then
frame : StopMovingOrSizing ( )
frame.isMoving = false
end
else
if ( frame.MyObject . container.isMoving ) then
frame.MyObject . container : StopMovingOrSizing ( )
frame.MyObject . container.isMoving = false
end
end
end
------------------------------------------------------------------------------------------------------------
--object constructor
function detailsFramework : CreatePanel ( parent , w , h , backdrop , backdropcolor , bordercolor , member , name )
return detailsFramework : NewPanel ( parent , parent , name , member , w , h , backdrop , backdropcolor , bordercolor )
end
function detailsFramework : NewPanel ( parent , container , name , member , w , h , backdrop , backdropcolor , bordercolor )
if ( not name ) then
name = " DetailsFrameworkPanelNumber " .. detailsFramework.PanelCounter
detailsFramework.PanelCounter = detailsFramework.PanelCounter + 1
elseif ( not parent ) then
parent = UIParent
end
if ( not container ) then
container = parent
end
if ( name : find ( " $parent " ) ) then
name = name : gsub ( " $parent " , parent : GetName ( ) )
end
local PanelObject = { type = " panel " , dframework = true }
if ( member ) then
parent [ member ] = PanelObject
end
if ( parent.dframework ) then
parent = parent.widget
end
if ( container.dframework ) then
container = container.widget
end
--default members:
--misc
PanelObject.is_locked = true
PanelObject.container = container
PanelObject.rightButtonClose = false
PanelObject.frame = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
PanelObject.frame : SetSize ( 100 , 100 )
PanelObject.frame . Gradient = {
[ " OnEnter " ] = { 0.3 , 0.3 , 0.3 , 0.5 } ,
[ " OnLeave " ] = { 0.9 , 0.7 , 0.7 , 1 }
}
PanelObject.frame : SetBackdrop ( { bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]] , edgeFile = " Interface \\ DialogFrame \\ UI-DialogBox-Border " , edgeSize = 10 , tileSize = 64 , tile = true } )
PanelObject.widget = PanelObject.frame
if ( not APIFrameFunctions ) then
APIFrameFunctions = { }
local idx = getmetatable ( PanelObject.frame ) . __index
for funcName , funcAddress in pairs ( idx ) do
if ( not PanelMetaFunctions [ funcName ] ) then
PanelMetaFunctions [ funcName ] = function ( object , ... )
local x = loadstring ( " return _G[' " .. object.frame : GetName ( ) .. " ']: " .. funcName .. " (...) " )
return x ( ... )
end
end
end
end
PanelObject.frame : SetWidth ( w or 100 )
PanelObject.frame : SetHeight ( h or 100 )
PanelObject.frame . MyObject = PanelObject
PanelObject.HookList = {
OnEnter = { } ,
OnLeave = { } ,
OnHide = { } ,
OnShow = { } ,
OnMouseDown = { } ,
OnMouseUp = { } ,
}
--hooks
PanelObject.frame : SetScript ( " OnEnter " , OnEnter )
PanelObject.frame : SetScript ( " OnLeave " , OnLeave )
PanelObject.frame : SetScript ( " OnHide " , OnHide )
PanelObject.frame : SetScript ( " OnShow " , OnShow )
PanelObject.frame : SetScript ( " OnMouseDown " , OnMouseDown )
PanelObject.frame : SetScript ( " OnMouseUp " , OnMouseUp )
setmetatable ( PanelObject , PanelMetaFunctions )
if ( backdrop ) then
PanelObject : SetBackdrop ( backdrop )
elseif ( type ( backdrop ) == " boolean " ) then
PanelObject.frame : SetBackdrop ( nil )
end
if ( backdropcolor ) then
PanelObject : SetBackdropColor ( backdropcolor )
end
if ( bordercolor ) then
PanelObject : SetBackdropBorderColor ( bordercolor )
end
return PanelObject
end
------------fill panel
local button_on_enter = function ( self )
self.MyObject . _icon : SetBlendMode ( " ADD " )
if ( self.MyObject . onenter_func ) then
pcall ( self.MyObject . onenter_func , self.MyObject )
end
end
local button_on_leave = function ( self )
self.MyObject . _icon : SetBlendMode ( " BLEND " )
if ( self.MyObject . onleave_func ) then
pcall ( self.MyObject . onleave_func , self.MyObject )
end
end
local add_row = function ( self , t , need_update )
local index = # self.rows + 1
local thisrow = detailsFramework : NewPanel ( self , self , " $parentHeader_ " .. self._name .. index , nil , 1 , 20 )
thisrow.backdrop = { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] }
thisrow.color = { .3 , .3 , .3 , .9 }
thisrow.type = t.type
thisrow.func = t.func
thisrow.name = t.name
thisrow.notext = t.notext
thisrow.icon = t.icon
thisrow.iconalign = t.iconalign
thisrow.hidden = t.hidden or false
thisrow.onenter = t.onenter
thisrow.onleave = t.onleave
local text = detailsFramework : NewLabel ( thisrow , nil , self._name .. " $parentLabel " .. index , " text " )
text : SetPoint ( " left " , thisrow , " left " , 2 , 0 )
text : SetText ( t.name )
tinsert ( self._raw_rows , t )
tinsert ( self.rows , thisrow )
if ( need_update ) then
self : AlignRows ( )
end
end
local align_rows = function ( self )
local rows_shown = 0
for index , row in ipairs ( self.rows ) do
if ( not row.hidden ) then
rows_shown = rows_shown + 1
end
end
local cur_width = 1
local row_width = self._width / max ( rows_shown , 0.0001 )
local sindex = 1
wipe ( self._anchors )
for index , row in ipairs ( self.rows ) do
if ( not row.hidden ) then
if ( self._autowidth ) then
if ( self._raw_rows [ index ] . width ) then
row.width = self._raw_rows [ index ] . width
else
row.width = row_width
end
row : SetPoint ( " topleft " , self , " topleft " , cur_width , - 1 )
tinsert ( self._anchors , cur_width )
cur_width = cur_width + row_width + 1
else
row : SetPoint ( " topleft " , self , " topleft " , cur_width , - 1 )
row.width = self._raw_rows [ index ] . width
tinsert ( self._anchors , cur_width )
cur_width = cur_width + self._raw_rows [ index ] . width + 1
end
row : Show ( )
local rowType = row.type
if ( rowType == " text " ) then
for i = 1 , # self.scrollframe . lines do
local line = self.scrollframe . lines [ i ]
local text = tremove ( line.text_available )
if ( not text ) then
self : CreateRowText ( line )
text = tremove ( line.text_available )
end
tinsert ( line.text_inuse , text )
text : SetPoint ( " left " , line , " left " , self._anchors [ # self._anchors ] , 0 )
text : SetWidth ( row.width )
detailsFramework : SetFontSize ( text , row.textsize or 10 )
text : SetJustifyH ( row.textalign or " left " )
end
elseif ( rowType == " entry " ) then
for i = 1 , # self.scrollframe . lines do
local line = self.scrollframe . lines [ i ]
local entry = tremove ( line.entry_available )
if ( not entry ) then
self : CreateRowEntry ( line )
entry = tremove ( line.entry_available )
end
tinsert ( line.entry_inuse , entry )
entry : SetPoint ( " left " , line , " left " , self._anchors [ # self._anchors ] , 0 )
if ( sindex == rows_shown ) then
entry : SetWidth ( row.width - 25 )
else
entry : SetWidth ( row.width )
end
entry.func = row.func
entry.onenter_func = nil
entry.onleave_func = nil
if ( row.onenter ) then
entry.onenter_func = row.onenter
end
if ( row.onleave ) then
entry.onleave_func = row.onleave
end
end
elseif ( rowType == " checkbox " ) then
for i = 1 , # self.scrollframe . lines do
local line = self.scrollframe . lines [ i ]
local checkbox = tremove ( line.checkbox_available )
if ( not checkbox ) then
self : CreateCheckbox ( line )
checkbox = tremove ( line.checkbox_available )
end
tinsert ( line.checkbox_inuse , checkbox )
checkbox : SetPoint ( " left " , line , " left " , self._anchors [ # self._anchors ] + ( ( row.width - 20 ) / 2 ) , 0 )
if ( sindex == rows_shown ) then
checkbox : SetWidth ( 20 )
--checkbox:SetWidth(row.width - 25)
else
checkbox : SetWidth ( 20 )
end
checkbox.onenter_func = nil
checkbox.onleave_func = nil
end
elseif ( rowType == " button " ) then
for i = 1 , # self.scrollframe . lines do
local line = self.scrollframe . lines [ i ]
local button = tremove ( line.button_available )
if ( not button ) then
self : CreateRowButton ( line )
button = tremove ( line.button_available )
end
tinsert ( line.button_inuse , button )
button : SetPoint ( " left " , line , " left " , self._anchors [ # self._anchors ] , 0 )
if ( sindex == rows_shown ) then
button : SetWidth ( row.width - 25 )
else
button : SetWidth ( row.width )
end
if ( row.icon ) then
button._icon . texture = row.icon
button._icon : ClearAllPoints ( )
if ( row.iconalign ) then
if ( row.iconalign == " center " ) then
button._icon : SetPoint ( " center " , button , " center " )
elseif ( row.iconalign == " right " ) then
button._icon : SetPoint ( " right " , button , " right " )
end
else
button._icon : SetPoint ( " left " , button , " left " )
end
end
if ( row.name and not row.notext ) then
button._text : SetPoint ( " left " , button._icon , " right " , 2 , 0 )
button._text . text = row.name
end
button.onenter_func = nil
button.onleave_func = nil
if ( row.onenter ) then
button.onenter_func = row.onenter
end
if ( row.onleave ) then
button.onleave_func = row.onleave
end
end
elseif ( rowType == " icon " ) then
for i = 1 , # self.scrollframe . lines do
local line = self.scrollframe . lines [ i ]
local icon = tremove ( line.icon_available )
if ( not icon ) then
self : CreateRowIcon ( line )
icon = tremove ( line.icon_available )
end
tinsert ( line.icon_inuse , icon )
icon : SetPoint ( " left " , line , " left " , self._anchors [ # self._anchors ] + ( ( ( row.width or 22 ) - 22 ) / 2 ) , 0 )
icon.func = row.func
end
elseif ( rowType == " texture " ) then
for i = 1 , # self.scrollframe . lines do
local line = self.scrollframe . lines [ i ]
local texture = tremove ( line.texture_available )
if ( not texture ) then
self : CreateRowTexture ( line )
texture = tremove ( line.texture_available )
end
tinsert ( line.texture_inuse , texture )
texture : SetPoint ( " left " , line , " left " , self._anchors [ # self._anchors ] + ( ( ( row.width or 22 ) - 22 ) / 2 ) , 0 )
end
end
sindex = sindex + 1
else
row : Hide ( )
end
end
if ( # self.rows > 0 ) then
if ( self._autowidth ) then
self.rows [ # self.rows ] : SetWidth ( row_width - rows_shown + 1 )
else
self.rows [ # self.rows ] : SetWidth ( self._raw_rows [ rows_shown ] . width - rows_shown + 1 )
end
end
self.showing_amt = rows_shown
end
local update_rows = function ( self , updated_rows )
for i = 1 , # updated_rows do
local t = updated_rows [ i ]
local raw = self._raw_rows [ i ]
if ( not raw ) then
self : AddRow ( t )
else
raw.name = t.name
raw.hidden = t.hidden or false
raw.textsize = t.textsize
raw.textalign = t.textalign
local widget = self.rows [ i ]
widget.name = t.name
widget.textsize = t.textsize
widget.textalign = t.textalign
widget.hidden = t.hidden or false
--
widget.onenter = t.onenter
widget.onleave = t.onleave
--
widget.text : SetText ( t.name )
detailsFramework : SetFontSize ( widget.text , raw.textsize or 10 )
widget.text : SetJustifyH ( raw.textalign or " left " )
end
end
for i = # updated_rows + 1 , # self._raw_rows do
local raw = self._raw_rows [ i ]
local widget = self.rows [ i ]
raw.hidden = true
widget.hidden = true
end
for index , row in ipairs ( self.scrollframe . lines ) do
for i = # row.text_inuse , 1 , - 1 do
tinsert ( row.text_available , tremove ( row.text_inuse , i ) )
end
for i = 1 , # row.text_available do
row.text_available [ i ] : Hide ( )
end
for i = # row.entry_inuse , 1 , - 1 do
tinsert ( row.entry_available , tremove ( row.entry_inuse , i ) )
end
for i = 1 , # row.entry_available do
row.entry_available [ i ] : Hide ( )
end
for i = # row.button_inuse , 1 , - 1 do
tinsert ( row.button_available , tremove ( row.button_inuse , i ) )
end
for i = 1 , # row.button_available do
row.button_available [ i ] : Hide ( )
end
for i = # row.checkbox_inuse , 1 , - 1 do
tinsert ( row.checkbox_available , tremove ( row.checkbox_inuse , i ) )
end
for i = 1 , # row.checkbox_available do
row.checkbox_available [ i ] : Hide ( )
end
for i = # row.icon_inuse , 1 , - 1 do
tinsert ( row.icon_available , tremove ( row.icon_inuse , i ) )
end
for i = 1 , # row.icon_available do
row.icon_available [ i ] : Hide ( )
end
for i = # row.texture_inuse , 1 , - 1 do
tinsert ( row.texture_available , tremove ( row.texture_inuse , i ) )
end
for i = 1 , # row.texture_available do
row.texture_available [ i ] : Hide ( )
end
end
self.current_header = updated_rows
self : AlignRows ( )
end
local create_panel_text = function ( self , row )
row.text_total = row.text_total + 1
local text = detailsFramework : NewLabel ( row , nil , self._name .. " $parentLabel " .. row.text_total , " text " .. row.text_total )
tinsert ( row.text_available , text )
end
local create_panel_entry = function ( self , row )
row.entry_total = row.entry_total + 1
local editbox = detailsFramework : NewTextEntry ( row , nil , " $parentEntry " .. row.entry_total , " entry " , 120 , 20 )
editbox.align = " left "
editbox : SetHook ( " OnEnterPressed " , function ( )
editbox.widget . focuslost = true
editbox : ClearFocus ( )
editbox.func ( editbox.index , editbox.text )
return true
end )
editbox : SetHook ( " OnEnter " , function ( )
if ( editbox.onenter_func ) then
pcall ( editbox.onenter_func , editbox )
end
end )
editbox : SetHook ( " OnLeave " , function ( )
if ( editbox.onleave_func ) then
pcall ( editbox.onleave_func , editbox )
end
end )
editbox.editbox . current_bordercolor = { 1 , 1 , 1 , 0.1 }
editbox : SetTemplate ( detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " ) )
editbox : SetBackdropColor ( .2 , .2 , .2 , 0.7 )
tinsert ( row.entry_available , editbox )
end
local create_panel_checkbox = function ( self , row )
--row.checkbox_available
row.checkbox_total = row.checkbox_total + 1
local switch = detailsFramework : NewSwitch ( row , nil , " $parentCheckBox " .. row.checkbox_total , nil , 20 , 20 , nil , nil , false )
switch : SetAsCheckBox ( )
switch : SetTemplate ( detailsFramework : GetTemplate ( " switch " , " OPTIONS_CHECKBOX_TEMPLATE " ) )
tinsert ( row.checkbox_available , switch )
end
local create_panel_button = function ( self , row )
row.button_total = row.button_total + 1
local button = detailsFramework : NewButton ( row , nil , " $parentButton " .. row.button_total , " button " .. row.button_total , 120 , 20 )
--create icon and the text
local icon = detailsFramework : NewImage ( button , nil , 20 , 20 )
local text = detailsFramework : NewLabel ( button )
button._icon = icon
button._text = text
button : SetHook ( " OnEnter " , button_on_enter )
button : SetHook ( " OnLeave " , button_on_leave )
tinsert ( row.button_available , button )
end
local icon_onclick = function ( texture , iconbutton )
iconbutton._icon . texture = texture
iconbutton.func ( iconbutton.index , texture )
end
local create_panel_icon = function ( self , row )
row.icon_total = row.icon_total + 1
local iconbutton = detailsFramework : NewButton ( row , nil , " $parentIconButton " .. row.icon_total , " iconbutton " , 22 , 20 )
iconbutton : SetHook ( " OnEnter " , button_on_enter )
iconbutton : SetHook ( " OnLeave " , button_on_leave )
iconbutton : SetHook ( " OnMouseUp " , function ( )
detailsFramework : IconPick ( icon_onclick , true , iconbutton )
return true
end )
local icon = detailsFramework : NewImage ( iconbutton , nil , 20 , 20 , " artwork " , nil , " _icon " , " $parentIcon " .. row.icon_total )
iconbutton._icon = icon
icon : SetPoint ( " center " , iconbutton , " center " , 0 , 0 )
tinsert ( row.icon_available , iconbutton )
end
local create_panel_texture = function ( self , row )
row.texture_total = row.texture_total + 1
local texture = detailsFramework : NewImage ( row , nil , 20 , 20 , " artwork " , nil , " _icon " .. row.texture_total , " $parentIcon " .. row.texture_total )
tinsert ( row.texture_available , texture )
end
local set_fill_function = function ( self , func )
self._fillfunc = func
end
local set_total_function = function ( self , func )
self._totalfunc = func
end
local drop_header_function = function ( self )
wipe ( self.rows )
end
local fillpanel_update_size = function ( self , elapsed )
local panel = self.MyObject
panel._width = panel : GetWidth ( )
panel._height = panel : GetHeight ( )
panel : UpdateRowAmount ( )
if ( panel.current_header ) then
update_rows ( panel , panel.current_header )
end
panel : Refresh ( )
self : SetScript ( " OnUpdate " , nil )
end
-- ~fillpanel
--alias
function detailsFramework : CreateFillPanel ( parent , rows , w , h , total_lines , fill_row , autowidth , options , member , name )
return detailsFramework : NewFillPanel ( parent , rows , name , member , w , h , total_lines , fill_row , autowidth , options )
end
function detailsFramework : NewFillPanel ( parent , rows , name , member , w , h , total_lines , fill_row , autowidth , options )
local panel = detailsFramework : NewPanel ( parent , parent , name , member , w , h )
panel.backdrop = nil
options = options or { rowheight = 20 }
panel.rows = { }
panel.AddRow = add_row
panel.AlignRows = align_rows
panel.UpdateRows = update_rows
panel.CreateRowText = create_panel_text
panel.CreateRowEntry = create_panel_entry
panel.CreateRowButton = create_panel_button
panel.CreateCheckbox = create_panel_checkbox
panel.CreateRowIcon = create_panel_icon
panel.CreateRowTexture = create_panel_texture
panel.SetFillFunction = set_fill_function
panel.SetTotalFunction = set_total_function
panel.DropHeader = drop_header_function
panel._name = name
panel._width = w
panel._height = h
panel._raw_rows = { }
panel._anchors = { }
panel._fillfunc = fill_row
panel._totalfunc = total_lines
panel._autowidth = autowidth
panel : SetScript ( " OnSizeChanged " , function ( )
panel : SetScript ( " OnUpdate " , fillpanel_update_size )
end )
for index , t in ipairs ( rows ) do
panel.AddRow ( panel , t )
end
local refresh_fillbox = function ( self )
local offset = FauxScrollFrame_GetOffset ( self )
local filled_lines = panel._totalfunc ( panel )
for index = 1 , # self.lines do
local row = self.lines [ index ]
if ( index <= filled_lines ) then
local real_index = index + offset
local results = panel._fillfunc ( real_index , panel )
if ( results and results [ 1 ] ) then
row : Show ( )
local text , entry , button , icon , texture , checkbox = 1 , 1 , 1 , 1 , 1 , 1
for index , t in ipairs ( panel.rows ) do
if ( not t.hidden ) then
if ( t.type == " text " ) then
local fontstring = row.text_inuse [ text ]
text = text + 1
fontstring : SetText ( results [ index ] )
fontstring.index = real_index
fontstring : Show ( )
elseif ( t.type == " entry " ) then
local entrywidget = row.entry_inuse [ entry ]
entry = entry + 1
entrywidget.index = real_index
if ( type ( results [ index ] ) == " table " ) then
entrywidget : SetText ( results [ index ] . text )
entrywidget.id = results [ index ] . id
entrywidget.data1 = results [ index ] . data1
entrywidget.data2 = results [ index ] . data2
else
entrywidget : SetText ( results [ index ] )
end
entrywidget : SetCursorPosition ( 0 )
entrywidget : Show ( )
elseif ( t.type == " checkbox " ) then
local checkboxwidget = row.checkbox_inuse [ button ]
checkbox = checkbox + 1
checkboxwidget.index = real_index
checkboxwidget : SetValue ( results [ index ] )
local func = function ( )
t.func ( real_index , index )
panel : Refresh ( )
end
checkboxwidget.OnSwitch = func
elseif ( t.type == " button " ) then
local buttonwidget = row.button_inuse [ button ]
button = button + 1
buttonwidget.index = real_index
if ( type ( results [ index ] ) == " table " ) then
if ( results [ index ] . text ) then
buttonwidget : SetText ( results [ index ] . text )
end
if ( results [ index ] . icon ) then
buttonwidget._icon : SetTexture ( results [ index ] . icon )
end
if ( results [ index ] . func ) then
local func = function ( )
t.func ( real_index , results [ index ] . value )
panel : Refresh ( )
end
buttonwidget : SetClickFunction ( func )
else
local func = function ( )
t.func ( real_index , index )
panel : Refresh ( )
end
buttonwidget : SetClickFunction ( func )
end
buttonwidget.id = results [ index ] . id
buttonwidget.data1 = results [ index ] . data1
buttonwidget.data2 = results [ index ] . data2
else
local func = function ( )
t.func ( real_index , index )
panel : Refresh ( )
end
buttonwidget : SetClickFunction ( func )
buttonwidget : SetText ( results [ index ] )
end
buttonwidget : Show ( )
elseif ( t.type == " icon " ) then
local iconwidget = row.icon_inuse [ icon ]
icon = icon + 1
iconwidget.line = index
iconwidget.index = real_index
if ( type ( results [ index ] ) == " string " ) then
local result = results [ index ] : gsub ( " .-% \\ " , " " )
iconwidget._icon . texture = results [ index ]
iconwidget._icon : SetTexCoord ( 0.1 , .9 , 0.1 , .9 )
elseif ( type ( results [ index ] ) == " table " ) then
iconwidget._icon : SetTexture ( results [ index ] . texture )
local textCoord = results [ index ] . texcoord
if ( textCoord ) then
iconwidget._icon : SetTexCoord ( unpack ( textCoord ) )
else
iconwidget._icon : SetTexCoord ( 0.1 , .9 , 0.1 , .9 )
end
local color = results [ index ] . color
if ( color ) then
local r , g , b , a = detailsFramework : ParseColors ( color )
iconwidget._icon : SetVertexColor ( r , g , b , a )
else
iconwidget._icon : SetVertexColor ( 1 , 1 , 1 , 1 )
end
else
iconwidget._icon : SetTexture ( results [ index ] )
iconwidget._icon : SetTexCoord ( 0.1 , .9 , 0.1 , .9 )
end
iconwidget : Show ( )
elseif ( t.type == " texture " ) then
local texturewidget = row.texture_inuse [ texture ]
texture = texture + 1
texturewidget.line = index
texturewidget.index = real_index
if ( type ( results [ index ] ) == " string " ) then
local result = results [ index ] : gsub ( " .-% \\ " , " " )
texturewidget.texture = results [ index ]
elseif ( type ( results [ index ] ) == " table " ) then
texturewidget : SetTexture ( results [ index ] . texture )
local textCoord = results [ index ] . texcoord
if ( textCoord ) then
texturewidget : SetTexCoord ( unpack ( textCoord ) )
else
texturewidget : SetTexCoord ( 0 , 1 , 0 , 1 )
end
local color = results [ index ] . color
if ( color ) then
local r , g , b , a = detailsFramework : ParseColors ( color )
texturewidget : SetVertexColor ( r , g , b , a )
else
texturewidget : SetVertexColor ( 1 , 1 , 1 , 1 )
end
else
texturewidget : SetTexture ( results [ index ] )
end
texturewidget : Show ( )
end
end
end
else
row : Hide ( )
end
else
row : Hide ( )
end
end
end
function panel : Refresh ( )
if ( type ( panel._totalfunc ) == " boolean " ) then
--not yet initialized
return
end
local filled_lines = panel._totalfunc ( panel )
local scroll_total_lines = # panel.scrollframe . lines
local line_height = options.rowheight
refresh_fillbox ( panel.scrollframe )
FauxScrollFrame_Update ( panel.scrollframe , filled_lines , scroll_total_lines , line_height )
panel.scrollframe : Show ( )
end
local scrollframe = CreateFrame ( " scrollframe " , name .. " Scroll " , panel.widget , " FauxScrollFrameTemplate " , " BackdropTemplate " )
scrollframe : SetScript ( " OnVerticalScroll " , function ( self , offset ) FauxScrollFrame_OnVerticalScroll ( self , offset , 20 , panel.Refresh ) end )
scrollframe : SetPoint ( " topleft " , panel.widget , " topleft " , 0 , - 21 )
scrollframe : SetPoint ( " topright " , panel.widget , " topright " , - 23 , - 21 )
scrollframe : SetPoint ( " bottomleft " , panel.widget , " bottomleft " )
scrollframe : SetPoint ( " bottomright " , panel.widget , " bottomright " , - 23 , 0 )
scrollframe : SetSize ( w , h )
panel.scrollframe = scrollframe
scrollframe.lines = { }
detailsFramework : ReskinSlider ( scrollframe )
--create lines
function panel : UpdateRowAmount ( )
local size = options.rowheight
local amount = math.floor ( ( ( panel._height - 21 ) / size ) )
for i = # scrollframe.lines + 1 , amount do
local row = CreateFrame ( " frame " , panel : GetName ( ) .. " Row_ " .. i , panel.widget , " BackdropTemplate " )
row : SetSize ( 1 , size )
row.color = { 1 , 1 , 1 , .2 }
row : SetBackdrop ( { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] } )
if ( i % 2 == 0 ) then
row : SetBackdropColor ( .5 , .5 , .5 , 0.2 )
else
row : SetBackdropColor ( 1 , 1 , 1 , 0.00 )
end
row : SetPoint ( " topleft " , scrollframe , " topleft " , 0 , ( i - 1 ) * size * - 1 )
row : SetPoint ( " topright " , scrollframe , " topright " , 0 , ( i - 1 ) * size * - 1 )
tinsert ( scrollframe.lines , row )
row.text_available = { }
row.text_inuse = { }
row.text_total = 0
row.entry_available = { }
row.entry_inuse = { }
row.entry_total = 0
row.button_available = { }
row.button_inuse = { }
row.button_total = 0
row.checkbox_available = { }
row.checkbox_inuse = { }
row.checkbox_total = 0
row.icon_available = { }
row.icon_inuse = { }
row.icon_total = 0
row.texture_available = { }
row.texture_inuse = { }
row.texture_total = 0
end
end
panel : UpdateRowAmount ( )
panel.AlignRows ( panel )
return panel
end
------------color pick
local color_pick_func = function ( )
local r , g , b = ColorPickerFrame : GetColorRGB ( )
local a = OpacitySliderFrame : GetValue ( )
ColorPickerFrame : dcallback ( r , g , b , a , ColorPickerFrame.dframe )
end
local color_pick_func_cancel = function ( )
ColorPickerFrame : SetColorRGB ( unpack ( ColorPickerFrame.previousValues ) )
local r , g , b = ColorPickerFrame : GetColorRGB ( )
local a = OpacitySliderFrame : GetValue ( )
ColorPickerFrame : dcallback ( r , g , b , a , ColorPickerFrame.dframe )
end
function detailsFramework : ColorPick ( frame , r , g , b , alpha , callback )
ColorPickerFrame : ClearAllPoints ( )
ColorPickerFrame : SetPoint ( " bottomleft " , frame , " topright " , 0 , 0 )
ColorPickerFrame.dcallback = callback
ColorPickerFrame.dframe = frame
ColorPickerFrame.func = color_pick_func
ColorPickerFrame.opacityFunc = color_pick_func
ColorPickerFrame.cancelFunc = color_pick_func_cancel
ColorPickerFrame.opacity = alpha
ColorPickerFrame.hasOpacity = alpha and true
ColorPickerFrame.previousValues = { r , g , b }
ColorPickerFrame : SetParent ( UIParent )
ColorPickerFrame : SetFrameStrata ( " tooltip " )
ColorPickerFrame : SetColorRGB ( r , g , b )
ColorPickerFrame : Show ( )
end
------------icon pick
function detailsFramework : IconPick ( callback , close_when_select , param1 , param2 )
if ( not detailsFramework.IconPickFrame ) then
local string_lower = string.lower
detailsFramework.IconPickFrame = CreateFrame ( " frame " , " DetailsFrameworkIconPickFrame " , UIParent , " BackdropTemplate " )
tinsert ( UISpecialFrames , " DetailsFrameworkIconPickFrame " )
detailsFramework.IconPickFrame : SetFrameStrata ( " FULLSCREEN " )
detailsFramework.IconPickFrame : SetPoint ( " center " , UIParent , " center " )
detailsFramework.IconPickFrame : SetWidth ( 416 )
detailsFramework.IconPickFrame : SetHeight ( 350 )
detailsFramework.IconPickFrame : EnableMouse ( true )
detailsFramework.IconPickFrame : SetMovable ( true )
detailsFramework : CreateTitleBar ( detailsFramework.IconPickFrame , " Details! Framework Icon Picker " )
detailsFramework.IconPickFrame : SetBackdrop ( { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } )
detailsFramework.IconPickFrame : SetBackdropBorderColor ( 0 , 0 , 0 )
detailsFramework.IconPickFrame : SetBackdropColor ( 24 / 255 , 24 / 255 , 24 / 255 , .8 )
detailsFramework.IconPickFrame : SetFrameLevel ( 5000 )
detailsFramework.IconPickFrame : SetScript ( " OnMouseDown " , function ( self )
if ( not self.isMoving ) then
detailsFramework.IconPickFrame : StartMoving ( )
self.isMoving = true
end
end )
detailsFramework.IconPickFrame : SetScript ( " OnMouseUp " , function ( self )
if ( self.isMoving ) then
detailsFramework.IconPickFrame : StopMovingOrSizing ( )
self.isMoving = nil
end
end )
detailsFramework.IconPickFrame . emptyFunction = function ( ) end
detailsFramework.IconPickFrame . callback = detailsFramework.IconPickFrame . emptyFunction
detailsFramework.IconPickFrame . preview = CreateFrame ( " frame " , nil , UIParent , " BackdropTemplate " )
detailsFramework.IconPickFrame . preview : SetFrameStrata ( " tooltip " )
detailsFramework.IconPickFrame . preview : SetFrameLevel ( 6001 )
detailsFramework.IconPickFrame . preview : SetSize ( 76 , 76 )
local preview_image_bg = detailsFramework : NewImage ( detailsFramework.IconPickFrame . preview , nil , 76 , 76 )
preview_image_bg : SetDrawLayer ( " background " , 0 )
preview_image_bg : SetAllPoints ( detailsFramework.IconPickFrame . preview )
preview_image_bg : SetColorTexture ( 0 , 0 , 0 )
local preview_image = detailsFramework : NewImage ( detailsFramework.IconPickFrame . preview , nil , 76 , 76 )
preview_image : SetAllPoints ( detailsFramework.IconPickFrame . preview )
detailsFramework.IconPickFrame . preview.icon = preview_image
detailsFramework.IconPickFrame . preview : Hide ( )
--serach
detailsFramework.IconPickFrame . searchLabel = detailsFramework : NewLabel ( detailsFramework.IconPickFrame , nil , " $parentSearchBoxLabel " , nil , " Search: " )
detailsFramework.IconPickFrame . searchLabel : SetPoint ( " topleft " , detailsFramework.IconPickFrame , " topleft " , 12 , - 36 )
detailsFramework.IconPickFrame . searchLabel : SetTemplate ( detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
detailsFramework.IconPickFrame . searchLabel.fontsize = 12
detailsFramework.IconPickFrame . search = detailsFramework : NewTextEntry ( detailsFramework.IconPickFrame , nil , " $parentSearchBox " , nil , 140 , 20 )
detailsFramework.IconPickFrame . search : SetPoint ( " left " , detailsFramework.IconPickFrame . searchLabel , " right " , 2 , 0 )
detailsFramework.IconPickFrame . search : SetTemplate ( detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " ) )
detailsFramework.IconPickFrame . search : SetHook ( " OnTextChanged " , function ( )
detailsFramework.IconPickFrame . searching = detailsFramework.IconPickFrame . search : GetText ( )
if ( detailsFramework.IconPickFrame . searching == " " ) then
detailsFramework.IconPickFrameScroll : Show ( )
detailsFramework.IconPickFrame . searching = nil
detailsFramework.IconPickFrameScroll . RefreshIcons ( )
else
detailsFramework.IconPickFrameScroll : Hide ( )
FauxScrollFrame_SetOffset ( detailsFramework.IconPickFrame , 1 )
detailsFramework.IconPickFrame . last_filter_index = 1
detailsFramework.IconPickFrameScroll . RefreshIcons ( )
end
end )
--manually enter the icon path
detailsFramework.IconPickFrame . customIcon = detailsFramework : CreateLabel ( detailsFramework.IconPickFrame , " Icon Path: " , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
detailsFramework.IconPickFrame . customIcon : SetPoint ( " bottomleft " , detailsFramework.IconPickFrame , " bottomleft " , 12 , 16 )
detailsFramework.IconPickFrame . customIcon.fontsize = 12
detailsFramework.IconPickFrame . customIconEntry = detailsFramework : CreateTextEntry ( detailsFramework.IconPickFrame , function ( ) end , 200 , 20 , " CustomIconEntry " , _ , _ , detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " ) )
detailsFramework.IconPickFrame . customIconEntry : SetPoint ( " left " , detailsFramework.IconPickFrame . customIcon , " right " , 2 , 0 )
detailsFramework.IconPickFrame . customIconEntry : SetHook ( " OnTextChanged " , function ( )
detailsFramework.IconPickFrame . preview : SetPoint ( " bottom " , detailsFramework.IconPickFrame . customIconEntry.widget , " top " , 0 , 2 )
detailsFramework.IconPickFrame . preview.icon : SetTexture ( detailsFramework.IconPickFrame . customIconEntry : GetText ( ) )
detailsFramework.IconPickFrame . preview : Show ( )
end )
detailsFramework.IconPickFrame . customIconEntry : SetHook ( " OnEnter " , function ( )
detailsFramework.IconPickFrame . preview : SetPoint ( " bottom " , detailsFramework.IconPickFrame . customIconEntry.widget , " top " , 0 , 2 )
detailsFramework.IconPickFrame . preview.icon : SetTexture ( detailsFramework.IconPickFrame . customIconEntry : GetText ( ) )
detailsFramework.IconPickFrame . preview : Show ( )
end )
--close button
local close_button = CreateFrame ( " button " , nil , detailsFramework.IconPickFrame , " UIPanelCloseButton " , " BackdropTemplate " )
close_button : SetWidth ( 32 )
close_button : SetHeight ( 32 )
close_button : SetPoint ( " TOPRIGHT " , detailsFramework.IconPickFrame , " TOPRIGHT " , - 8 , - 7 )
close_button : SetFrameLevel ( close_button : GetFrameLevel ( ) + 2 )
close_button : SetAlpha ( 0 ) --just hide, it is used below
--accept custom icon button
local accept_custom_icon = function ( )
local path = detailsFramework.IconPickFrame . customIconEntry : GetText ( )
detailsFramework : QuickDispatch ( detailsFramework.IconPickFrame . callback , path , detailsFramework.IconPickFrame . param1 , detailsFramework.IconPickFrame . param2 )
if ( detailsFramework.IconPickFrame . click_close ) then
close_button : Click ( )
end
end
detailsFramework.IconPickFrame . customIconAccept = detailsFramework : CreateButton ( detailsFramework.IconPickFrame , accept_custom_icon , 82 , 20 , " Accept " , nil , nil , nil , nil , nil , nil , detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " ) , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
detailsFramework.IconPickFrame . customIconAccept : SetPoint ( " left " , detailsFramework.IconPickFrame . customIconEntry , " right " , 2 , 0 )
--fill with icons
local MACRO_ICON_FILENAMES = { }
local SPELLNAMES_CACHE = { }
detailsFramework.IconPickFrame : SetScript ( " OnShow " , function ( )
MACRO_ICON_FILENAMES [ 1 ] = " INV_MISC_QUESTIONMARK "
local index = 2
for i = 1 , GetNumSpellTabs ( ) do
local tab , tabTex , offset , numSpells , _ = GetSpellTabInfo ( i )
offset = offset + 1
local tabEnd = offset + numSpells
for j = offset , tabEnd - 1 do
--to get spell info by slot, you have to pass in a pet argument
local spellType , ID = GetSpellBookItemInfo ( j , " player " )
if ( spellType ~= " FLYOUT " ) then
MACRO_ICON_FILENAMES [ index ] = GetSpellBookItemTexture ( j , " player " ) or 0
SPELLNAMES_CACHE [ index ] = GetSpellInfo ( ID )
index = index + 1
elseif ( spellType == " FLYOUT " ) then
local _ , _ , numSlots , isKnown = GetFlyoutInfo ( ID )
if ( isKnown and numSlots > 0 ) then
for k = 1 , numSlots do
local spellID , overrideSpellID , isKnown = GetFlyoutSlotInfo ( ID , k )
if ( isKnown ) then
MACRO_ICON_FILENAMES [ index ] = GetSpellTexture ( spellID ) or 0
SPELLNAMES_CACHE [ index ] = GetSpellInfo ( spellID )
index = index + 1
end
end
end
end
end
end
GetLooseMacroItemIcons ( MACRO_ICON_FILENAMES )
GetLooseMacroIcons ( MACRO_ICON_FILENAMES )
GetMacroIcons ( MACRO_ICON_FILENAMES )
GetMacroItemIcons ( MACRO_ICON_FILENAMES )
--reset the custom icon text entry
detailsFramework.IconPickFrame . customIconEntry : SetText ( " " )
--reset the search text entry
detailsFramework.IconPickFrame . search : SetText ( " " )
end )
detailsFramework.IconPickFrame : SetScript ( " OnHide " , function ( )
wipe ( MACRO_ICON_FILENAMES )
wipe ( SPELLNAMES_CACHE )
detailsFramework.IconPickFrame . preview : Hide ( )
collectgarbage ( )
end )
detailsFramework.IconPickFrame . buttons = { }
local onClickFunction = function ( self )
detailsFramework : QuickDispatch ( detailsFramework.IconPickFrame . callback , self.icon : GetTexture ( ) , detailsFramework.IconPickFrame . param1 , detailsFramework.IconPickFrame . param2 )
if ( detailsFramework.IconPickFrame . click_close ) then
close_button : Click ( )
end
end
local onEnter = function ( self )
detailsFramework.IconPickFrame . preview : SetPoint ( " bottom " , self , " top " , 0 , 2 )
detailsFramework.IconPickFrame . preview.icon : SetTexture ( self.icon : GetTexture ( ) )
detailsFramework.IconPickFrame . preview : Show ( )
self.icon : SetBlendMode ( " ADD " )
end
local onLeave = function ( self )
detailsFramework.IconPickFrame . preview : Hide ( )
self.icon : SetBlendMode ( " BLEND " )
end
local backdrop = { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tile = true , tileSize = 16 ,
insets = { left = 0 , right = 0 , top = 0 , bottom = 0 } , edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 }
for _ , button in ipairs ( detailsFramework.IconPickFrame . buttons ) do
button : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
end
local width = 412
local height = 248
local linesAmount = 6
local lineHeight = 40
local updateIconScroll = function ( self , data , offset , totalLines )
for i = 1 , totalLines do
local index = i + offset
local iconsInThisLine = data [ index ]
if ( iconsInThisLine ) then
local line = self : GetLine ( i )
for o = 1 , # iconsInThisLine do
local _ , _ , texture = GetSpellInfo ( iconsInThisLine [ o ] )
if ( texture ) then
line.buttons [ o ] . icon : SetTexture ( texture )
line.buttons [ o ] . texture = texture
else
line.buttons [ o ] . icon : SetTexture ( iconsInThisLine [ o ] )
line.buttons [ o ] . texture = iconsInThisLine [ o ]
end
end
end
end
end
local lower = string.lower
local scroll = detailsFramework : CreateScrollBox ( detailsFramework.IconPickFrame , " DetailsFrameworkIconPickFrameScroll " , updateIconScroll , { } , width , height , linesAmount , lineHeight )
detailsFramework : ReskinSlider ( scroll )
scroll : SetPoint ( " topleft " , detailsFramework.IconPickFrame , " topleft " , 2 , - 58 )
function scroll . RefreshIcons ( )
--build icon list
local iconList = { }
local numMacroIcons = # MACRO_ICON_FILENAMES
local filter
if ( detailsFramework.IconPickFrame . searching ) then
filter = lower ( detailsFramework.IconPickFrame . searching )
end
if ( filter and filter ~= " " ) then
local index
local currentTable
for i = 1 , # SPELLNAMES_CACHE do
if ( SPELLNAMES_CACHE [ i ] and SPELLNAMES_CACHE [ i ] : lower ( ) : find ( filter ) ) then
if ( not index ) then
index = 1
local t = { }
iconList [ # iconList + 1 ] = t
currentTable = t
end
currentTable [ index ] = SPELLNAMES_CACHE [ i ]
index = index + 1
if ( index == 11 ) then
index = nil
end
end
end
else
for i = 1 , # SPELLNAMES_CACHE , 10 do
local t = { }
iconList [ # iconList + 1 ] = t
for o = i , i + 9 do
if ( SPELLNAMES_CACHE [ o ] ) then
t [ # t + 1 ] = SPELLNAMES_CACHE [ o ]
end
end
end
for i = 1 , # MACRO_ICON_FILENAMES , 10 do
local t = { }
iconList [ # iconList + 1 ] = t
for o = i , i + 9 do
if ( MACRO_ICON_FILENAMES [ o ] ) then
t [ # t + 1 ] = MACRO_ICON_FILENAMES [ o ]
end
end
end
end
--set data and refresh
scroll : SetData ( iconList )
scroll : Refresh ( )
end
--create the lines and button of the scroll box
for i = 1 , linesAmount do
scroll : CreateLine ( function ( self , index )
local line = CreateFrame ( " button " , " $parentLine " .. index , self , " BackdropTemplate " )
line : SetPoint ( " topleft " , self , " topleft " , 1 , - ( ( index - 1 ) * ( lineHeight + 1 ) ) - 1 )
line : SetSize ( width - 2 , lineHeight )
line : SetBackdrop ( { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } )
line : SetBackdropColor ( .2 , .2 , .2 , .5 )
line.buttons = { }
local lastButton
for o = 1 , 10 do
local button = CreateFrame ( " button " , " $parentIcon " .. o , line )
if ( not lastButton ) then
button : SetPoint ( " left " , line , " left " , 0 , 0 )
else
button : SetPoint ( " left " , lastButton , " right " , 1 , 0 )
end
button : SetSize ( lineHeight , lineHeight )
button.icon = button : CreateTexture ( " $parentIcon " , " overlay " )
button.icon : SetAllPoints ( )
button.icon : SetTexCoord ( .1 , .9 , .1 , .9 )
line.buttons [ o ] = button
button : SetScript ( " OnEnter " , onEnter )
button : SetScript ( " OnLeave " , onLeave )
button : SetScript ( " OnClick " , onClickFunction )
lastButton = button
end
return line
end )
end
detailsFramework.IconPickFrameScroll = scroll
detailsFramework.IconPickFrame : Hide ( )
end
detailsFramework.IconPickFrame . param1 , detailsFramework.IconPickFrame . param2 = param1 , param2
detailsFramework.IconPickFrame : Show ( )
detailsFramework.IconPickFrame . callback = callback or detailsFramework.IconPickFrame . emptyFunction
detailsFramework.IconPickFrame . click_close = close_when_select
detailsFramework.IconPickFrameScroll . RefreshIcons ( )
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function detailsFramework : ShowPanicWarning ( text )
if ( not detailsFramework.PanicWarningWindow ) then
detailsFramework.PanicWarningWindow = CreateFrame ( " frame " , " DetailsFrameworkPanicWarningWindow " , UIParent , " BackdropTemplate " )
detailsFramework.PanicWarningWindow : SetHeight ( 80 )
detailsFramework.PanicWarningWindow : SetBackdrop ( { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } )
detailsFramework.PanicWarningWindow : SetBackdropColor ( 1 , 0 , 0 , 0.2 )
detailsFramework.PanicWarningWindow : SetPoint ( " topleft " , UIParent , " topleft " , 0 , - 250 )
detailsFramework.PanicWarningWindow : SetPoint ( " topright " , UIParent , " topright " , 0 , - 250 )
detailsFramework.PanicWarningWindow . text = detailsFramework.PanicWarningWindow : CreateFontString ( nil , " overlay " , " GameFontNormal " )
detailsFramework.PanicWarningWindow . text : SetPoint ( " center " , detailsFramework.PanicWarningWindow , " center " )
detailsFramework.PanicWarningWindow . text : SetTextColor ( 1 , 0.6 , 0 )
end
detailsFramework.PanicWarningWindow . text : SetText ( text )
detailsFramework.PanicWarningWindow : Show ( )
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local simple_panel_mouse_down = function ( self , button )
if ( button == " RightButton " ) then
if ( self.IsMoving ) then
self.IsMoving = false
self : StopMovingOrSizing ( )
if ( self.db and self.db . position ) then
detailsFramework : SavePositionOnScreen ( self )
end
end
if ( not self.DontRightClickClose ) then
self : Hide ( )
end
return
end
if ( not self.IsMoving and not self.IsLocked ) then
self.IsMoving = true
self : StartMoving ( )
end
end
local simple_panel_mouse_up = function ( self , button )
if ( self.IsMoving ) then
self.IsMoving = false
self : StopMovingOrSizing ( )
if ( self.db and self.db . position ) then
detailsFramework : SavePositionOnScreen ( self )
end
end
end
local simple_panel_settitle = function ( self , title )
self.Title : SetText ( title )
end
local simple_panel_close_click = function ( self )
self : GetParent ( ) : GetParent ( ) : Hide ( )
end
local SimplePanel_frame_backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true }
local SimplePanel_frame_backdrop_color = { 0 , 0 , 0 , 0.9 }
local SimplePanel_frame_backdrop_border_color = { 0 , 0 , 0 , 1 }
--with_label was making the frame stay in place while its parent moves
--the slider was anchoring to with_label and here here were anchoring the slider again
function detailsFramework : CreateScaleBar ( frame , config ) --~scale
local scaleBar , text = detailsFramework : CreateSlider ( frame , 120 , 14 , 0.6 , 1.6 , 0.1 , config.scale , true , " ScaleBar " , nil , " Scale: " , detailsFramework : GetTemplate ( " slider " , " OPTIONS_SLIDER_TEMPLATE " ) , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
scaleBar.thumb : SetWidth ( 24 )
scaleBar : SetValueStep ( 0.1 )
scaleBar : SetObeyStepOnDrag ( true )
scaleBar.mouseDown = false
rawset ( scaleBar , " lockdown " , true )
--create a custom editbox to enter the scale from text
local editbox = CreateFrame ( " editbox " , nil , scaleBar.widget , " BackdropTemplate " )
editbox : SetSize ( 40 , 20 )
editbox : SetJustifyH ( " center " )
editbox : SetBackdrop ( { bgFile = [[Interface\ACHIEVEMENTFRAME\UI-GuildAchievement-Parchment-Horizontal-Desaturated]] ,
edgeFile = [[Interface\Buttons\WHITE8X8]] ,
tile = true , edgeSize = 1 , tileSize = 64 } )
editbox : SetFontObject ( " GameFontHighlightSmall " )
editbox : SetBackdropColor ( 0 , 0 , 0 , 1 )
editbox : SetScript ( " OnEditFocusGained " , function ( )
end )
editbox : SetScript ( " OnEnterPressed " , function ( )
editbox : ClearFocus ( )
editbox : Hide ( )
local text = editbox : GetText ( )
local newScale = detailsFramework.TextToFloor ( text )
if ( newScale ) then
config.scale = newScale
scaleBar : SetValue ( newScale )
frame : SetScale ( newScale )
editbox.defaultValue = newScale
end
end )
editbox : SetScript ( " OnEscapePressed " , function ( )
editbox : ClearFocus ( )
editbox : Hide ( )
editbox : SetText ( editbox.defaultValue )
end )
scaleBar : SetScript ( " OnMouseDown " , function ( _ , mouseButton )
if ( mouseButton == " RightButton " ) then
editbox : Show ( )
editbox : SetAllPoints ( )
editbox : SetText ( config.scale )
editbox : SetFocus ( true )
editbox.defaultValue = config.scale
elseif ( mouseButton == " LeftButton " ) then
scaleBar.mouseDown = true
end
end )
scaleBar : SetScript ( " OnMouseUp " , function ( _ , mouseButton )
if ( mouseButton == " LeftButton " ) then
scaleBar.mouseDown = false
frame : SetScale ( config.scale )
editbox.defaultValue = config.scale
end
end )
text : SetPoint ( " topleft " , frame , " topleft " , 12 , - 7 )
scaleBar : SetFrameLevel ( detailsFramework.FRAMELEVEL_OVERLAY )
scaleBar.OnValueChanged = function ( _ , _ , value )
if ( scaleBar.mouseDown ) then
config.scale = value
end
end
scaleBar : SetAlpha ( 0.70 )
editbox.defaultValue = config.scale
editbox : SetFocus ( false )
editbox : SetAutoFocus ( false )
editbox : ClearFocus ( )
C_Timer.After ( 1 , function ( )
editbox : SetFocus ( false )
editbox : SetAutoFocus ( false )
editbox : ClearFocus ( )
end )
return scaleBar
end
local no_options = { }
--[=[
options available to panel_options :
NoScripts = false , --if true, won't set OnMouseDown and OnMouseUp (won't be movable)
NoTUISpecialFrame = false , --if true, won't add the frame to 'UISpecialFrames'
DontRightClickClose = false , --if true, won't make the frame close when clicked with the right mouse button
UseScaleBar = false , --if true, will create a scale bar in the top left corner (require a table on 'db' to save the scale)
UseStatusBar = false , --if true, creates a status bar at the bottom of the frame (frame.StatusBar)
NoCloseButton = false , --if true, won't show the close button
NoTitleBar = false , --if true, don't create the title bar
] = ]
function detailsFramework : CreateSimplePanel ( parent , width , height , title , frameName , panelOptions , savedVariableTable )
if ( savedVariableTable and frameName and not savedVariableTable [ frameName ] ) then
savedVariableTable [ frameName ] = {
scale = 1
}
end
if ( not frameName ) then
frameName = " DetailsFrameworkSimplePanel " .. detailsFramework.SimplePanelCounter
detailsFramework.SimplePanelCounter = detailsFramework.SimplePanelCounter + 1
end
if ( not parent ) then
parent = UIParent
end
panelOptions = panelOptions or no_options
local simplePanel = CreateFrame ( " frame " , frameName , UIParent , " BackdropTemplate " )
simplePanel : SetSize ( width or 400 , height or 250 )
simplePanel : SetPoint ( " center " , UIParent , " center " , 0 , 0 )
simplePanel : SetFrameStrata ( " FULLSCREEN " )
simplePanel : EnableMouse ( )
simplePanel : SetMovable ( true )
simplePanel : SetBackdrop ( SimplePanel_frame_backdrop )
simplePanel : SetBackdropColor ( unpack ( SimplePanel_frame_backdrop_color ) )
simplePanel : SetBackdropBorderColor ( unpack ( SimplePanel_frame_backdrop_border_color ) )
simplePanel.DontRightClickClose = panelOptions.DontRightClickClose
if ( not panelOptions.NoTUISpecialFrame ) then
tinsert ( UISpecialFrames , frameName )
end
if ( panelOptions.UseStatusBar ) then
local statusBar = detailsFramework : CreateStatusBar ( simplePanel )
simplePanel.StatusBar = statusBar
end
local titleBar = CreateFrame ( " frame " , frameName .. " TitleBar " , simplePanel , " BackdropTemplate " )
titleBar : SetPoint ( " topleft " , simplePanel , " topleft " , 2 , - 3 )
titleBar : SetPoint ( " topright " , simplePanel , " topright " , - 2 , - 3 )
titleBar : SetHeight ( 20 )
titleBar : SetBackdrop ( SimplePanel_frame_backdrop )
titleBar : SetBackdropColor ( .2 , .2 , .2 , 1 )
titleBar : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
simplePanel.TitleBar = titleBar
local close = CreateFrame ( " button " , frameName and frameName .. " CloseButton " , titleBar )
close : SetFrameLevel ( detailsFramework.FRAMELEVEL_OVERLAY )
close : SetSize ( 16 , 16 )
close : SetNormalTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
close : SetHighlightTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
close : SetPushedTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
close : GetNormalTexture ( ) : SetDesaturated ( true )
close : GetHighlightTexture ( ) : SetDesaturated ( true )
close : GetPushedTexture ( ) : SetDesaturated ( true )
close : SetAlpha ( 0.7 )
close : SetScript ( " OnClick " , simple_panel_close_click )
simplePanel.Close = close
local titleText = titleBar : CreateFontString ( frameName and frameName .. " Title " , " overlay " , " GameFontNormal " )
titleText : SetTextColor ( .8 , .8 , .8 , 1 )
titleText : SetText ( title or " " )
simplePanel.Title = titleText
if ( panelOptions.UseScaleBar and savedVariableTable [ frameName ] ) then
detailsFramework : CreateScaleBar ( simplePanel , savedVariableTable [ frameName ] )
simplePanel : SetScale ( savedVariableTable [ frameName ] . scale )
end
simplePanel.Title : SetPoint ( " center " , titleBar , " center " )
simplePanel.Close : SetPoint ( " right " , titleBar , " right " , - 2 , 0 )
if ( panelOptions.NoCloseButton ) then
simplePanel.Close : Hide ( )
end
if ( panelOptions.NoTitleBar ) then
simplePanel.TitleBar : Hide ( )
end
if ( not panelOptions.NoScripts ) then
simplePanel : SetScript ( " OnMouseDown " , simple_panel_mouse_down )
simplePanel : SetScript ( " OnMouseUp " , simple_panel_mouse_up )
end
simplePanel.SetTitle = simple_panel_settitle
return simplePanel
end
local Panel1PxBackdrop = { bgFile = " Interface \\ Tooltips \\ UI-Tooltip-Background " , tile = true , tileSize = 64 ,
edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , insets = { left = 2 , right = 2 , top = 3 , bottom = 3 } }
local Panel1PxOnClickClose = function ( self )
self : GetParent ( ) : Hide ( )
end
local Panel1PxOnToggleLock = function ( self )
if ( self.IsLocked ) then
self.IsLocked = false
self : SetMovable ( true )
self : EnableMouse ( true )
self.Lock : GetNormalTexture ( ) : SetTexCoord ( 16 / 64 , 32 / 64 , 0 , 1 )
self.Lock : GetHighlightTexture ( ) : SetTexCoord ( 16 / 32 , 32 / 64 , 0 , 1 )
self.Lock : GetPushedTexture ( ) : SetTexCoord ( 16 / 64 , 32 / 64 , 0 , 1 )
if ( self.OnUnlock ) then
self : OnUnlock ( )
end
if ( self.db ) then
self.db . IsLocked = self.IsLocked
end
else
self.IsLocked = true
self : SetMovable ( false )
self : EnableMouse ( false )
self.Lock : GetNormalTexture ( ) : SetTexCoord ( 0 / 64 , 16 / 64 , 0 , 1 )
self.Lock : GetHighlightTexture ( ) : SetTexCoord ( 0 / 64 , 16 / 64 , 0 , 1 )
self.Lock : GetPushedTexture ( ) : SetTexCoord ( 0 / 64 , 16 / 64 , 0 , 1 )
if ( self.OnLock ) then
self : OnLock ( )
end
if ( self.db ) then
self.db . IsLocked = self.IsLocked
end
end
end
local Panel1PxOnClickLock = function ( self )
local f = self : GetParent ( )
Panel1PxOnToggleLock ( f )
end
local Panel1PxSetTitle = function ( self , text )
self.Title : SetText ( text or " " )
end
local Panel1PxSetLocked = function ( self , lock_state )
if ( type ( lock_state ) ~= " boolean " ) then
return
end
if ( lock_state ) then
-- lock it
self.IsLocked = false
Panel1PxOnClickLock ( self.Lock )
else
-- unlockit
self.IsLocked = true
Panel1PxOnClickLock ( self.Lock )
end
end
local Panel1PxReadConfig = function ( self )
local db = self.db
if ( db ) then
db.IsLocked = db.IsLocked or false
self.IsLocked = db.IsLocked
db.position = db.position or { x = 0 , y = 0 }
db.position . x = db.position . x or 0
db.position . y = db.position . y or 0
detailsFramework : RestoreFramePosition ( self )
end
end
function detailsFramework : SavePositionOnScreen ( frame )
if ( frame.db and frame.db . position ) then
local x , y = detailsFramework : GetPositionOnScreen ( frame )
--print("saving...", x, y, frame:GetName())
if ( x and y ) then
frame.db . position.x , frame.db . position.y = x , y
end
end
end
function detailsFramework : GetPositionOnScreen ( frame )
local xOfs , yOfs = frame : GetCenter ( )
if ( not xOfs ) then
return
end
local scale = frame : GetEffectiveScale ( )
local UIscale = UIParent : GetScale ( )
xOfs = xOfs * scale - GetScreenWidth ( ) * UIscale / 2
yOfs = yOfs * scale - GetScreenHeight ( ) * UIscale / 2
return xOfs / UIscale , yOfs / UIscale
end
function detailsFramework : RestoreFramePosition ( frame )
if ( frame.db and frame.db . position ) then
local scale , UIscale = frame : GetEffectiveScale ( ) , UIParent : GetScale ( )
frame : ClearAllPoints ( )
frame.db . position.x = frame.db . position.x or 0
frame.db . position.y = frame.db . position.y or 0
frame : SetPoint ( " center " , UIParent , " center " , frame.db . position.x * UIscale / scale , frame.db . position.y * UIscale / scale )
end
end
local Panel1PxSavePosition = function ( self )
detailsFramework : SavePositionOnScreen ( self )
end
local Panel1PxHasPosition = function ( self )
local db = self.db
if ( db ) then
if ( db.position and db.position . x and ( db.position . x ~= 0 or db.position . y ~= 0 ) ) then
return true
end
end
end
function detailsFramework : Create1PxPanel ( parent , width , height , title , name , config , titleAnchor , noSpecialFrame )
local newFrame = CreateFrame ( " frame " , name , parent or UIParent , " BackdropTemplate " )
newFrame : SetSize ( width or 100 , height or 75 )
newFrame : SetPoint ( " center " , UIParent , " center " , 0 , 0 )
if ( name and not noSpecialFrame ) then
tinsert ( UISpecialFrames , name )
end
newFrame : SetScript ( " OnMouseDown " , simple_panel_mouse_down )
newFrame : SetScript ( " OnMouseUp " , simple_panel_mouse_up )
newFrame : SetBackdrop ( Panel1PxBackdrop )
newFrame : SetBackdropColor ( 0 , 0 , 0 , 0.5 )
newFrame.IsLocked = ( config and config.IsLocked ~= nil and config.IsLocked ) or false
newFrame : SetMovable ( true )
newFrame : EnableMouse ( true )
newFrame : SetUserPlaced ( true )
newFrame.db = config
Panel1PxReadConfig ( newFrame )
local closeButton = CreateFrame ( " button " , name and name .. " CloseButton " , newFrame , " BackdropTemplate " )
closeButton : SetSize ( 16 , 16 )
closeButton : SetNormalTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
closeButton : SetHighlightTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
closeButton : SetPushedTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
closeButton : GetNormalTexture ( ) : SetDesaturated ( true )
closeButton : GetHighlightTexture ( ) : SetDesaturated ( true )
closeButton : GetPushedTexture ( ) : SetDesaturated ( true )
closeButton : SetAlpha ( 0.7 )
local lockButton = CreateFrame ( " button " , name and name .. " LockButton " , newFrame , " BackdropTemplate " )
lockButton : SetSize ( 16 , 16 )
lockButton : SetNormalTexture ( [[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]] )
lockButton : SetHighlightTexture ( [[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]] )
lockButton : SetPushedTexture ( [[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]] )
lockButton : GetNormalTexture ( ) : SetDesaturated ( true )
lockButton : GetHighlightTexture ( ) : SetDesaturated ( true )
lockButton : GetPushedTexture ( ) : SetDesaturated ( true )
lockButton : SetAlpha ( 0.7 )
closeButton : SetPoint ( " topright " , newFrame , " topright " , - 3 , - 3 )
lockButton : SetPoint ( " right " , closeButton , " left " , 3 , 0 )
closeButton : SetScript ( " OnClick " , Panel1PxOnClickClose )
lockButton : SetScript ( " OnClick " , Panel1PxOnClickLock )
local titleString = newFrame : CreateFontString ( name and name .. " Title " , " overlay " , " GameFontNormal " )
titleString : SetPoint ( " topleft " , newFrame , " topleft " , 5 , - 5 )
detailsFramework.Language . SetTextIfLocTableOrDefault ( titleString , title or " " )
if ( titleAnchor ) then
if ( titleAnchor == " top " ) then
titleString : ClearAllPoints ( )
titleString : SetPoint ( " bottomleft " , newFrame , " topleft " , 0 , 0 )
closeButton : ClearAllPoints ( )
closeButton : SetPoint ( " bottomright " , newFrame , " topright " , 0 , 0 )
end
newFrame.title_anchor = titleAnchor
end
newFrame.SetTitle = Panel1PxSetTitle
newFrame.Title = titleString
newFrame.Lock = lockButton
newFrame.Close = closeButton
newFrame.HasPosition = Panel1PxHasPosition
newFrame.SavePosition = Panel1PxSavePosition
newFrame.IsLocked = not newFrame.IsLocked
newFrame.SetLocked = Panel1PxSetLocked
Panel1PxOnToggleLock ( newFrame )
return newFrame
end
------------------------------------------------------------------------------------------------------------------------------------------------
-- ~prompt
--@dontOverride: won't show another prompt if theres already a shown prompt
function detailsFramework : ShowPromptPanel ( message , trueCallback , falseCallback , dontOverride , width )
if ( not DetailsFrameworkPromptSimple ) then
local promptFrame = CreateFrame ( " frame " , " DetailsFrameworkPromptSimple " , UIParent , " BackdropTemplate " )
promptFrame : SetSize ( 400 , 80 )
promptFrame : SetFrameStrata ( " DIALOG " )
promptFrame : SetPoint ( " center " , UIParent , " center " , 0 , 300 )
detailsFramework : ApplyStandardBackdrop ( promptFrame )
tinsert ( UISpecialFrames , " DetailsFrameworkPromptSimple " )
detailsFramework : CreateTitleBar ( promptFrame , " Prompt! " )
detailsFramework : ApplyStandardBackdrop ( promptFrame )
local prompt = promptFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " )
prompt : SetPoint ( " top " , promptFrame , " top " , 0 , - 28 )
prompt : SetJustifyH ( " center " )
promptFrame.prompt = prompt
local button_text_template = detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " )
local options_dropdown_template = detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local buttonTrue = detailsFramework : CreateButton ( promptFrame , nil , 60 , 20 , " Yes " , nil , nil , nil , nil , nil , nil , options_dropdown_template )
buttonTrue : SetPoint ( " bottomright " , promptFrame , " bottomright " , - 5 , 5 )
promptFrame.button_true = buttonTrue
local buttonFalse = detailsFramework : CreateButton ( promptFrame , nil , 60 , 20 , " No " , nil , nil , nil , nil , nil , nil , options_dropdown_template )
buttonFalse : SetPoint ( " bottomleft " , promptFrame , " bottomleft " , 5 , 5 )
promptFrame.button_false = buttonFalse
buttonTrue : SetClickFunction ( function ( )
local my_func = buttonTrue.true_function
if ( my_func ) then
local okey , errormessage = pcall ( my_func , true )
if ( not okey ) then
print ( " error: " , errormessage )
end
promptFrame : Hide ( )
end
end )
buttonFalse : SetClickFunction ( function ( )
local my_func = buttonFalse.false_function
if ( my_func ) then
local okey , errormessage = pcall ( my_func , true )
if ( not okey ) then
print ( " error: " , errormessage )
end
promptFrame : Hide ( )
end
end )
promptFrame.ShowAnimation = detailsFramework : CreateAnimationHub ( promptFrame , function ( )
promptFrame : SetBackdropBorderColor ( 0 , 0 , 0 , 0 )
promptFrame.TitleBar : SetBackdropBorderColor ( 0 , 0 , 0 , 0 )
end ,
function ( )
promptFrame : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
promptFrame.TitleBar : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
end )
detailsFramework : CreateAnimation ( promptFrame.ShowAnimation , " scale " , 1 , .075 , .2 , .2 , 1.1 , 1.1 , " center " , 0 , 0 )
detailsFramework : CreateAnimation ( promptFrame.ShowAnimation , " scale " , 2 , .075 , 1 , 1 , .90 , .90 , " center " , 0 , 0 )
promptFrame.FlashTexture = promptFrame : CreateTexture ( nil , " overlay " )
promptFrame.FlashTexture : SetColorTexture ( 1 , 1 , 1 , 1 )
promptFrame.FlashTexture : SetAllPoints ( )
promptFrame.FlashAnimation = detailsFramework : CreateAnimationHub ( promptFrame.FlashTexture , function ( ) promptFrame.FlashTexture : Show ( ) end , function ( ) promptFrame.FlashTexture : Hide ( ) end )
detailsFramework : CreateAnimation ( promptFrame.FlashAnimation , " alpha " , 1 , .075 , 0 , .25 )
detailsFramework : CreateAnimation ( promptFrame.FlashAnimation , " alpha " , 2 , .075 , .35 , 0 )
promptFrame : Hide ( )
detailsFramework.promtp_panel = promptFrame
end
assert ( type ( trueCallback ) == " function " and type ( falseCallback ) == " function " , " ShowPromptPanel expects two functions. " )
if ( dontOverride ) then
if ( detailsFramework.promtp_panel : IsShown ( ) ) then
return
end
end
if ( width ) then
detailsFramework.promtp_panel : SetWidth ( width )
else
detailsFramework.promtp_panel : SetWidth ( 400 )
end
detailsFramework.promtp_panel . prompt : SetText ( message )
detailsFramework.promtp_panel . button_true.true_function = trueCallback
detailsFramework.promtp_panel . button_false.false_function = falseCallback
detailsFramework.promtp_panel : Show ( )
detailsFramework.promtp_panel . ShowAnimation : Play ( )
detailsFramework.promtp_panel . FlashAnimation : Play ( )
end
function detailsFramework : ShowTextPromptPanel ( message , callback )
if ( not detailsFramework.text_prompt_panel ) then
local promptFrame = CreateFrame ( " frame " , " DetailsFrameworkPrompt " , UIParent , " BackdropTemplate " )
promptFrame : SetSize ( 400 , 120 )
promptFrame : SetFrameStrata ( " FULLSCREEN " )
promptFrame : SetPoint ( " center " , UIParent , " center " , 0 , 100 )
promptFrame : EnableMouse ( true )
promptFrame : SetMovable ( true )
promptFrame : RegisterForDrag ( " LeftButton " )
promptFrame : SetScript ( " OnDragStart " , function ( ) promptFrame : StartMoving ( ) end )
promptFrame : SetScript ( " OnDragStop " , function ( ) promptFrame : StopMovingOrSizing ( ) end )
promptFrame : SetScript ( " OnMouseDown " , function ( self , button ) if ( button == " RightButton " ) then promptFrame.EntryBox : ClearFocus ( ) promptFrame : Hide ( ) end end )
tinsert ( UISpecialFrames , " DetailsFrameworkPrompt " )
detailsFramework : CreateTitleBar ( promptFrame , " Prompt! " )
detailsFramework : ApplyStandardBackdrop ( promptFrame )
local prompt = promptFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " )
prompt : SetPoint ( " top " , promptFrame , " top " , 0 , - 25 )
prompt : SetJustifyH ( " center " )
prompt : SetSize ( 360 , 36 )
promptFrame.prompt = prompt
local button_text_template = detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " )
local options_dropdown_template = detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local textbox = detailsFramework : CreateTextEntry ( promptFrame , function ( ) end , 380 , 20 , " textbox " , nil , nil , options_dropdown_template )
textbox : SetPoint ( " topleft " , promptFrame , " topleft " , 10 , - 60 )
promptFrame.EntryBox = textbox
local buttonTrue = detailsFramework : CreateButton ( promptFrame , nil , 60 , 20 , " Okey " , nil , nil , nil , nil , nil , nil , options_dropdown_template )
buttonTrue : SetPoint ( " bottomright " , promptFrame , " bottomright " , - 10 , 5 )
promptFrame.button_true = buttonTrue
local buttonFalse = detailsFramework : CreateButton ( promptFrame , function ( ) promptFrame.textbox : ClearFocus ( ) promptFrame : Hide ( ) end , 60 , 20 , " Cancel " , nil , nil , nil , nil , nil , nil , options_dropdown_template )
buttonFalse : SetPoint ( " bottomleft " , promptFrame , " bottomleft " , 10 , 5 )
promptFrame.button_false = buttonFalse
local executeCallback = function ( )
local my_func = buttonTrue.true_function
if ( my_func ) then
local okey , errormessage = pcall ( my_func , textbox : GetText ( ) )
textbox : ClearFocus ( )
if ( not okey ) then
print ( " error: " , errormessage )
end
promptFrame : Hide ( )
end
end
buttonTrue : SetClickFunction ( function ( )
executeCallback ( )
end )
textbox : SetHook ( " OnEnterPressed " , function ( )
executeCallback ( )
end )
promptFrame : Hide ( )
detailsFramework.text_prompt_panel = promptFrame
end
detailsFramework.text_prompt_panel : Show ( )
DetailsFrameworkPrompt.EntryBox : SetText ( " " )
detailsFramework.text_prompt_panel . prompt : SetText ( message )
detailsFramework.text_prompt_panel . button_true.true_function = callback
detailsFramework.text_prompt_panel . textbox : SetFocus ( true )
end
------------------------------------------------------------------------------------------------------------------------------------------------
--chart panel -- ~chart
local chart_panel_backdrop = { bgFile = " Interface \\ Tooltips \\ UI-Tooltip-Background " , tile = true , tileSize = 16 ,
edgeFile = " Interface \\ Tooltips \\ UI-Tooltip-Border " , edgeSize = 32 , insets = { left = 5 , right = 5 , top = 5 , bottom = 5 } }
local chart_panel_align_timelabels = function ( self , elapsed_time )
self.TimeScale = elapsed_time
local linha = self.TimeLabels [ 17 ]
local minutes , seconds = math.floor ( elapsed_time / 60 ) , math.floor ( elapsed_time % 60 )
if ( seconds < 10 ) then
seconds = " 0 " .. seconds
end
if ( minutes > 0 ) then
if ( minutes < 10 ) then
minutes = " 0 " .. minutes
end
linha : SetText ( minutes .. " : " .. seconds )
else
linha : SetText ( " 00: " .. seconds )
end
local time_div = elapsed_time / 16 --786 -- 49.125
for i = 2 , 16 do
local linha = self.TimeLabels [ i ]
local this_time = time_div * ( i - 1 )
local minutes , seconds = math.floor ( this_time / 60 ) , math.floor ( this_time % 60 )
if ( seconds < 10 ) then
seconds = " 0 " .. seconds
end
if ( minutes > 0 ) then
if ( minutes < 10 ) then
minutes = " 0 " .. minutes
end
linha : SetText ( minutes .. " : " .. seconds )
else
linha : SetText ( " 00: " .. seconds )
end
end
end
local chart_panel_set_scale = function ( self , amt , func , text )
if ( type ( amt ) ~= " number " ) then
return
end
--each line amount, then multiply the line index by this number
local piece = amt / 8
for i = 1 , 8 do
if ( func ) then
self [ " dpsamt " .. math.abs ( i - 9 ) ] : SetText ( func ( piece * i ) )
else
if ( piece * i > 1 ) then
self [ " dpsamt " .. math.abs ( i - 9 ) ] : SetText ( detailsFramework.FormatNumber ( piece * i ) )
else
self [ " dpsamt " .. math.abs ( i - 9 ) ] : SetText ( format ( " %.3f " , piece * i ) )
end
end
end
end
local chart_panel_can_move = function ( self , can )
self.can_move = can
end
local chart_panel_overlay_reset = function ( self )
self.OverlaysAmount = 1
for index , pack in ipairs ( self.Overlays ) do
for index2 , texture in ipairs ( pack ) do
texture : Hide ( )
end
end
end
local chart_panel_reset = function ( self )
self.Graphic : ResetData ( )
self.Graphic . max_value = 0
self.TimeScale = nil
self.BoxLabelsAmount = 1
table.wipe ( self.GData )
table.wipe ( self.OData )
for index , box in ipairs ( self.BoxLabels ) do
box.check : Hide ( )
box.button : Hide ( )
box.box : Hide ( )
box.text : Hide ( )
box.border : Hide ( )
box.showing = false
end
chart_panel_overlay_reset ( self )
end
local chart_panel_enable_line = function ( f , thisbox )
local index = thisbox.index
local boxType = thisbox.type
if ( thisbox.enabled ) then
--disable
thisbox.check : Hide ( )
thisbox.enabled = false
else
--enable
thisbox.check : Show ( )
thisbox.enabled = true
end
if ( boxType == " graphic " ) then
f.Graphic : ResetData ( )
f.Graphic . max_value = 0
local max = 0
local max_time = 0
for index , box in ipairs ( f.BoxLabels ) do
if ( box.type == boxType and box.showing and box.enabled ) then
local data = f.GData [ index ]
f.Graphic : AddDataSeries ( data [ 1 ] , data [ 2 ] , nil , data [ 3 ] )
if ( data [ 4 ] > max ) then
max = data [ 4 ]
end
if ( data [ 5 ] > max_time ) then
max_time = data [ 5 ]
end
end
end
f : SetScale ( max )
f : SetTime ( max_time )
elseif ( boxType == " overlay " ) then
chart_panel_overlay_reset ( f )
for index , box in ipairs ( f.BoxLabels ) do
if ( box.type == boxType and box.showing and box.enabled ) then
f : AddOverlay ( box.index )
end
end
end
end
local create_box = function ( self , next_box )
local thisbox = { }
self.BoxLabels [ next_box ] = thisbox
local box = detailsFramework : NewImage ( self.Graphic , nil , 16 , 16 , " border " )
local text = detailsFramework : NewLabel ( self.Graphic )
local border = detailsFramework : NewImage ( self.Graphic , [[Interface\DialogFrame\UI-DialogBox-Gold-Corner]] , 30 , 30 , " artwork " )
border : SetPoint ( " center " , box , " center " , - 3 , - 4 )
border : SetTexture ( [[Interface\DialogFrame\UI-DialogBox-Gold-Corner]] )
local checktexture = detailsFramework : NewImage ( self.Graphic , [[Interface\Buttons\UI-CheckBox-Check]] , 18 , 18 , " overlay " )
checktexture : SetPoint ( " center " , box , " center " , 0 , - 1 )
checktexture : SetTexture ( [[Interface\Buttons\UI-CheckBox-Check]] )
thisbox.box = box
thisbox.text = text
thisbox.border = border
thisbox.check = checktexture
thisbox.enabled = true
local button = CreateFrame ( " button " , nil , self.Graphic , " BackdropTemplate " )
button : SetSize ( 20 , 20 )
button : SetScript ( " OnClick " , function ( )
chart_panel_enable_line ( self , thisbox )
end )
button : SetPoint ( " topleft " , box.widget or box , " topleft " , 0 , 0 )
button : SetPoint ( " bottomright " , box.widget or box , " bottomright " , 0 , 0 )
button : SetBackdrop ( { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } )
button : SetBackdropColor ( 0 , 0 , 0 , 0.0 )
button : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
thisbox.button = button
thisbox.box : SetPoint ( " right " , text , " left " , - 4 , 0 )
if ( next_box == 1 ) then
thisbox.text : SetPoint ( " topright " , self , " topright " , - 35 , - 16 )
else
thisbox.text : SetPoint ( " right " , self.BoxLabels [ next_box - 1 ] . box , " left " , - 17 , 0 )
end
return thisbox
end
local realign_labels = function ( self )
if ( not self.ShowHeader ) then
for _ , box in ipairs ( self.BoxLabels ) do
box.check : Hide ( )
box.button : Hide ( )
box.border : Hide ( )
box.box : Hide ( )
box.text : Hide ( )
end
return
end
local width = self : GetWidth ( ) - 108
local first_box = self.BoxLabels [ 1 ]
first_box.text : SetPoint ( " topright " , self , " topright " , - 35 , - 16 )
local line_width = first_box.text : GetStringWidth ( ) + 26
for i = 2 , # self.BoxLabels do
local box = self.BoxLabels [ i ]
if ( box.box : IsShown ( ) ) then
line_width = line_width + box.text : GetStringWidth ( ) + 26
if ( line_width > width ) then
line_width = box.text : GetStringWidth ( ) + 26
box.text : SetPoint ( " topright " , self , " topright " , - 35 , - 40 )
else
box.text : SetPoint ( " right " , self.BoxLabels [ i - 1 ] . box , " left " , - 27 , 0 )
end
else
break
end
end
if ( self.HeaderOnlyIndicator ) then
for _ , box in ipairs ( self.BoxLabels ) do
box.check : Hide ( )
box.button : Hide ( )
end
return
end
end
local chart_panel_add_label = function ( self , color , name , type , number )
local next_box = self.BoxLabelsAmount
local thisbox = self.BoxLabels [ next_box ]
if ( not thisbox ) then
thisbox = create_box ( self , next_box )
end
self.BoxLabelsAmount = self.BoxLabelsAmount + 1
thisbox.type = type
thisbox.index = number
thisbox.box : SetColorTexture ( unpack ( color ) )
thisbox.text : SetText ( name )
thisbox.check : Show ( )
thisbox.button : Show ( )
thisbox.border : Hide ( )
thisbox.box : Show ( )
thisbox.text : Show ( )
thisbox.showing = true
thisbox.enabled = true
realign_labels ( self )
end
local line_default_color = { 1 , 1 , 1 }
local draw_overlay = function ( self , this_overlay , overlayData , color )
local pixel = self.Graphic : GetWidth ( ) / self.TimeScale
local index = 1
local r , g , b , a = unpack ( color or line_default_color )
for i = 1 , # overlayData , 2 do
local aura_start = overlayData [ i ]
local aura_end = overlayData [ i + 1 ]
local this_block = this_overlay [ index ]
if ( not this_block ) then
this_block = self.Graphic : CreateTexture ( nil , " border " )
tinsert ( this_overlay , this_block )
end
this_block : SetHeight ( self.Graphic : GetHeight ( ) )
this_block : SetPoint ( " left " , self.Graphic , " left " , pixel * aura_start , 0 )
if ( aura_end ) then
this_block : SetWidth ( ( aura_end - aura_start ) * pixel )
else
--malformed table
this_block : SetWidth ( pixel * 5 )
end
this_block : SetColorTexture ( r , g , b , a or 0.25 )
this_block : Show ( )
index = index + 1
end
end
local chart_panel_add_overlay = function ( self , overlayData , color , name , icon )
if ( not self.TimeScale ) then
error ( " Use SetTime (time) before adding an overlay. " )
end
if ( type ( overlayData ) == " number " ) then
local overlay_index = overlayData
draw_overlay ( self , self.Overlays [ self.OverlaysAmount ] , self.OData [ overlay_index ] [ 1 ] , self.OData [ overlay_index ] [ 2 ] )
else
local this_overlay = self.Overlays [ self.OverlaysAmount ]
if ( not this_overlay ) then
this_overlay = { }
tinsert ( self.Overlays , this_overlay )
end
draw_overlay ( self , this_overlay , overlayData , color )
tinsert ( self.OData , { overlayData , color or line_default_color } )
if ( name and self.HeaderShowOverlays ) then
self : AddLabel ( color or line_default_color , name , " overlay " , # self.OData )
end
end
self.OverlaysAmount = self.OverlaysAmount + 1
end
-- Define the tricube weight function
function calc_cubeweight ( i , j , d )
local w = ( 1 - math.abs ( ( j - i ) / d ) ^ 3 ) ^ 3
if w < 0 then
w = 0
end
return w
end
local calc_lowess_smoothing = function ( self , data , bandwidth )
local length = # data
local newData = { }
for i = 1 , length do
local A = 0
local B = 0
local C = 0
local D = 0
local E = 0
-- Calculate span of values to be included in the regression
local jmin = floor ( i - bandwidth / 2 )
local jmax = ceil ( i + bandwidth / 2 )
if jmin < 1 then
jmin = 1
end
if jmax > length then
jmax = length
end
-- For all the values in the span, compute the weight and then the linear fit
for j = jmin , jmax do
w = calc_cubeweight ( i , j , bandwidth / 2 )
x = j
y = data [ j ]
A = A + w * x
B = B + w * y
C = C + w * x ^ 2
D = D + w * x * y
E = E + w
end
-- Calculate a (slope) and b (offset) for the linear fit
local a = ( A * B - D * E ) / ( A ^ 2 - C * E )
local b = ( A * D - B * C ) / ( A ^ 2 - C * E )
-- Calculate the smoothed value by the formula y=a*x+b (x <- i)
newData [ i ] = a * i + b
end
return newData
end
local calc_stddev = function ( self , data )
local total = 0
for i = 1 , # data do
total = total + data [ i ]
end
local mean = total / # data
local totalDistance = 0
for i = 1 , # data do
totalDistance = totalDistance + ( ( data [ i ] - mean ) ^ 2 )
end
local deviation = math.sqrt ( totalDistance / # data )
return deviation
end
local SMA_table = { }
local SMA_max = 0
local reset_SMA = function ( )
table.wipe ( SMA_table )
SMA_max = 0
end
local calc_SMA
calc_SMA = function ( a , b , ... )
if ( b ) then
return calc_SMA ( a + b , ... )
else
return a
end
end
local do_SMA = function ( value , max_value )
if ( # SMA_table == 10 ) then
tremove ( SMA_table , 1 )
end
SMA_table [ # SMA_table + 1 ] = value
local new_value = calc_SMA ( unpack ( SMA_table ) ) / # SMA_table
if ( new_value > SMA_max ) then
SMA_max = new_value
return new_value , SMA_max
else
return new_value
end
end
local chart_panel_onresize = function ( self )
local width , height = self : GetSize ( )
local spacement = width - 78 - 60
spacement = spacement / 16
for i = 1 , 17 do
local label = self.TimeLabels [ i ]
label : SetPoint ( " bottomleft " , self , " bottomleft " , 78 + ( ( i - 1 ) * spacement ) , self.TimeLabelsHeight )
label.line : SetHeight ( height - 45 )
end
local spacement = ( self.Graphic : GetHeight ( ) ) / 8
for i = 1 , 8 do
self [ " dpsamt " .. i ] : SetPoint ( " TOPLEFT " , self , " TOPLEFT " , 27 , - 25 + ( - ( spacement * ( i - 1 ) ) ) )
self [ " dpsamt " .. i ] . line : SetWidth ( width - 20 )
end
self.Graphic : SetSize ( width - 135 , height - 67 )
self.Graphic : SetPoint ( " topleft " , self , " topleft " , 108 , - 35 )
end
local chart_panel_add_data = function ( self , graphicData , color , name , elapsedTime , lineTexture , smoothLevel , firstIndex )
local chartPanel = self --chartPanel from the framework CreateChartPanel
local LibGraphChartFrame = self.Graphic
local builtData = { }
local maxValue = graphicData.max_value
local scaleWidth = 1 / LibGraphChartFrame : GetWidth ( )
local content = graphicData
--smooth the start and end of the chart
tinsert ( content , 1 , 0 )
tinsert ( content , 1 , 0 )
tinsert ( content , # content + 1 , 0 )
tinsert ( content , # content + 1 , 0 )
local index = 3
local graphMaxDps = math.max ( LibGraphChartFrame.max_value , maxValue )
--do smoothness progress
if ( not smoothLevel ) then
while ( index <= # content - 2 ) do
local value = ( content [ index - 2 ] + content [ index - 1 ] + content [ index ] + content [ index + 1 ] + content [ index + 2 ] ) / 5 --normalize
builtData [ # builtData + 1 ] = { scaleWidth * ( index - 2 ) , value / graphMaxDps } -- x and y coords
index = index + 1
end
elseif ( smoothLevel == " SHORT " ) then
while ( index <= # content - 2 ) do
local value = ( content [ index ] + content [ index + 1 ] ) / 2
builtData [ # builtData + 1 ] = { scaleWidth * ( index - 2 ) , value }
builtData [ # builtData + 1 ] = { scaleWidth * ( index - 2 ) , value }
index = index + 2
end
elseif ( smoothLevel == " SMA " ) then
reset_SMA ( )
while ( index <= # content - 2 ) do
local value , is_new_max_value = do_SMA ( content [ index ] , maxValue )
if ( is_new_max_value ) then
maxValue = is_new_max_value
end
builtData [ # builtData + 1 ] = { scaleWidth * ( index - 2 ) , value } -- x and y coords
index = index + 1
end
elseif ( smoothLevel == - 1 ) then
while ( index <= # content - 2 ) do
local current = content [ index ]
local minus_2 = content [ index - 2 ] * 0.6
local minus_1 = content [ index - 1 ] * 0.8
local plus_1 = content [ index + 1 ] * 0.8
local plus_2 = content [ index + 2 ] * 0.6
local value = ( current + minus_2 + minus_1 + plus_1 + plus_2 ) / 5 --normalize
builtData [ # builtData + 1 ] = { scaleWidth * ( index - 2 ) , value / graphMaxDps } -- x and y coords
index = index + 1
end
elseif ( smoothLevel == 1 ) then
index = 2
while ( index <= # content - 1 ) do
local value = ( content [ index - 1 ] + content [ index ] + content [ index + 1 ] ) / 3 --normalize
builtData [ # builtData + 1 ] = { scaleWidth * ( index - 1 ) , value / graphMaxDps } -- x and y coords
index = index + 1
end
elseif ( smoothLevel == 2 ) then
index = 1
while ( index <= # content ) do
local value = content [ index ] --do not normalize
builtData [ # builtData + 1 ] = { scaleWidth * ( index ) , value / graphMaxDps } -- x and y coords
index = index + 1
end
end
tremove ( content , 1 )
tremove ( content , 1 )
tremove ( content , # graphicData )
tremove ( content , # graphicData )
if ( maxValue > LibGraphChartFrame.max_value ) then
--normalize previous data
if ( LibGraphChartFrame.max_value > 0 ) then
local normalizePercent = LibGraphChartFrame.max_value / maxValue
for dataIndex , Data in ipairs ( LibGraphChartFrame.Data ) do
local Points = Data.Points
for i = 1 , # Points do
Points [ i ] [ 2 ] = Points [ i ] [ 2 ] * normalizePercent
end
end
end
LibGraphChartFrame.max_value = maxValue
chartPanel : SetScale ( maxValue )
end
tinsert ( chartPanel.GData , { builtData , color or line_default_color , lineTexture , maxValue , elapsedTime } )
if ( name ) then
chartPanel : AddLabel ( color or line_default_color , name , " graphic " , # chartPanel.GData )
end
local newLineTexture = " Interface \\ AddOns \\ Details \\ Libs \\ LibGraph-2.0 \\ line "
if ( firstIndex ) then
table.insert ( LibGraphChartFrame.Data , 1 , { Points = builtData , Color = color or line_default_color , lineTexture = newLineTexture , ElapsedTime = elapsedTime } )
LibGraphChartFrame.NeedsUpdate = true
else
LibGraphChartFrame : AddDataSeries ( builtData , color or line_default_color , nil , newLineTexture )
LibGraphChartFrame.Data [ # LibGraphChartFrame.Data ] . ElapsedTime = elapsedTime
end
local maxTime = 0
for _ , data in ipairs ( LibGraphChartFrame.Data ) do
if ( data.ElapsedTime > maxTime ) then
maxTime = data.ElapsedTime
end
end
chartPanel : SetTime ( maxTime )
chart_panel_onresize ( chartPanel )
end
local chart_panel_vlines_on = function ( self )
for i = 1 , 17 do
local label = self.TimeLabels [ i ]
label.line : Show ( )
end
end
local chart_panel_vlines_off = function ( self )
for i = 1 , 17 do
local label = self.TimeLabels [ i ]
label.line : Hide ( )
end
end
local chart_panel_set_title = function ( self , title )
self.chart_title . text = title
end
local chart_panel_mousedown = function ( self , button )
if ( button == " LeftButton " and self.can_move ) then
if ( not self.isMoving ) then
self : StartMoving ( )
self.isMoving = true
end
elseif ( button == " RightButton " and not self.no_right_click_close ) then
if ( not self.isMoving ) then
self : Hide ( )
end
end
end
local chart_panel_mouseup = function ( self , button )
if ( button == " LeftButton " and self.isMoving ) then
self : StopMovingOrSizing ( )
self.isMoving = nil
end
end
local chart_panel_hide_close_button = function ( self )
self.CloseButton : Hide ( )
end
local chart_panel_right_click_close = function ( self , value )
if ( type ( value ) == " boolean " ) then
if ( value ) then
self.no_right_click_close = nil
else
self.no_right_click_close = true
end
end
end
function detailsFramework : CreateChartPanel ( parent , width , height , name )
if ( not name ) then
name = " DFPanel " .. detailsFramework.PanelCounter
detailsFramework.PanelCounter = detailsFramework.PanelCounter + 1
end
parent = parent or UIParent
width = width or 800
height = height or 500
local chartFrame = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
chartFrame : SetSize ( width or 500 , height or 400 )
chartFrame : EnableMouse ( true )
chartFrame : SetMovable ( true )
chartFrame : SetScript ( " OnMouseDown " , chart_panel_mousedown )
chartFrame : SetScript ( " OnMouseUp " , chart_panel_mouseup )
chartFrame : SetBackdrop ( chart_panel_backdrop )
chartFrame : SetBackdropColor ( .3 , .3 , .3 , .3 )
local closeButton = CreateFrame ( " Button " , nil , chartFrame , " UIPanelCloseButton " , " BackdropTemplate " )
closeButton : SetWidth ( 32 )
closeButton : SetHeight ( 32 )
closeButton : SetPoint ( " TOPRIGHT " , chartFrame , " TOPRIGHT " , - 3 , - 7 )
closeButton : SetFrameLevel ( chartFrame : GetFrameLevel ( ) + 1 )
closeButton : SetAlpha ( 0.9 )
chartFrame.CloseButton = closeButton
local title = detailsFramework : NewLabel ( chartFrame , nil , " $parentTitle " , " chart_title " , " Chart! " , nil , 20 , { 1 , 1 , 0 } )
title : SetPoint ( " topleft " , chartFrame , " topleft " , 110 , - 13 )
chartFrame.Overlays = { }
chartFrame.OverlaysAmount = 1
chartFrame.BoxLabels = { }
chartFrame.BoxLabelsAmount = 1
chartFrame.ShowHeader = true
chartFrame.HeaderOnlyIndicator = false
chartFrame.HeaderShowOverlays = true
--graphic
local g = LibStub : GetLibrary ( " LibGraph-2.0 " ) : CreateGraphLine ( name .. " Graphic " , chartFrame , " topleft " , " topleft " , 108 , - 35 , width - 120 , height - 67 )
g : SetXAxis ( - 1 , 1 )
g : SetYAxis ( - 1 , 1 )
g : SetGridSpacing ( false , false )
g : SetGridColor ( { 0.5 , 0.5 , 0.5 , 0.3 } )
g : SetAxisDrawing ( false , false )
g : SetAxisColor ( { 1.0 , 1.0 , 1.0 , 1.0 } )
g : SetAutoScale ( true )
g : SetLineTexture ( " smallline " )
g : SetBorderSize ( " right " , 0.001 )
g : SetBorderSize ( " left " , 0.000 )
g : SetBorderSize ( " top " , 0.002 )
g : SetBorderSize ( " bottom " , 0.001 )
g.VerticalLines = { }
g.max_value = 0
g : SetLineTexture ( " line " )
chartFrame.Graphic = g
chartFrame.GData = { }
chartFrame.OData = { }
chartFrame.ChartFrames = { }
--div lines
for i = 1 , 8 , 1 do
local line = g : CreateTexture ( nil , " overlay " )
line : SetColorTexture ( 1 , 1 , 1 , .05 )
line : SetWidth ( 670 )
line : SetHeight ( 1.1 )
local s = chartFrame : CreateFontString ( nil , " overlay " , " GameFontHighlightSmall " )
chartFrame [ " dpsamt " .. i ] = s
s : SetText ( " 100k " )
s : SetPoint ( " topleft " , chartFrame , " topleft " , 27 , - 61 + ( - ( 24.6 * i ) ) )
line : SetPoint ( " topleft " , s , " bottom " , - 27 , 0 )
line : SetPoint ( " topright " , g , " right " , 0 , 0 )
s.line = line
end
--create time labels and the bottom texture to use as a background to these labels
chartFrame.TimeLabels = { }
chartFrame.TimeLabelsHeight = 16
for i = 1 , 17 do
local timeString = chartFrame : CreateFontString ( nil , " overlay " , " GameFontHighlightSmall " )
timeString : SetText ( " 00:00 " )
timeString : SetPoint ( " bottomleft " , chartFrame , " bottomleft " , 78 + ( ( i - 1 ) * 36 ) , chartFrame.TimeLabelsHeight )
chartFrame.TimeLabels [ i ] = timeString
local line = chartFrame : CreateTexture ( nil , " border " )
line : SetSize ( 1 , height - 45 )
line : SetColorTexture ( 1 , 1 , 1 , .1 )
line : SetPoint ( " bottomleft " , timeString , " topright " , 0 , - 10 )
line : Hide ( )
timeString.line = line
end
local bottom_texture = detailsFramework : NewImage ( chartFrame , nil , 702 , 25 , " background " , nil , nil , " $parentBottomTexture " )
bottom_texture : SetColorTexture ( .1 , .1 , .1 , .7 )
bottom_texture : SetPoint ( " topright " , g , " bottomright " , 0 , 0 )
bottom_texture : SetPoint ( " bottomleft " , chartFrame , " bottomleft " , 8 , 12 )
chartFrame.SetTime = chart_panel_align_timelabels
chartFrame.EnableVerticalLines = chart_panel_vlines_on
chartFrame.DisableVerticalLines = chart_panel_vlines_off
chartFrame.SetTitle = chart_panel_set_title
chartFrame.SetScale = chart_panel_set_scale
chartFrame.Reset = chart_panel_reset
chartFrame.AddLine = chart_panel_add_data
chartFrame.CanMove = chart_panel_can_move
chartFrame.AddLabel = chart_panel_add_label
chartFrame.AddOverlay = chart_panel_add_overlay
chartFrame.HideCloseButton = chart_panel_hide_close_button
chartFrame.RightClickClose = chart_panel_right_click_close
chartFrame.CalcStdDev = calc_stddev
chartFrame.CalcLowessSmoothing = calc_lowess_smoothing
chartFrame : SetScript ( " OnSizeChanged " , chart_panel_onresize )
chart_panel_onresize ( chartFrame )
return chartFrame
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~gframe
local gframe_on_enter_line = function ( self )
self : SetBackdropColor ( 0 , 0 , 0 , 0 )
local parent = self : GetParent ( )
local ball = self.ball
ball : SetBlendMode ( " ADD " )
local on_enter = parent._onenter_line
if ( on_enter ) then
return on_enter ( self , parent )
end
end
local gframe_on_leave_line = function ( self )
self : SetBackdropColor ( 0 , 0 , 0 , .6 )
local parent = self : GetParent ( )
local ball = self.ball
ball : SetBlendMode ( " BLEND " )
local on_leave = parent._onleave_line
if ( on_leave ) then
return on_leave ( self , parent )
end
end
local gframe_create_line = function ( self )
local index = # self._lines + 1
local f = CreateFrame ( " frame " , nil , self , " BackdropTemplate " )
self._lines [ index ] = f
f.id = index
f : SetScript ( " OnEnter " , gframe_on_enter_line )
f : SetScript ( " OnLeave " , gframe_on_leave_line )
f : SetWidth ( self._linewidth )
if ( index == 1 ) then
f : SetPoint ( " topleft " , self , " topleft " )
f : SetPoint ( " bottomleft " , self , " bottomleft " )
else
local previous_line = self._lines [ index - 1 ]
f : SetPoint ( " topleft " , previous_line , " topright " )
f : SetPoint ( " bottomleft " , previous_line , " bottomright " )
end
local t = f : CreateTexture ( nil , " background " )
t : SetWidth ( 1 )
t : SetPoint ( " topright " , f , " topright " )
t : SetPoint ( " bottomright " , f , " bottomright " )
t : SetColorTexture ( 1 , 1 , 1 , .1 )
f.grid = t
local b = f : CreateTexture ( nil , " overlay " )
b : SetTexture ( [[Interface\COMMON\Indicator-Yellow]] )
b : SetSize ( 16 , 16 )
f.ball = b
local anchor = CreateFrame ( " frame " , nil , f , " BackdropTemplate " )
anchor : SetAllPoints ( b )
b.tooltip_anchor = anchor
local spellicon = f : CreateTexture ( nil , " artwork " )
spellicon : SetPoint ( " bottom " , b , " bottom " , 0 , 10 )
spellicon : SetSize ( 16 , 16 )
f.spellicon = spellicon
local text = f : CreateFontString ( nil , " overlay " , " GameFontNormal " )
local textBackground = f : CreateTexture ( nil , " artwork " )
textBackground : SetSize ( 30 , 16 )
textBackground : SetColorTexture ( 0 , 0 , 0 , 0.5 )
textBackground : SetPoint ( " bottom " , f.ball , " top " , 0 , - 6 )
text : SetPoint ( " center " , textBackground , " center " )
detailsFramework : SetFontSize ( text , 10 )
f.text = text
f.textBackground = textBackground
local timeline = f : CreateFontString ( nil , " overlay " , " GameFontNormal " )
timeline : SetPoint ( " bottomright " , f , " bottomright " , - 2 , 0 )
detailsFramework : SetFontSize ( timeline , 8 )
f.timeline = timeline
return f
end
local gframe_getline = function ( self , index )
local line = self._lines [ index ]
if ( not line ) then
line = gframe_create_line ( self )
end
return line
end
local gframe_reset = function ( self )
for i , line in ipairs ( self._lines ) do
line : Hide ( )
end
if ( self.GraphLib_Lines_Used ) then
for i = # self.GraphLib_Lines_Used , 1 , - 1 do
local line = tremove ( self.GraphLib_Lines_Used )
tinsert ( self.GraphLib_Lines , line )
line : Hide ( )
end
end
end
local gframe_update = function ( self , lines )
local g = LibStub : GetLibrary ( " LibGraph-2.0 " )
local h = self : GetHeight ( ) / 100
local amtlines = # lines
local linewidth = self._linewidth
local max_value = 0
for i = 1 , amtlines do
if ( lines [ i ] . value > max_value ) then
max_value = lines [ i ] . value
end
end
self.MaxValue = max_value
local o = 1
local lastvalue = self : GetHeight ( ) / 2
max_value = math.max ( max_value , 0.0000001 )
for i = 1 , min ( amtlines , self._maxlines ) do
local data = lines [ i ]
local pvalue = data.value / max_value * 100
if ( pvalue > 98 ) then
pvalue = 98
end
pvalue = pvalue * h
g : DrawLine ( self , ( o - 1 ) * linewidth , lastvalue , o * linewidth , pvalue , linewidth , { 1 , 1 , 1 , 1 } , " overlay " )
lastvalue = pvalue
local line = self : GetLine ( i )
line : Show ( )
line.ball : Show ( )
line.ball : SetPoint ( " bottomleft " , self , " bottomleft " , ( o * linewidth ) - 8 , pvalue - 8 )
line.spellicon : SetTexture ( nil )
line.timeline : SetText ( data.text )
line.timeline : Show ( )
if ( data.utext ) then
line.text : Show ( )
line.textBackground : Show ( )
line.text : SetText ( data.utext )
else
line.text : Hide ( )
line.textBackground : Hide ( )
end
line.data = data
o = o + 1
end
end
function detailsFramework : CreateGFrame ( parent , width , height , lineWidth , onEnter , onLeave , member , name )
local newGraphicFrame = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
newGraphicFrame : SetSize ( width or 450 , height or 150 )
if ( member ) then
parent [ member ] = newGraphicFrame
end
newGraphicFrame.CreateLine = gframe_create_line
newGraphicFrame.GetLine = gframe_getline
newGraphicFrame.Reset = gframe_reset
newGraphicFrame.UpdateLines = gframe_update
newGraphicFrame.MaxValue = 0
newGraphicFrame._lines = { }
newGraphicFrame._onenter_line = onEnter
newGraphicFrame._onleave_line = onLeave
newGraphicFrame._linewidth = lineWidth or 50
newGraphicFrame._maxlines = floor ( newGraphicFrame : GetWidth ( ) / newGraphicFrame._linewidth )
return newGraphicFrame
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--options tabs and buttons -dot
function detailsFramework : FindHighestParent ( self )
local highestParent
if ( self : GetParent ( ) == UIParent ) then
highestParent = self
end
if ( not highestParent ) then
highestParent = self
for i = 1 , 6 do
local parent = highestParent : GetParent ( )
if ( parent == UIParent ) then
break
else
highestParent = parent
end
end
end
return highestParent
end
detailsFramework.TabContainerFunctions = { }
local button_tab_template = detailsFramework.table . copy ( { } , detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " ) )
button_tab_template.backdropbordercolor = nil
detailsFramework.TabContainerFunctions . CreateUnderlineGlow = function ( button )
local selectedGlow = button : CreateTexture ( nil , " background " , nil , - 4 )
selectedGlow : SetPoint ( " topleft " , button.widget , " bottomleft " , - 7 , 0 )
selectedGlow : SetPoint ( " topright " , button.widget , " bottomright " , 7 , 0 )
selectedGlow : SetTexture ( [[Interface\BUTTONS\UI-Panel-Button-Glow]] )
selectedGlow : SetTexCoord ( 0 , 95 / 128 , 30 / 64 , 38 / 64 )
selectedGlow : SetBlendMode ( " ADD " )
selectedGlow : SetHeight ( 8 )
selectedGlow : SetAlpha ( .75 )
selectedGlow : Hide ( )
button.selectedUnderlineGlow = selectedGlow
end
detailsFramework.TabContainerFunctions . OnMouseDown = function ( self , button )
--search for UIParent
local f = detailsFramework : FindHighestParent ( self )
local container = self : GetParent ( )
if ( button == " LeftButton " ) then
if ( not f.IsMoving and f : IsMovable ( ) ) then
f : StartMoving ( )
f.IsMoving = true
end
elseif ( button == " RightButton " ) then
if ( not f.IsMoving and container.IsContainer ) then
if ( self.IsFrontPage ) then
if ( container.CanCloseWithRightClick ) then
if ( f.CloseFunction ) then
f : CloseFunction ( )
else
f : Hide ( )
end
end
else
--goes back to front page
detailsFramework.TabContainerFunctions . SelectIndex ( self , _ , 1 )
end
end
end
end
detailsFramework.TabContainerFunctions . OnMouseUp = function ( self , button )
local f = detailsFramework : FindHighestParent ( self )
if ( f.IsMoving ) then
f : StopMovingOrSizing ( )
f.IsMoving = false
end
end
detailsFramework.TabContainerFunctions . SelectIndex = function ( self , fixedParam , menuIndex )
local mainFrame = self.AllFrames and self or self.mainFrame or self : GetParent ( )
for i = 1 , # mainFrame.AllFrames do
mainFrame.AllFrames [ i ] : Hide ( )
if ( mainFrame.ButtonNotSelectedBorderColor ) then
mainFrame.AllButtons [ i ] : SetBackdropBorderColor ( unpack ( mainFrame.ButtonNotSelectedBorderColor ) )
end
if ( mainFrame.AllButtons [ i ] . selectedUnderlineGlow ) then
mainFrame.AllButtons [ i ] . selectedUnderlineGlow : Hide ( )
end
end
mainFrame.AllFrames [ menuIndex ] : Show ( )
if mainFrame.AllFrames [ menuIndex ] . RefreshOptions then
mainFrame.AllFrames [ menuIndex ] : RefreshOptions ( )
end
if ( mainFrame.ButtonSelectedBorderColor ) then
mainFrame.AllButtons [ menuIndex ] : SetBackdropBorderColor ( unpack ( mainFrame.ButtonSelectedBorderColor ) )
end
if ( mainFrame.AllButtons [ menuIndex ] . selectedUnderlineGlow ) then
mainFrame.AllButtons [ menuIndex ] . selectedUnderlineGlow : Show ( )
end
mainFrame.CurrentIndex = menuIndex
if ( mainFrame.hookList . OnSelectIndex ) then
detailsFramework : QuickDispatch ( mainFrame.hookList . OnSelectIndex , mainFrame , mainFrame.AllButtons [ menuIndex ] )
end
end
detailsFramework.TabContainerFunctions . SetIndex = function ( self , index )
self.CurrentIndex = index
end
local tab_container_on_show = function ( self )
local index = self.CurrentIndex
self.SelectIndex ( self.AllButtons [ index ] , nil , index )
end
function detailsFramework : CreateTabContainer ( parent , title , frame_name , frameList , options_table , hookList )
local options_text_template = detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " )
local options_dropdown_template = detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local options_switch_template = detailsFramework : GetTemplate ( " switch " , " OPTIONS_CHECKBOX_TEMPLATE " )
local options_slider_template = detailsFramework : GetTemplate ( " slider " , " OPTIONS_SLIDER_TEMPLATE " )
local options_button_template = detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " )
options_table = options_table or { }
local parentFrameWidth = parent : GetWidth ( )
local y_offset = options_table.y_offset or 0
local buttonWidth = options_table.button_width or 160
local buttonHeight = options_table.button_height or 20
local buttonAnchorX = options_table.button_x or 230
local buttonAnchorY = options_table.button_y or - 32
local button_text_size = options_table.button_text_size or 10
local containerWidthOffset = options_table.container_width_offset or 0
local mainFrame = CreateFrame ( " frame " , frame_name , parent.widget or parent , " BackdropTemplate " )
mainFrame : SetAllPoints ( )
detailsFramework : Mixin ( mainFrame , detailsFramework.TabContainerFunctions )
mainFrame.hookList = hookList or { }
local mainTitle = detailsFramework : CreateLabel ( mainFrame , title , 24 , " white " )
mainTitle : SetPoint ( " topleft " , mainFrame , " topleft " , 10 , - 30 + y_offset )
mainFrame : SetFrameLevel ( 200 )
mainFrame.AllFrames = { }
mainFrame.AllButtons = { }
mainFrame.CurrentIndex = 1
mainFrame.IsContainer = true
mainFrame.ButtonSelectedBorderColor = options_table.button_selected_border_color or { 1 , 1 , 0 , 1 }
mainFrame.ButtonNotSelectedBorderColor = options_table.button_border_color or { 0 , 0 , 0 , 0 }
if ( options_table.right_click_interact ~= nil ) then
mainFrame.CanCloseWithRightClick = options_table.right_click_interact
else
mainFrame.CanCloseWithRightClick = true
end
for i , frame in ipairs ( frameList ) do
local f = CreateFrame ( " frame " , " $parent " .. frame.name , mainFrame , " BackdropTemplate " )
f : SetAllPoints ( )
f : SetFrameLevel ( 210 )
f : Hide ( )
local title = detailsFramework : CreateLabel ( f , frame.title , 16 , " silver " )
title : SetPoint ( " topleft " , mainTitle , " bottomleft " , 0 , 0 )
f.titleText = title
local tabButton = detailsFramework : CreateButton ( mainFrame , detailsFramework.TabContainerFunctions . SelectIndex , buttonWidth , buttonHeight , frame.title , i , nil , nil , nil , " $parentTabButton " .. frame.name , false , button_tab_template )
PixelUtil.SetSize ( tabButton , buttonWidth , buttonHeight )
tabButton : SetFrameLevel ( 220 )
tabButton.textsize = button_text_size
tabButton.mainFrame = mainFrame
detailsFramework.TabContainerFunctions . CreateUnderlineGlow ( tabButton )
local right_click_to_back
if ( i == 1 or options_table.rightbutton_always_close ) then
right_click_to_back = detailsFramework : CreateLabel ( f , " right click to close " , 10 , " gray " )
right_click_to_back : SetPoint ( " bottomright " , f , " bottomright " , - 1 , options_table.right_click_y or 0 )
if ( options_table.close_text_alpha ) then
right_click_to_back : SetAlpha ( options_table.close_text_alpha )
end
f.IsFrontPage = true
else
right_click_to_back = detailsFramework : CreateLabel ( f , " right click to go back to main menu " , 10 , " gray " )
right_click_to_back : SetPoint ( " bottomright " , f , " bottomright " , - 1 , options_table.right_click_y or 0 )
if ( options_table.close_text_alpha ) then
right_click_to_back : SetAlpha ( options_table.close_text_alpha )
end
end
if ( options_table.hide_click_label ) then
right_click_to_back : Hide ( )
end
f : SetScript ( " OnMouseDown " , detailsFramework.TabContainerFunctions . OnMouseDown )
f : SetScript ( " OnMouseUp " , detailsFramework.TabContainerFunctions . OnMouseUp )
tinsert ( mainFrame.AllFrames , f )
tinsert ( mainFrame.AllButtons , tabButton )
end
--order buttons
local x = buttonAnchorX
local y = buttonAnchorY
local spaceBetweenButtons = 3
local allocatedSpaceForButtons = parentFrameWidth - ( ( # frameList - 2 ) * spaceBetweenButtons ) - buttonAnchorX + containerWidthOffset
local amountButtonsPerRow = floor ( allocatedSpaceForButtons / buttonWidth )
mainFrame.AllButtons [ 1 ] : SetPoint ( " topleft " , mainTitle , " topleft " , x , y )
x = x + buttonWidth + 2
for i = 2 , # mainFrame.AllButtons do
local button = mainFrame.AllButtons [ i ]
PixelUtil.SetPoint ( button , " topleft " , mainTitle , " topleft " , x , y )
x = x + buttonWidth + 2
if ( i % amountButtonsPerRow == 0 ) then
x = buttonAnchorX
y = y - buttonHeight - 1
end
end
--when show the frame, reset to the current internal index
mainFrame : SetScript ( " OnShow " , tab_container_on_show )
--select the first frame
mainFrame.SelectIndex ( mainFrame.AllButtons [ 1 ] , nil , 1 )
return mainFrame
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~right ~click to ~close
function detailsFramework : CreateRightClickToClose ( parent , xOffset , yOffset , color , fontSize )
--default values
xOffset = xOffset or 0
yOffset = yOffset or 0
color = color or " white "
fontSize = fontSize or 10
local label = detailsFramework : CreateLabel ( parent , " right click to close " , fontSize , color )
label : SetPoint ( " bottomright " , parent , " bottomright " , - 4 + xOffset , 5 + yOffset )
return label
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~listbox
local simple_list_box_ResetWidgets = function ( self )
for _ , widget in ipairs ( self.widgets ) do
widget : Hide ( )
end
self.nextWidget = 1
end
local simple_list_box_onenter = function ( self , capsule )
self : GetParent ( ) . options.onenter ( self , capsule , capsule.value )
end
local simple_list_box_onleave = function ( self , capsule )
self : GetParent ( ) . options.onleave ( self , capsule , capsule.value )
GameTooltip : Hide ( )
end
local simple_list_box_GetOrCreateWidget = function ( self )
local index = self.nextWidget
local widget = self.widgets [ index ]
if ( not widget ) then
widget = detailsFramework : CreateButton ( self , function ( ) end , self.options . width , self.options . row_height , " " , nil , nil , nil , nil , nil , nil , detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " ) )
widget : SetHook ( " OnEnter " , simple_list_box_onenter )
widget : SetHook ( " OnLeave " , simple_list_box_onleave )
widget.textcolor = self.options . textcolor
widget.textsize = self.options . text_size
widget.onleave_backdrop = self.options . backdrop_color
widget.XButton = detailsFramework : CreateButton ( widget , function ( ) end , 16 , 16 )
widget.XButton : SetPoint ( " topright " , widget.widget , " topright " )
widget.XButton : SetIcon ( [[Interface\BUTTONS\UI-Panel-MinimizeButton-Up]] , 16 , 16 , " overlay " , nil , nil , 0 , - 4 , 0 , false )
widget.XButton . icon : SetDesaturated ( true )
if ( not self.options . show_x_button ) then
widget.XButton : Hide ( )
end
tinsert ( self.widgets , widget )
end
self.nextWidget = self.nextWidget + 1
return widget
end
local simple_list_box_RefreshWidgets = function ( self )
self : ResetWidgets ( )
local amt = 0
for value , _ in pairs ( self.list_table ) do
local widget = self : GetOrCreateWidget ( )
widget : SetPoint ( " topleft " , self , " topleft " , 1 , - self.options . row_height * ( self.nextWidget - 2 ) - 4 )
widget : SetPoint ( " topright " , self , " topright " , - 1 , - self.options . row_height * ( self.nextWidget - 2 ) - 4 )
widget : SetClickFunction ( self.func , value )
if ( self.options . show_x_button ) then
widget.XButton : SetClickFunction ( self.options . x_button_func , value )
widget.XButton . value = value
widget.XButton : Show ( )
else
widget.XButton : Hide ( )
end
widget.value = value
if ( self.options . icon ) then
if ( type ( self.options . icon ) == " string " or type ( self.options . icon ) == " number " ) then
local coords = type ( self.options . iconcoords ) == " table " and self.options . iconcoords or { 0 , 1 , 0 , 1 }
widget : SetIcon ( self.options . icon , self.options . row_height - 2 , self.options . row_height - 2 , " overlay " , coords )
elseif ( type ( self.options . icon ) == " function " ) then
local icon = self.options . icon ( value )
if ( icon ) then
local coords = type ( self.options . iconcoords ) == " table " and self.options . iconcoords or { 0 , 1 , 0 , 1 }
widget : SetIcon ( icon , self.options . row_height - 2 , self.options . row_height - 2 , " overlay " , coords )
end
end
else
widget : SetIcon ( " " , self.options . row_height , self.options . row_height )
end
if ( self.options . text ) then
if ( type ( self.options . text ) == " function " ) then
local text = self.options . text ( value )
if ( text ) then
widget : SetText ( text )
else
widget : SetText ( " " )
end
else
widget : SetText ( self.options . text or " " )
end
else
widget : SetText ( " " )
end
widget.value = value
local r , g , b , a = detailsFramework : ParseColors ( self.options . backdrop_color )
widget : SetBackdropColor ( r , g , b , a )
widget : Show ( )
amt = amt + 1
end
if ( amt == 0 ) then
self.EmptyLabel : Show ( )
else
self.EmptyLabel : Hide ( )
end
end
local backdrop = { bgFile = " Interface \\ Tooltips \\ UI-Tooltip-Background " , tile = true , tileSize = 16 , edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 }
local default_options = {
height = 400 ,
row_height = 16 ,
width = 230 ,
icon = false ,
text = " " ,
text_size = 10 ,
textcolor = " wheat " ,
backdrop_color = { 1 , 1 , 1 , .5 } ,
panel_border_color = { 0 , 0 , 0 , 0.5 } ,
onenter = function ( self , capsule )
if ( capsule ) then
capsule.textcolor = " white "
end
end ,
onleave = function ( self , capsule )
if ( capsule ) then
capsule.textcolor = self : GetParent ( ) . options.textcolor
end
GameTooltip : Hide ( )
end ,
}
local simple_list_box_SetData = function ( self , t )
self.list_table = t
end
function detailsFramework : CreateSimpleListBox ( parent , name , title , empty_text , list_table , onclick , options )
local f = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
f.ResetWidgets = simple_list_box_ResetWidgets
f.GetOrCreateWidget = simple_list_box_GetOrCreateWidget
f.Refresh = simple_list_box_RefreshWidgets
f.SetData = simple_list_box_SetData
f.nextWidget = 1
f.list_table = list_table
f.func = function ( self , button , value )
--onclick (value)
detailsFramework : QuickDispatch ( onclick , value )
f : Refresh ( )
end
f.widgets = { }
detailsFramework : ApplyStandardBackdrop ( f )
f.options = options or { }
self.table . deploy ( f.options , default_options )
if ( f.options . x_button_func ) then
local original_X_function = f.options . x_button_func
f.options . x_button_func = function ( self , button , value )
detailsFramework : QuickDispatch ( original_X_function , value )
f : Refresh ( )
end
end
f : SetBackdropBorderColor ( unpack ( f.options . panel_border_color ) )
f : SetSize ( f.options . width + 2 , f.options . height )
local name = detailsFramework : CreateLabel ( f , title , 12 , " silver " )
name : SetTemplate ( detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
name : SetPoint ( " bottomleft " , f , " topleft " , 0 , 2 )
f.Title = name
local emptyLabel = detailsFramework : CreateLabel ( f , empty_text , 12 , " gray " )
emptyLabel : SetAlpha ( .6 )
emptyLabel : SetSize ( f.options . width - 10 , f.options . height )
emptyLabel : SetPoint ( " center " , 0 , 0 )
emptyLabel : Hide ( )
emptyLabel.align = " center "
f.EmptyLabel = emptyLabel
return f
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~scrollbox
function detailsFramework : CreateScrollBox ( parent , name , refreshFunc , data , width , height , lineAmount , lineHeight , createLineFunc , autoAmount , noScroll )
local scroll = CreateFrame ( " scrollframe " , name , parent , " FauxScrollFrameTemplate, BackdropTemplate " )
detailsFramework : ApplyStandardBackdrop ( scroll )
scroll : SetSize ( width , height )
scroll.LineAmount = lineAmount
scroll.LineHeight = lineHeight
scroll.IsFauxScroll = true
scroll.HideScrollBar = noScroll
scroll.Frames = { }
scroll.ReajustNumFrames = autoAmount
scroll.CreateLineFunc = createLineFunc
detailsFramework : Mixin ( scroll , detailsFramework.SortFunctions )
detailsFramework : Mixin ( scroll , detailsFramework.ScrollBoxFunctions )
scroll.refresh_func = refreshFunc
scroll.data = data
scroll : SetScript ( " OnVerticalScroll " , scroll.OnVerticalScroll )
scroll : SetScript ( " OnSizeChanged " , detailsFramework.ScrollBoxFunctions . OnSizeChanged )
return scroll
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~resizers
function detailsFramework : CreateResizeGrips ( parent )
if ( parent ) then
local parentName = parent : GetName ( )
local leftResizer = CreateFrame ( " button " , parentName and parentName .. " LeftResizer " or nil , parent , " BackdropTemplate " )
local rightResizer = CreateFrame ( " button " , parentName and parentName .. " RightResizer " or nil , parent , " BackdropTemplate " )
leftResizer : SetPoint ( " bottomleft " , parent , " bottomleft " )
rightResizer : SetPoint ( " bottomright " , parent , " bottomright " )
leftResizer : SetSize ( 16 , 16 )
rightResizer : SetSize ( 16 , 16 )
rightResizer : SetNormalTexture ( [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Up]] )
rightResizer : SetHighlightTexture ( [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Highlight]] )
rightResizer : SetPushedTexture ( [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Down]] )
leftResizer : SetNormalTexture ( [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Up]] )
leftResizer : SetHighlightTexture ( [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Highlight]] )
leftResizer : SetPushedTexture ( [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Down]] )
leftResizer : GetNormalTexture ( ) : SetTexCoord ( 1 , 0 , 0 , 1 )
leftResizer : GetHighlightTexture ( ) : SetTexCoord ( 1 , 0 , 0 , 1 )
leftResizer : GetPushedTexture ( ) : SetTexCoord ( 1 , 0 , 0 , 1 )
return leftResizer , rightResizer
end
end
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~keybind
--------------------------------
--keybind frame ~key
local ignoredKeys = {
[ " LSHIFT " ] = true ,
[ " RSHIFT " ] = true ,
[ " LCTRL " ] = true ,
[ " RCTRL " ] = true ,
[ " LALT " ] = true ,
[ " RALT " ] = true ,
[ " UNKNOWN " ] = true ,
}
local mouseKeys = {
[ " LeftButton " ] = " type1 " ,
[ " RightButton " ] = " type2 " ,
[ " MiddleButton " ] = " type3 " ,
[ " Button4 " ] = " type4 " ,
[ " Button5 " ] = " type5 " ,
[ " Button6 " ] = " type6 " ,
[ " Button7 " ] = " type7 " ,
[ " Button8 " ] = " type8 " ,
[ " Button9 " ] = " type9 " ,
[ " Button10 " ] = " type10 " ,
[ " Button11 " ] = " type11 " ,
[ " Button12 " ] = " type12 " ,
[ " Button13 " ] = " type13 " ,
[ " Button14 " ] = " type14 " ,
[ " Button15 " ] = " type15 " ,
[ " Button16 " ] = " type16 " ,
}
local keysToMouse = {
[ " type1 " ] = " LeftButton " ,
[ " type2 " ] = " RightButton " ,
[ " type3 " ] = " MiddleButton " ,
[ " type4 " ] = " Button4 " ,
[ " type5 " ] = " Button5 " ,
[ " type6 " ] = " Button6 " ,
[ " type7 " ] = " Button7 " ,
[ " type8 " ] = " Button8 " ,
[ " type9 " ] = " Button9 " ,
[ " type10 " ] = " Button10 " ,
[ " type11 " ] = " Button11 " ,
[ " type12 " ] = " Button12 " ,
[ " type13 " ] = " Button13 " ,
[ " type14 " ] = " Button14 " ,
[ " type15 " ] = " Button15 " ,
[ " type16 " ] = " Button16 " ,
}
local keybind_set_data = function ( self , new_data_table )
self.Data = new_data_table
self.keybindScroll : UpdateScroll ( )
end
function detailsFramework : CreateKeybindBox ( parent , name , data , callback , width , height , line_amount , line_height )
local options_text_template = detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " )
local options_dropdown_template = detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local options_switch_template = detailsFramework : GetTemplate ( " switch " , " OPTIONS_CHECKBOX_TEMPLATE " )
local options_slider_template = detailsFramework : GetTemplate ( " slider " , " OPTIONS_SLIDER_TEMPLATE " )
local options_button_template = detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " )
local SCROLL_ROLL_AMOUNT = line_amount
--keybind set frame
local new_keybind_frame = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
new_keybind_frame : SetSize ( width , height )
-- keybind scrollframe
local keybindScroll = CreateFrame ( " scrollframe " , " $parentScrollFrame " , new_keybind_frame , " FauxScrollFrameTemplate, BackdropTemplate " )
keybindScroll : SetSize ( 1019 , 348 )
keybindScroll.Frames = { }
new_keybind_frame.keybindScroll = keybindScroll
--waiting the player to press a key
new_keybind_frame.IsListening = false
--check for valid data table
if ( type ( data ) ~= " table " ) then
print ( " error: data must be a table. DF > CreateKeybindBox() " )
return
end
if ( not next ( data ) ) then
--build data table for the character class
local _ , unitClass = UnitClass ( " player " )
if ( unitClass ) then
local specIds = detailsFramework : GetClassSpecIDs ( unitClass )
if ( specIds ) then
for _ , specId in ipairs ( specIds ) do
data [ specId ] = { }
end
end
end
end
new_keybind_frame.Data = data
new_keybind_frame.SetData = keybind_set_data
new_keybind_frame.EditingSpec = detailsFramework : GetCurrentSpec ( )
new_keybind_frame.CurrentKeybindEditingSet = new_keybind_frame.Data [ new_keybind_frame.EditingSpec ]
local allSpecButtons = { }
local switch_spec = function ( self , button , specID )
new_keybind_frame.EditingSpec = specID
new_keybind_frame.CurrentKeybindEditingSet = new_keybind_frame.Data [ specID ]
for _ , button in ipairs ( allSpecButtons ) do
button.selectedTexture : Hide ( )
end
self.MyObject . selectedTexture : Show ( )
--feedback ao jogador uma vez que as keybinds podem ter o mesmo valor
C_Timer.After ( .04 , function ( ) new_keybind_frame : Hide ( ) end )
C_Timer.After ( .06 , function ( ) new_keybind_frame : Show ( ) end )
--atualiza a scroll
keybindScroll : UpdateScroll ( )
end
--choose which spec to use
local spec1 = detailsFramework : CreateButton ( new_keybind_frame , switch_spec , 160 , 20 , " Spec1 Placeholder Text " , 1 , _ , _ , " SpecButton1 " , _ , 0 , options_button_template , options_text_template )
local spec2 = detailsFramework : CreateButton ( new_keybind_frame , switch_spec , 160 , 20 , " Spec2 Placeholder Text " , 1 , _ , _ , " SpecButton2 " , _ , 0 , options_button_template , options_text_template )
local spec3 = detailsFramework : CreateButton ( new_keybind_frame , switch_spec , 160 , 20 , " Spec3 Placeholder Text " , 1 , _ , _ , " SpecButton3 " , _ , 0 , options_button_template , options_text_template )
local spec4 = detailsFramework : CreateButton ( new_keybind_frame , switch_spec , 160 , 20 , " Spec4 Placeholder Text " , 1 , _ , _ , " SpecButton4 " , _ , 0 , options_button_template , options_text_template )
--format the button label and icon with the spec information
local className , class = UnitClass ( " player " )
local i = 1
local specIds = detailsFramework : GetClassSpecIDs ( class )
for index , specId in ipairs ( specIds ) do
local button = new_keybind_frame [ " SpecButton " .. index ]
local spec_id , spec_name , spec_description , spec_icon , spec_background , spec_role , spec_class = DetailsFramework.GetSpecializationInfoByID ( specId )
button.text = spec_name
button : SetClickFunction ( switch_spec , specId )
button : SetIcon ( spec_icon )
button.specID = specId
local selectedTexture = button : CreateTexture ( nil , " background " )
selectedTexture : SetAllPoints ( )
selectedTexture : SetColorTexture ( 1 , 1 , 1 , 0.5 )
if ( specId ~= new_keybind_frame.EditingSpec ) then
selectedTexture : Hide ( )
end
button.selectedTexture = selectedTexture
tinsert ( allSpecButtons , button )
i = i + 1
end
local specsTitle = detailsFramework : CreateLabel ( new_keybind_frame , " Config keys for spec: " , 12 , " silver " )
specsTitle : SetPoint ( " topleft " , new_keybind_frame , " topleft " , 10 , mainStartY )
keybindScroll : SetPoint ( " topleft " , specsTitle.widget , " bottomleft " , 0 , - 120 )
spec1 : SetPoint ( " topleft " , specsTitle , " bottomleft " , 0 , - 10 )
spec2 : SetPoint ( " topleft " , specsTitle , " bottomleft " , 0 , - 30 )
spec3 : SetPoint ( " topleft " , specsTitle , " bottomleft " , 0 , - 50 )
if ( class == " DRUID " ) then
spec4 : SetPoint ( " topleft " , specsTitle , " bottomleft " , 0 , - 70 )
end
local enter_the_key = CreateFrame ( " frame " , nil , new_keybind_frame , " BackdropTemplate " )
enter_the_key : SetFrameStrata ( " tooltip " )
enter_the_key : SetSize ( 200 , 60 )
enter_the_key : SetBackdrop ( { bgFile = " Interface \\ Tooltips \\ UI-Tooltip-Background " , tile = true , tileSize = 16 , edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 } )
enter_the_key : SetBackdropColor ( 0 , 0 , 0 , 1 )
enter_the_key : SetBackdropBorderColor ( 1 , 1 , 1 , 1 )
enter_the_key.text = detailsFramework : CreateLabel ( enter_the_key , " - Press a keyboard key to bind. \n - Click to bind a mouse button. \n - Press escape to cancel. " , 11 , " orange " )
enter_the_key.text : SetPoint ( " center " , enter_the_key , " center " )
enter_the_key : Hide ( )
local registerKeybind = function ( self , key )
if ( ignoredKeys [ key ] ) then
return
end
if ( key == " ESCAPE " ) then
enter_the_key : Hide ( )
new_keybind_frame.IsListening = false
new_keybind_frame : SetScript ( " OnKeyDown " , nil )
return
end
local bind = ( IsShiftKeyDown ( ) and " SHIFT- " or " " ) .. ( IsControlKeyDown ( ) and " CTRL- " or " " ) .. ( IsAltKeyDown ( ) and " ALT- " or " " )
bind = bind .. key
--adiciona para a tabela de keybinds
local keybind = new_keybind_frame.CurrentKeybindEditingSet [ self.keybindIndex ]
keybind.key = bind
new_keybind_frame.IsListening = false
new_keybind_frame : SetScript ( " OnKeyDown " , nil )
enter_the_key : Hide ( )
new_keybind_frame.keybindScroll : UpdateScroll ( )
detailsFramework : QuickDispatch ( callback )
end
local set_keybind_key = function ( self , button , keybindIndex )
if ( new_keybind_frame.IsListening ) then
key = mouseKeys [ button ] or button
return registerKeybind ( new_keybind_frame , key )
end
new_keybind_frame.IsListening = true
new_keybind_frame.keybindIndex = keybindIndex
new_keybind_frame : SetScript ( " OnKeyDown " , registerKeybind )
enter_the_key : Show ( )
enter_the_key : SetPoint ( " bottom " , self , " top " )
end
local new_key_bind = function ( self , button , specID )
tinsert ( new_keybind_frame.CurrentKeybindEditingSet , { key = " -none- " , action = " _target " , actiontext = " " } )
FauxScrollFrame_SetOffset ( new_keybind_frame.keybindScroll , max ( # new_keybind_frame.CurrentKeybindEditingSet - SCROLL_ROLL_AMOUNT , 0 ) )
new_keybind_frame.keybindScroll : UpdateScroll ( )
end
local set_action_text = function ( keybindIndex , _ , text )
local keybind = new_keybind_frame.CurrentKeybindEditingSet [ keybindIndex ]
keybind.actiontext = text
detailsFramework : QuickDispatch ( callback )
end
local set_action_on_espace_press = function ( textentry , capsule )
capsule = capsule or textentry.MyObject
local keybind = new_keybind_frame.CurrentKeybindEditingSet [ capsule.CurIndex ]
textentry : SetText ( keybind.actiontext )
detailsFramework : QuickDispatch ( callback )
end
local lock_textentry = {
[ " _target " ] = true ,
[ " _taunt " ] = true ,
[ " _interrupt " ] = true ,
[ " _dispel " ] = true ,
[ " _spell " ] = false ,
[ " _macro " ] = false ,
}
local change_key_action = function ( self , keybindIndex , value )
local keybind = new_keybind_frame.CurrentKeybindEditingSet [ keybindIndex ]
keybind.action = value
new_keybind_frame.keybindScroll : UpdateScroll ( )
detailsFramework : QuickDispatch ( callback )
end
local fill_action_dropdown = function ( )
local locClass , class = UnitClass ( " player " )
local taunt = " "
local interrupt = " "
local dispel = " "
if ( type ( dispel ) == " table " ) then
local dispelString = " \n "
for specID , spellid in pairs ( dispel ) do
local specid , specName = DetailsFramework.GetSpecializationInfoByID ( specID )
local spellName = GetSpellInfo ( spellid )
dispelString = dispelString .. " |cFFE5E5E5 " .. ( specName or " " ) .. " |r: |cFFFFFFFF " .. spellName .. " \n "
end
dispel = dispelString
else
dispel = " "
end
return {
--{value = "_target", label = "Target", onclick = change_key_action, desc = "Target the unit"},
--{value = "_taunt", label = "Taunt", onclick = change_key_action, desc = "Cast the taunt spell for your class\n\n|cFFFFFFFFSpell: " .. taunt},
--{value = "_interrupt", label = "Interrupt", onclick = change_key_action, desc = "Cast the interrupt spell for your class\n\n|cFFFFFFFFSpell: " .. interrupt},
--{value = "_dispel", label = "Dispel", onclick = change_key_action, desc = "Cast the interrupt spell for your class\n\n|cFFFFFFFFSpell: " .. dispel},
{ value = " _spell " , label = " Cast Spell " , onclick = change_key_action , desc = " Type the spell name in the text box " } ,
{ value = " _macro " , label = " Run Macro " , onclick = change_key_action , desc = " Type your macro in the text box " } ,
}
end
local copy_keybind = function ( self , button , keybindIndex )
local keybind = new_keybind_frame.CurrentKeybindEditingSet [ keybindIndex ]
for specID , t in pairs ( new_keybind_frame.Data ) do
if ( specID ~= new_keybind_frame.EditingSpec ) then
local key = CopyTable ( keybind )
local specid , specName = DetailsFramework.GetSpecializationInfoByID ( specID )
tinsert ( new_keybind_frame.Data [ specID ] , key )
detailsFramework : Msg ( " Keybind copied to " .. ( specName or " " ) )
end
end
detailsFramework : QuickDispatch ( callback )
end
local delete_keybind = function ( self , button , keybindIndex )
tremove ( new_keybind_frame.CurrentKeybindEditingSet , keybindIndex )
new_keybind_frame.keybindScroll : UpdateScroll ( )
detailsFramework : QuickDispatch ( callback )
end
local newTitle = detailsFramework : CreateLabel ( new_keybind_frame , " Create a new Keybind: " , 12 , " silver " )
newTitle : SetPoint ( " topleft " , new_keybind_frame , " topleft " , 200 , mainStartY )
local createNewKeybind = detailsFramework : CreateButton ( new_keybind_frame , new_key_bind , 160 , 20 , " New Key Bind " , 1 , _ , _ , " NewKeybindButton " , _ , 0 , options_button_template , options_text_template )
createNewKeybind : SetPoint ( " topleft " , newTitle , " bottomleft " , 0 , - 10 )
--createNewKeybind:SetIcon ([[Interface\Buttons\UI-GuildButton-PublicNote-Up]])
local update_keybind_list = function ( self )
local keybinds = new_keybind_frame.CurrentKeybindEditingSet
FauxScrollFrame_Update ( self , # keybinds , SCROLL_ROLL_AMOUNT , 21 )
local offset = FauxScrollFrame_GetOffset ( self )
for i = 1 , SCROLL_ROLL_AMOUNT do
local index = i + offset
local f = self.Frames [ i ]
local data = keybinds [ index ]
if ( data ) then
--index
f.Index . text = index
--keybind
local keyBindText = keysToMouse [ data.key ] or data.key
keyBindText = keyBindText : gsub ( " type1 " , " LeftButton " )
keyBindText = keyBindText : gsub ( " type2 " , " RightButton " )
keyBindText = keyBindText : gsub ( " type3 " , " MiddleButton " )
f.KeyBind . text = keyBindText
f.KeyBind : SetClickFunction ( set_keybind_key , index , nil , " left " )
f.KeyBind : SetClickFunction ( set_keybind_key , index , nil , " right " )
--action
f.ActionDrop : SetFixedParameter ( index )
f.ActionDrop : Select ( data.action )
--action text
f.ActionText . text = data.actiontext
f.ActionText : SetEnterFunction ( set_action_text , index )
f.ActionText . CurIndex = index
if ( lock_textentry [ data.action ] ) then
f.ActionText : Disable ( )
else
f.ActionText : Enable ( )
end
--copy
f.Copy : SetClickFunction ( copy_keybind , index )
--delete
f.Delete : SetClickFunction ( delete_keybind , index )
f : Show ( )
else
f : Hide ( )
end
end
self : Show ( )
end
keybindScroll : SetScript ( " OnVerticalScroll " , function ( self , offset )
FauxScrollFrame_OnVerticalScroll ( self , offset , 21 , update_keybind_list )
end )
keybindScroll.UpdateScroll = update_keybind_list
local backdropColor = { .3 , .3 , .3 , .3 }
local backdropColorOnEnter = { .6 , .6 , .6 , .6 }
local on_enter = function ( self )
self : SetBackdropColor ( unpack ( backdropColorOnEnter ) )
end
local on_leave = function ( self )
self : SetBackdropColor ( unpack ( backdropColor ) )
end
local font = " GameFontHighlightSmall "
for i = 1 , SCROLL_ROLL_AMOUNT do
local f = CreateFrame ( " frame " , " $KeyBindFrame " .. i , keybindScroll , " BackdropTemplate " )
f : SetSize ( 1009 , 20 )
f : SetPoint ( " topleft " , keybindScroll , " topleft " , 0 , - ( i - 1 ) * 29 )
f : SetBackdrop ( { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } )
f : SetBackdropColor ( unpack ( backdropColor ) )
f : SetScript ( " OnEnter " , on_enter )
f : SetScript ( " OnLeave " , on_leave )
tinsert ( keybindScroll.Frames , f )
f.Index = detailsFramework : CreateLabel ( f , " 1 " )
f.KeyBind = detailsFramework : CreateButton ( f , set_key_bind , 100 , 20 , " " , _ , _ , _ , " SetNewKeybindButton " , _ , 0 , options_button_template , options_text_template )
f.ActionDrop = detailsFramework : CreateDropDown ( f , fill_action_dropdown , 0 , 120 , 20 , " ActionDropdown " , _ , options_dropdown_template )
f.ActionText = detailsFramework : CreateTextEntry ( f , function ( ) end , 660 , 20 , " TextBox " , _ , _ , options_dropdown_template )
f.Copy = detailsFramework : CreateButton ( f , copy_keybind , 20 , 20 , " " , _ , _ , _ , " CopyKeybindButton " , _ , 0 , options_button_template , options_text_template )
f.Delete = detailsFramework : CreateButton ( f , delete_keybind , 16 , 20 , " " , _ , _ , _ , " DeleteKeybindButton " , _ , 2 , options_button_template , options_text_template )
f.Index : SetPoint ( " left " , f , " left " , 10 , 0 )
f.KeyBind : SetPoint ( " left " , f , " left " , 43 , 0 )
f.ActionDrop : SetPoint ( " left " , f , " left " , 150 , 0 )
f.ActionText : SetPoint ( " left " , f , " left " , 276 , 0 )
f.Copy : SetPoint ( " left " , f , " left " , 950 , 0 )
f.Delete : SetPoint ( " left " , f , " left " , 990 , 0 )
f.Copy : SetIcon ( [[Interface\Buttons\UI-GuildButton-PublicNote-Up]] , nil , nil , nil , nil , nil , nil , 4 )
f.Delete : SetIcon ( [[Interface\Buttons\UI-StopButton]] , nil , nil , nil , nil , nil , nil , 4 )
f.Copy . tooltip = " copy this keybind to other specs "
f.Delete . tooltip = " erase this keybind "
--editbox
f.ActionText : SetJustifyH ( " left " )
f.ActionText : SetHook ( " OnEscapePressed " , set_action_on_espace_press )
f.ActionText : SetHook ( " OnEditFocusGained " , function ( )
local playerSpells = { }
local tab , tabTex , offset , numSpells = GetSpellTabInfo ( 2 )
for i = 1 , numSpells do
local index = offset + i
local spellType , spellId = GetSpellBookItemInfo ( index , " player " )
if ( spellType == " SPELL " ) then
local spellName = GetSpellInfo ( spellId )
tinsert ( playerSpells , spellName )
end
end
f.ActionText . WordList = playerSpells
end )
f.ActionText : SetAsAutoComplete ( " WordList " )
end
local header = CreateFrame ( " frame " , " $parentOptionsPanelFrameHeader " , keybindScroll , " BackdropTemplate " )
header : SetPoint ( " bottomleft " , keybindScroll , " topleft " , 0 , 2 )
header : SetPoint ( " bottomright " , keybindScroll , " topright " , 0 , 2 )
header : SetHeight ( 16 )
header.Index = detailsFramework : CreateLabel ( header , " Index " , detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
header.Key = detailsFramework : CreateLabel ( header , " Key " , detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
header.Action = detailsFramework : CreateLabel ( header , " Action " , detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
header.Macro = detailsFramework : CreateLabel ( header , " Spell Name / Macro " , detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
header.Copy = detailsFramework : CreateLabel ( header , " Copy " , detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
header.Delete = detailsFramework : CreateLabel ( header , " Delete " , detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " ) )
header.Index : SetPoint ( " left " , header , " left " , 10 , 0 )
header.Key : SetPoint ( " left " , header , " left " , 43 , 0 )
header.Action : SetPoint ( " left " , header , " left " , 150 , 0 )
header.Macro : SetPoint ( " left " , header , " left " , 276 , 0 )
header.Copy : SetPoint ( " left " , header , " left " , 950 , 0 )
header.Delete : SetPoint ( " left " , header , " left " , 990 , 0 )
new_keybind_frame : SetScript ( " OnShow " , function ( )
--new_keybind_frame.EditingSpec = EnemyGrid.CurrentSpec
--new_keybind_frame.CurrentKeybindEditingSet = EnemyGrid.CurrentKeybindSet
for _ , button in ipairs ( allSpecButtons ) do
if ( new_keybind_frame.EditingSpec ~= button.specID ) then
button.selectedTexture : Hide ( )
else
button.selectedTexture : Show ( )
end
end
keybindScroll : UpdateScroll ( )
end )
new_keybind_frame : SetScript ( " OnHide " , function ( )
if ( new_keybind_frame.IsListening ) then
new_keybind_frame.IsListening = false
new_keybind_frame : SetScript ( " OnKeyDown " , nil )
end
end )
return new_keybind_frame
end
function detailsFramework : BuildKeybindFunctions ( data , prefix )
--~keybind
local classLoc , class = UnitClass ( " player " )
local bindingList = data
local bindString = " self:ClearBindings() "
local bindKeyBindTypeFunc = [[local unitFrame = ...]]
local bindMacroTextFunc = [[local unitFrame = ...]]
local isMouseBinding
for i = 1 , # bindingList do
local bind = bindingList [ i ]
local bindType
--which button to press
if ( bind.key : find ( " type " ) ) then
local keyNumber = tonumber ( bind.key : match ( " %d " ) )
bindType = keyNumber
isMouseBinding = true
else
bindType = prefix .. " " .. i
bindString = bindString .. " self:SetBindingClick (0, ' " .. bind.key .. " ', self:GetName(), ' " .. bindType .. " ') "
bindType = " - " .. prefix .. " " .. i
isMouseBinding = nil
end
--keybind type
local shift , alt , ctrl = bind.key : match ( " SHIFT " ) , bind.key : match ( " ALT " ) , bind.key : match ( " CTRL " )
local CommandKeys = alt and alt .. " - " or " "
CommandKeys = ctrl and CommandKeys .. ctrl .. " - " or CommandKeys
CommandKeys = shift and CommandKeys .. shift .. " - " or CommandKeys
local keyBindType
if ( isMouseBinding ) then
keyBindType = [[unitFrame:SetAttribute ("@COMMANDtype@BINDTYPE", "macro")]]
else
keyBindType = [[unitFrame:SetAttribute ("type@BINDTYPE", "macro")]]
end
keyBindType = keyBindType : gsub ( " @BINDTYPE " , bindType )
keyBindType = keyBindType : gsub ( " @COMMAND " , CommandKeys )
bindKeyBindTypeFunc = bindKeyBindTypeFunc .. keyBindType
--spell or macro
if ( bind.action == " _spell " ) then
local macroTextLine
if ( isMouseBinding ) then
macroTextLine = [[unitFrame:SetAttribute ("@COMMANDmacrotext@BINDTYPE", "/cast [@mouseover] @SPELL")]]
else
macroTextLine = [[unitFrame:SetAttribute ("macrotext@BINDTYPE", "/cast [@mouseover] @SPELL")]]
end
macroTextLine = macroTextLine : gsub ( " @BINDTYPE " , bindType )
macroTextLine = macroTextLine : gsub ( " @SPELL " , bind.actiontext )
macroTextLine = macroTextLine : gsub ( " @COMMAND " , CommandKeys )
bindMacroTextFunc = bindMacroTextFunc .. macroTextLine
elseif ( bind.action == " _macro " ) then
local macroTextLine
if ( isMouseBinding ) then
macroTextLine = [[unitFrame:SetAttribute ("@COMMANDmacrotext@BINDTYPE", "@MACRO")]]
else
macroTextLine = [[unitFrame:SetAttribute ("macrotext@BINDTYPE", "@MACRO")]]
end
macroTextLine = macroTextLine : gsub ( " @BINDTYPE " , bindType )
macroTextLine = macroTextLine : gsub ( " @MACRO " , bind.actiontext )
macroTextLine = macroTextLine : gsub ( " @COMMAND " , CommandKeys )
bindMacroTextFunc = bindMacroTextFunc .. macroTextLine
end
end
--~key
local bindTypeFuncLoaded = loadstring ( bindKeyBindTypeFunc )
local bindMacroFuncLoaded = loadstring ( bindMacroTextFunc )
if ( not bindMacroFuncLoaded or not bindTypeFuncLoaded ) then
return
end
return bindString , bindTypeFuncLoaded , bindMacroFuncLoaded
end
function detailsFramework : SetKeybindsOnProtectedFrame ( frame , bind_string , bind_type_func , bind_macro_func )
bind_type_func ( frame )
bind_macro_func ( frame )
frame : SetAttribute ( " _onenter " , bind_string )
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~standard backdrop
function detailsFramework : ApplyStandardBackdrop ( frame , solidColor , alphaScale )
alphaScale = alphaScale or 0.95
if ( not frame.SetBackdrop ) then
--print(debugstack(1,2,1))
Mixin ( frame , BackdropTemplateMixin )
end
local red , green , blue , alpha = detailsFramework : GetDefaultBackdropColor ( )
if ( solidColor ) then
local colorDeviation = 0.05
frame : SetBackdrop ( { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Buttons\WHITE8X8]] , tileSize = 32 , tile = true } )
frame : SetBackdropColor ( red , green , blue , 0.872 )
frame : SetBackdropBorderColor ( 0 , 0 , 0 , 0.95 )
else
frame : SetBackdrop ( { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } )
frame : SetBackdropColor ( red , green , blue , alpha * alphaScale )
frame : SetBackdropBorderColor ( 0 , 0 , 0 , 0.95 )
end
if ( not frame.__background ) then
frame.__background = frame : CreateTexture ( nil , " background " )
frame.__background : SetColorTexture ( red , green , blue )
frame.__background : SetAllPoints ( )
end
frame.__background : SetAlpha ( alpha * alphaScale )
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~title bar
detailsFramework.TitleFunctions = {
SetTitle = function ( self , titleText , titleColor , font , size )
self.TitleLabel : SetText ( titleText or self.TitleLabel : GetText ( ) )
if ( titleColor ) then
local r , g , b , a = detailsFramework : ParseColors ( titleColor )
self.TitleLabel : SetTextColor ( r , g , b , a )
end
if ( font ) then
detailsFramework : SetFontFace ( self.TitleLabel , font )
end
if ( size ) then
detailsFramework : SetFontSize ( self.TitleLabel , size )
end
end
}
function detailsFramework : CreateTitleBar ( f , titleText )
local titleBar = CreateFrame ( " frame " , f : GetName ( ) and f : GetName ( ) .. " TitleBar " or nil , f , " BackdropTemplate " )
titleBar : SetPoint ( " topleft " , f , " topleft " , 2 , - 3 )
titleBar : SetPoint ( " topright " , f , " topright " , - 2 , - 3 )
titleBar : SetHeight ( 20 )
titleBar : SetBackdrop ( SimplePanel_frame_backdrop ) --it's an upload from this file
titleBar : SetBackdropColor ( .2 , .2 , .2 , 1 )
titleBar : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
local closeButton = CreateFrame ( " button " , titleBar : GetName ( ) and titleBar : GetName ( ) .. " CloseButton " or nil , titleBar , " BackdropTemplate " )
closeButton : SetSize ( 16 , 16 )
closeButton : SetNormalTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
closeButton : SetHighlightTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
closeButton : SetPushedTexture ( [[Interface\GLUES\LOGIN\Glues-CheckBox-Check]] )
closeButton : GetNormalTexture ( ) : SetDesaturated ( true )
closeButton : GetHighlightTexture ( ) : SetDesaturated ( true )
closeButton : GetPushedTexture ( ) : SetDesaturated ( true )
closeButton : SetAlpha ( 0.7 )
closeButton : SetScript ( " OnClick " , simple_panel_close_click ) --upvalue from this file
local titleLabel = titleBar : CreateFontString ( titleBar : GetName ( ) and titleBar : GetName ( ) .. " TitleText " or nil , " overlay " , " GameFontNormal " )
titleLabel : SetTextColor ( .8 , .8 , .8 , 1 )
titleLabel : SetText ( titleText or " " )
--anchors
closeButton : SetPoint ( " right " , titleBar , " right " , - 2 , 0 )
titleLabel : SetPoint ( " center " , titleBar , " center " )
--members
f.TitleBar = titleBar
f.CloseButton = closeButton
f.TitleLabel = titleLabel
titleBar.CloseButton = closeButton
titleBar.Text = titleLabel
detailsFramework : Mixin ( f , detailsFramework.TitleFunctions )
return titleBar
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- ~icon row
detailsFramework.IconRowFunctions = {
GetIcon = function ( self )
local iconFrame = self.IconPool [ self.NextIcon ]
if ( not iconFrame ) then
local newIconFrame = CreateFrame ( " frame " , " $parentIcon " .. self.NextIcon , self , " BackdropTemplate " )
newIconFrame.parentIconRow = self
newIconFrame.Texture = newIconFrame : CreateTexture ( nil , " artwork " )
PixelUtil.SetPoint ( newIconFrame.Texture , " topleft " , newIconFrame , " topleft " , 1 , - 1 )
PixelUtil.SetPoint ( newIconFrame.Texture , " bottomright " , newIconFrame , " bottomright " , - 1 , 1 )
newIconFrame.Border = newIconFrame : CreateTexture ( nil , " background " )
newIconFrame.Border : SetAllPoints ( )
newIconFrame.Border : SetColorTexture ( 0 , 0 , 0 )
newIconFrame : SetBackdrop ( { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 } )
newIconFrame : SetBackdropBorderColor ( 0 , 0 , 0 , 0 )
newIconFrame : EnableMouse ( false )
local cooldownFrame = CreateFrame ( " cooldown " , " $parentIconCooldown " .. self.NextIcon , newIconFrame , " CooldownFrameTemplate, BackdropTemplate " )
cooldownFrame : SetAllPoints ( )
cooldownFrame : EnableMouse ( false )
cooldownFrame : SetFrameLevel ( newIconFrame : GetFrameLevel ( ) + 1 )
cooldownFrame : SetHideCountdownNumbers ( self.options . surpress_blizzard_cd_timer )
cooldownFrame.noCooldownCount = self.options . surpress_tulla_omni_cc
newIconFrame.CountdownText = cooldownFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " )
--newIconFrame.CountdownText:SetPoint("center")
newIconFrame.CountdownText : SetPoint ( self.options . text_anchor or " center " , newIconFrame , self.options . text_rel_anchor or " center " , self.options . text_x_offset or 0 , self.options . text_y_offset or 0 )
newIconFrame.CountdownText : Hide ( )
newIconFrame.StackText = newIconFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " )
--newIconFrame.StackText:SetPoint("bottomright")
newIconFrame.StackText : SetPoint ( self.options . stack_text_anchor or " center " , newIconFrame , self.options . stack_text_rel_anchor or " bottomright " , self.options . stack_text_x_offset or 0 , self.options . stack_text_y_offset or 0 )
newIconFrame.StackText : Hide ( )
newIconFrame.Desc = newIconFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " )
--newIconFrame.Desc:SetPoint("bottom", newIconFrame, "top", 0, 2)
newIconFrame.Desc : SetPoint ( self.options . desc_text_anchor or " bottom " , newIconFrame , self.options . desc_text_rel_anchor or " top " , self.options . desc_text_x_offset or 0 , self.options . desc_text_y_offset or 2 )
newIconFrame.Desc : Hide ( )
newIconFrame.Cooldown = cooldownFrame
self.IconPool [ self.NextIcon ] = newIconFrame
iconFrame = newIconFrame
end
iconFrame : ClearAllPoints ( )
local anchor = self.options . anchor
local anchorTo = self.NextIcon == 1 and self or self.IconPool [ self.NextIcon - 1 ]
local xPadding = self.NextIcon == 1 and self.options . left_padding or self.options . icon_padding or 1
local growDirection = self.options . grow_direction
if ( growDirection == 1 ) then --grow to right
if ( self.NextIcon == 1 ) then
PixelUtil.SetPoint ( iconFrame , " left " , anchorTo , " left " , xPadding , 0 )
else
PixelUtil.SetPoint ( iconFrame , " left " , anchorTo , " right " , xPadding , 0 )
end
elseif ( growDirection == 2 ) then --grow to left
if ( self.NextIcon == 1 ) then
PixelUtil.SetPoint ( iconFrame , " right " , anchorTo , " right " , xPadding , 0 )
else
PixelUtil.SetPoint ( iconFrame , " right " , anchorTo , " left " , xPadding , 0 )
end
end
detailsFramework : SetFontColor ( iconFrame.CountdownText , self.options . text_color )
self.NextIcon = self.NextIcon + 1
return iconFrame
end ,
--adds only if not existing already in the cache
AddSpecificIcon = function ( self , identifierKey , spellId , borderColor , startTime , duration , forceTexture , descText , count , debuffType , caster , canStealOrPurge , spellName , isBuff )
if not identifierKey or identifierKey == " " then
return
end
if not self.AuraCache [ identifierKey ] then
local icon = self : SetIcon ( spellId , borderColor , startTime , duration , forceTexture , descText , count , debuffType , caster , canStealOrPurge , spellName , isBuff or false )
icon.identifierKey = identifierKey
self.AuraCache [ identifierKey ] = true
end
end ,
SetIcon = function ( self , spellId , borderColor , startTime , duration , forceTexture , descText , count , debuffType , caster , canStealOrPurge , spellName , isBuff , modRate )
local actualSpellName , _ , spellIcon = GetSpellInfo ( spellId )
if forceTexture then
spellIcon = forceTexture
end
spellName = spellName or actualSpellName or " unknown_aura "
modRate = modRate or 1
if ( spellIcon ) then
local iconFrame = self : GetIcon ( )
iconFrame.Texture : SetTexture ( spellIcon )
iconFrame.Texture : SetTexCoord ( unpack ( self.options . texcoord ) )
if ( borderColor ) then
iconFrame : SetBackdropBorderColor ( Plater : ParseColors ( borderColor ) )
else
iconFrame : SetBackdropBorderColor ( 0 , 0 , 0 , 0 )
end
if ( startTime ) then
CooldownFrame_Set ( iconFrame.Cooldown , startTime , duration , true , true , modRate )
if ( self.options . show_text ) then
iconFrame.CountdownText : Show ( )
local now = GetTime ( )
iconFrame.timeRemaining = ( startTime + duration - now ) / modRate
iconFrame.expirationTime = startTime + duration
local formattedTime = ( iconFrame.timeRemaining > 0 ) and self.options . decimal_timer and iconFrame.parentIconRow . FormatCooldownTimeDecimal ( iconFrame.timeRemaining ) or iconFrame.parentIconRow . FormatCooldownTime ( iconFrame.timeRemaining ) or " "
iconFrame.CountdownText : SetText ( formattedTime )
iconFrame.CountdownText : SetPoint ( self.options . text_anchor or " center " , iconFrame , self.options . text_rel_anchor or " center " , self.options . text_x_offset or 0 , self.options . text_y_offset or 0 )
detailsFramework : SetFontSize ( iconFrame.CountdownText , self.options . text_size )
detailsFramework : SetFontFace ( iconFrame.CountdownText , self.options . text_font )
detailsFramework : SetFontOutline ( iconFrame.CountdownText , self.options . text_outline )
if self.options . on_tick_cooldown_update then
iconFrame.lastUpdateCooldown = now
iconFrame : SetScript ( " OnUpdate " , self.OnIconTick )
else
iconFrame : SetScript ( " OnUpdate " , nil )
end
else
iconFrame : SetScript ( " OnUpdate " , nil )
iconFrame.CountdownText : Hide ( )
end
iconFrame.Cooldown : SetReverse ( self.options . cooldown_reverse )
iconFrame.Cooldown : SetDrawSwipe ( self.options . cooldown_swipe_enabled )
iconFrame.Cooldown : SetEdgeTexture ( self.options . cooldown_edge_texture )
iconFrame.Cooldown : SetHideCountdownNumbers ( self.options . surpress_blizzard_cd_timer )
else
iconFrame.timeRemaining = nil
iconFrame.expirationTime = nil
iconFrame : SetScript ( " OnUpdate " , nil )
iconFrame.CountdownText : Hide ( )
end
if ( descText and self.options . desc_text ) then
iconFrame.Desc : Show ( )
iconFrame.Desc : SetText ( descText.text )
iconFrame.Desc : SetTextColor ( detailsFramework : ParseColors ( descText.text_color or self.options . desc_text_color ) )
iconFrame.Desc : SetPoint ( self.options . desc_text_anchor or " bottom " , iconFrame , self.options . desc_text_rel_anchor or " top " , self.options . desc_text_x_offset or 0 , self.options . desc_text_y_offset or 2 )
detailsFramework : SetFontSize ( iconFrame.Desc , descText.text_size or self.options . desc_text_size )
detailsFramework : SetFontFace ( iconFrame.Desc , self.options . desc_text_font )
detailsFramework : SetFontOutline ( iconFrame.Desc , self.options . desc_text_outline )
else
iconFrame.Desc : Hide ( )
end
if ( count and count > 1 and self.options . stack_text ) then
iconFrame.StackText : Show ( )
iconFrame.StackText : SetText ( count )
iconFrame.StackText : SetTextColor ( detailsFramework : ParseColors ( self.options . desc_text_color ) )
iconFrame.StackText : SetPoint ( self.options . stack_text_anchor or " center " , iconFrame , self.options . stack_text_rel_anchor or " bottomright " , self.options . stack_text_x_offset or 0 , self.options . stack_text_y_offset or 0 )
detailsFramework : SetFontSize ( iconFrame.StackText , self.options . stack_text_size )
detailsFramework : SetFontFace ( iconFrame.StackText , self.options . stack_text_font )
detailsFramework : SetFontOutline ( iconFrame.StackText , self.options . stack_text_outline )
else
iconFrame.StackText : Hide ( )
end
PixelUtil.SetSize ( iconFrame , self.options . icon_width , self.options . icon_height )
iconFrame : Show ( )
--update the size of the frame
self : SetWidth ( ( self.options . left_padding * 2 ) + ( self.options . icon_padding * ( self.NextIcon - 2 ) ) + ( self.options . icon_width * ( self.NextIcon - 1 ) ) )
self : SetHeight ( self.options . icon_height + ( self.options . top_padding * 2 ) )
--make information available
iconFrame.spellId = spellId
iconFrame.startTime = startTime
iconFrame.duration = duration
iconFrame.count = count
iconFrame.debuffType = debuffType
iconFrame.caster = caster
iconFrame.canStealOrPurge = canStealOrPurge
iconFrame.isBuff = isBuff
iconFrame.spellName = spellName
iconFrame.identifierKey = nil -- only used for "specific" add/remove
--add the spell into the cache
self.AuraCache [ spellId or - 1 ] = true
self.AuraCache [ spellName ] = true
self.AuraCache . canStealOrPurge = self.AuraCache . canStealOrPurge or canStealOrPurge
self.AuraCache . hasEnrage = self.AuraCache . hasEnrage or debuffType == " " --yes, enrages are empty-string...
--show the frame
self : Show ( )
return iconFrame
end
end ,
OnIconTick = function ( self , deltaTime )
local now = GetTime ( )
if ( self.lastUpdateCooldown + 0.05 ) <= now then
self.timeRemaining = self.expirationTime - now
if self.timeRemaining > 0 then
if self.parentIconRow . options.decimal_timer then
self.CountdownText : SetText ( self.parentIconRow . FormatCooldownTimeDecimal ( self.timeRemaining ) )
else
self.CountdownText : SetText ( self.parentIconRow . FormatCooldownTime ( self.timeRemaining ) )
end
else
self.CountdownText : SetText ( " " )
end
self.lastUpdateCooldown = now
end
end ,
FormatCooldownTime = function ( formattedTime )
if ( formattedTime >= 3600 ) then
formattedTime = floor ( formattedTime / 3600 ) .. " h "
elseif ( formattedTime >= 60 ) then
formattedTime = floor ( formattedTime / 60 ) .. " m "
else
formattedTime = floor ( formattedTime )
end
return formattedTime
end ,
FormatCooldownTimeDecimal = function ( formattedTime )
if formattedTime < 10 then
return ( " %.1f " ) : format ( formattedTime )
elseif formattedTime < 60 then
return ( " %d " ) : format ( formattedTime )
elseif formattedTime < 3600 then
return ( " %d:%02d " ) : format ( formattedTime / 60 % 60 , formattedTime % 60 )
elseif formattedTime < 86400 then
return ( " %dh %02dm " ) : format ( formattedTime / ( 3600 ) , formattedTime / 60 % 60 )
else
return ( " %dd %02dh " ) : format ( formattedTime / 86400 , ( formattedTime / 3600 ) - ( floor ( formattedTime / 86400 ) * 24 ) )
end
end ,
RemoveSpecificIcon = function ( self , identifierKey )
if not identifierKey or identifierKey == " " then
return
end
table.wipe ( self.AuraCache )
local iconPool = self.IconPool
local countStillShown = 0
for i = 1 , self.NextIcon - 1 do
local iconFrame = iconPool [ i ]
if iconFrame.identifierKey and iconFrame.identifierKey == identifierKey then
iconFrame : Hide ( )
iconFrame : ClearAllPoints ( )
iconFrame.identifierKey = nil
else
self.AuraCache [ iconFrame.spellId ] = true
self.AuraCache [ iconFrame.spellName ] = true
self.AuraCache . canStealOrPurge = self.AuraCache . canStealOrPurge or iconFrame.canStealOrPurge
self.AuraCache . hasEnrage = self.AuraCache . hasEnrage or iconFrame.debuffType == " " --yes, enrages are empty-string...
countStillShown = countStillShown + 1
end
end
self : AlignAuraIcons ( )
end ,
ClearIcons = function ( self , resetBuffs , resetDebuffs )
resetBuffs = resetBuffs ~= false
resetDebuffs = resetDebuffs ~= false
table.wipe ( self.AuraCache )
local iconPool = self.IconPool
for i = 1 , self.NextIcon - 1 do
local iconFrame = iconPool [ i ]
if iconFrame.isBuff == nil then
iconFrame : Hide ( )
iconFrame : ClearAllPoints ( )
elseif resetBuffs and iconFrame.isBuff then
iconFrame : Hide ( )
iconFrame : ClearAllPoints ( )
elseif resetDebuffs and not iconFrame.isBuff then
iconFrame : Hide ( )
iconFrame : ClearAllPoints ( )
else
self.AuraCache [ iconFrame.spellId ] = true
self.AuraCache [ iconFrame.spellName ] = true
self.AuraCache . canStealOrPurge = self.AuraCache . canStealOrPurge or iconFrame.canStealOrPurge
self.AuraCache . hasEnrage = self.AuraCache . hasEnrage or iconFrame.debuffType == " " --yes, enrages are empty-string...
end
end
self : AlignAuraIcons ( )
end ,
AlignAuraIcons = function ( self )
local iconPool = self.IconPool
local iconAmount = # iconPool
local countStillShown = 0
table.sort ( iconPool , function ( i1 , i2 ) return i1 : IsShown ( ) and not i2 : IsShown ( ) end )
if iconAmount == 0 then
self : Hide ( )
else
-- re-anchor not hidden
for i = 1 , iconAmount do
local iconFrame = iconPool [ i ]
local anchor = self.options . anchor
local anchorTo = i == 1 and self or self.IconPool [ i - 1 ]
local xPadding = i == 1 and self.options . left_padding or self.options . icon_padding or 1
local growDirection = self.options . grow_direction
countStillShown = countStillShown + ( iconFrame : IsShown ( ) and 1 or 0 )
iconFrame : ClearAllPoints ( )
if ( growDirection == 1 ) then --grow to right
if ( i == 1 ) then
PixelUtil.SetPoint ( iconFrame , " left " , anchorTo , " left " , xPadding , 0 )
else
PixelUtil.SetPoint ( iconFrame , " left " , anchorTo , " right " , xPadding , 0 )
end
elseif ( growDirection == 2 ) then --grow to left
if ( i == 1 ) then
PixelUtil.SetPoint ( iconFrame , " right " , anchorTo , " right " , xPadding , 0 )
else
PixelUtil.SetPoint ( iconFrame , " right " , anchorTo , " left " , xPadding , 0 )
end
end
end
end
self.NextIcon = countStillShown + 1
end ,
GetIconGrowDirection = function ( self )
local side = self.options . anchor.side
if ( side == 1 ) then
return 1
elseif ( side == 2 ) then
return 2
elseif ( side == 3 ) then
return 1
elseif ( side == 4 ) then
return 1
elseif ( side == 5 ) then
return 2
elseif ( side == 6 ) then
return 1
elseif ( side == 7 ) then
return 2
elseif ( side == 8 ) then
return 1
elseif ( side == 9 ) then
return 1
elseif ( side == 10 ) then
return 1
elseif ( side == 11 ) then
return 2
elseif ( side == 12 ) then
return 1
elseif ( side == 13 ) then
return 1
end
end ,
OnOptionChanged = function ( self , optionName )
self : SetBackdropColor ( unpack ( self.options . backdrop_color ) )
self : SetBackdropBorderColor ( unpack ( self.options . backdrop_border_color ) )
end ,
}
local default_icon_row_options = {
icon_width = 20 ,
icon_height = 20 ,
texcoord = { .1 , .9 , .1 , .9 } ,
show_text = true ,
text_color = { 1 , 1 , 1 , 1 } ,
text_size = 12 ,
text_font = " Arial Narrow " ,
text_outline = " NONE " ,
text_anchor = " center " ,
text_rel_anchor = " center " ,
text_x_offset = 0 ,
text_y_offset = 0 ,
desc_text = true ,
desc_text_color = { 1 , 1 , 1 , 1 } ,
desc_text_size = 7 ,
desc_text_font = " Arial Narrow " ,
desc_text_outline = " NONE " ,
desc_text_anchor = " bottom " ,
desc_text_rel_anchor = " top " ,
desc_text_x_offset = 0 ,
desc_text_y_offset = 2 ,
stack_text = true ,
stack_text_color = { 1 , 1 , 1 , 1 } ,
stack_text_size = 10 ,
stack_text_font = " Arial Narrow " ,
stack_text_outline = " NONE " ,
stack_text_anchor = " center " ,
stack_text_rel_anchor = " bottomright " ,
stack_text_x_offset = 0 ,
stack_text_y_offset = 0 ,
left_padding = 1 , --distance between right and left
top_padding = 1 , --distance between top and bottom
icon_padding = 1 , --distance between each icon
backdrop = { } ,
backdrop_color = { 0 , 0 , 0 , 0.5 } ,
backdrop_border_color = { 0 , 0 , 0 , 1 } ,
anchor = { side = 6 , x = 2 , y = 0 } ,
grow_direction = 1 , --1 = to right 2 = to left
surpress_blizzard_cd_timer = false ,
surpress_tulla_omni_cc = false ,
on_tick_cooldown_update = true ,
decimal_timer = false ,
cooldown_reverse = false ,
cooldown_swipe_enabled = true ,
cooldown_edge_texture = " Interface \\ Cooldown \\ edge " ,
}
function detailsFramework : CreateIconRow ( parent , name , options )
local f = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
f.IconPool = { }
f.NextIcon = 1
f.AuraCache = { }
detailsFramework : Mixin ( f , detailsFramework.IconRowFunctions )
detailsFramework : Mixin ( f , detailsFramework.OptionsFunctions )
f : BuildOptionsTable ( default_icon_row_options , options )
f : SetSize ( f.options . icon_width , f.options . icon_height + ( f.options . top_padding * 2 ) )
f : SetBackdrop ( f.options . backdrop )
f : SetBackdropColor ( unpack ( f.options . backdrop_color ) )
f : SetBackdropBorderColor ( unpack ( f.options . backdrop_border_color ) )
return f
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--~header
--mixed functions
detailsFramework.HeaderFunctions = {
AddFrameToHeaderAlignment = function ( self , frame )
self.FramesToAlign = self.FramesToAlign or { }
tinsert ( self.FramesToAlign , frame )
end ,
--@self: an object like a line
--@headerFrame: the main header frame
--@anchor: which side the columnHeaders are attach
AlignWithHeader = function ( self , headerFrame , anchor )
local columnHeaderFrames = headerFrame.columnHeadersCreated
anchor = anchor or " topleft "
for i = 1 , # self.FramesToAlign do
local frame = self.FramesToAlign [ i ]
frame : ClearAllPoints ( )
local columnHeader = columnHeaderFrames [ i ]
local offset = 0
if ( columnHeader.columnAlign == " right " ) then
offset = columnHeader : GetWidth ( )
if ( frame : GetObjectType ( ) == " FontString " ) then
frame : SetJustifyH ( " right " )
end
end
frame : SetPoint ( columnHeader.columnAlign , self , anchor , columnHeader.XPosition + columnHeader.columnOffset + offset , 0 )
end
end ,
--@self: column header button
OnClick = function ( self , buttonClicked )
--get the header main frame
local headerFrame = self : GetParent ( )
--if this header does not have a clickable header, just ignore
if ( not headerFrame.columnSelected ) then
return
end
--get the latest column header selected
local previousColumnHeader = headerFrame.columnHeadersCreated [ headerFrame.columnSelected ]
previousColumnHeader.Arrow : Hide ( )
headerFrame : ResetColumnHeaderBackdrop ( previousColumnHeader )
headerFrame : SetBackdropColorForSelectedColumnHeader ( self )
if ( headerFrame.columnSelected == self.columnIndex ) then
self.order = self.order ~= " ASC " and " ASC " or " DESC "
end
headerFrame.columnOrder = self.order
--set the new column header selected
headerFrame.columnSelected = self.columnIndex
headerFrame : UpdateSortArrow ( self )
if ( headerFrame.options . header_click_callback ) then
--callback with the main header frame, column header, column index and column order as payload
local okay , errortext = pcall ( headerFrame.options . header_click_callback , headerFrame , self , self.columnIndex , self.order )
if ( not okay ) then
print ( " DF: Header onClick callback error: " , errortext )
end
end
end ,
}
detailsFramework.HeaderCoreFunctions = {
GetColumnWidth = function ( self , columnId )
return self.HeaderTable [ columnId ] . width
end ,
SetHeaderTable = function ( self , newTable )
self.columnHeadersCreated = self.columnHeadersCreated or { }
self.HeaderTable = newTable
self.NextHeader = 1
self.HeaderWidth = 0
self.HeaderHeight = 0
self : Refresh ( )
end ,
--return which header is current selected and the the order ASC DESC
GetSelectedColumn = function ( self )
return self.columnSelected , self.columnHeadersCreated [ self.columnSelected or 1 ] . order
end ,
--clean up and rebuild the header following the header options
--@self: main header frame
Refresh = function ( self )
--refresh background frame
self : SetBackdrop ( self.options . backdrop )
self : SetBackdropColor ( unpack ( self.options . backdrop_color ) )
self : SetBackdropBorderColor ( unpack ( self.options . backdrop_border_color ) )
--reset all header frames
for i = 1 , # self.columnHeadersCreated do
local columnHeader = self.columnHeadersCreated [ i ]
columnHeader.InUse = false
columnHeader : Hide ( )
end
local previousColumnHeader
local growDirection = string.lower ( self.options . grow_direction )
--update header frames
local headerSize = # self.HeaderTable
for i = 1 , headerSize do
--get the header button, a new one is created if it doesn't exists yet
local columnHeader = self : GetNextHeader ( )
self : UpdateColumnHeader ( columnHeader , i )
--grow direction
if ( not previousColumnHeader ) then
columnHeader : SetPoint ( " topleft " , self , " topleft " , 0 , 0 )
if ( growDirection == " right " ) then
if ( self.options . use_line_separators ) then
columnHeader.Separator : Show ( )
columnHeader.Separator : SetWidth ( self.options . line_separator_width )
columnHeader.Separator : SetColorTexture ( unpack ( self.options . line_separator_color ) )
columnHeader.Separator : ClearAllPoints ( )
if ( self.options . line_separator_gap_align ) then
columnHeader.Separator : SetPoint ( " topleft " , columnHeader , " topright " , 0 , 0 )
else
columnHeader.Separator : SetPoint ( " topright " , columnHeader , " topright " , 0 , 0 )
end
columnHeader.Separator : SetHeight ( self.options . line_separator_height )
end
end
else
if ( growDirection == " right " ) then
columnHeader : SetPoint ( " topleft " , previousColumnHeader , " topright " , self.options . padding , 0 )
if ( self.options . use_line_separators ) then
columnHeader.Separator : Show ( )
columnHeader.Separator : SetWidth ( self.options . line_separator_width )
columnHeader.Separator : SetColorTexture ( unpack ( self.options . line_separator_color ) )
columnHeader.Separator : ClearAllPoints ( )
if ( self.options . line_separator_gap_align ) then
columnHeader.Separator : SetPoint ( " topleft " , columnHeader , " topright " , 0 , 0 )
else
columnHeader.Separator : SetPoint ( " topleft " , columnHeader , " topright " , 0 , 0 )
end
columnHeader.Separator : SetHeight ( self.options . line_separator_height )
if ( headerSize == i ) then
columnHeader.Separator : Hide ( )
end
end
elseif ( growDirection == " left " ) then
columnHeader : SetPoint ( " topright " , previousColumnHeader , " topleft " , - self.options . padding , 0 )
elseif ( growDirection == " bottom " ) then
columnHeader : SetPoint ( " topleft " , previousColumnHeader , " bottomleft " , 0 , - self.options . padding )
elseif ( growDirection == " top " ) then
columnHeader : SetPoint ( " bottomleft " , previousColumnHeader , " topleft " , 0 , self.options . padding )
end
end
previousColumnHeader = columnHeader
end
self : SetSize ( self.HeaderWidth , self.HeaderHeight )
end ,
--@self: main header frame
UpdateSortArrow = function ( self , columnHeader , defaultShown , defaultOrder )
local options = self.options
local order = defaultOrder or columnHeader.order
local arrowIcon = columnHeader.Arrow
if ( type ( defaultShown ) ~= " boolean " ) then
arrowIcon : Show ( )
else
arrowIcon : SetShown ( defaultShown )
if ( defaultShown ) then
self : SetBackdropColorForSelectedColumnHeader ( columnHeader )
end
end
arrowIcon : SetAlpha ( options.arrow_alpha )
if ( order == " ASC " ) then
arrowIcon : SetTexture ( options.arrow_up_texture )
arrowIcon : SetTexCoord ( unpack ( options.arrow_up_texture_coords ) )
arrowIcon : SetSize ( unpack ( options.arrow_up_size ) )
elseif ( order == " DESC " ) then
arrowIcon : SetTexture ( options.arrow_down_texture )
arrowIcon : SetTexCoord ( unpack ( options.arrow_down_texture_coords ) )
arrowIcon : SetSize ( unpack ( options.arrow_down_size ) )
end
end ,
--@self: main header frame
UpdateColumnHeader = function ( self , columnHeader , headerIndex )
local headerData = self.HeaderTable [ headerIndex ]
if ( headerData.icon ) then
columnHeader.Icon : SetTexture ( headerData.icon )
if ( headerData.texcoord ) then
columnHeader.Icon : SetTexCoord ( unpack ( headerData.texcoord ) )
else
columnHeader.Icon : SetTexCoord ( 0 , 1 , 0 , 1 )
end
columnHeader.Icon : SetPoint ( " left " , columnHeader , " left " , self.options . padding , 0 )
columnHeader.Icon : Show ( )
end
if ( headerData.text ) then
columnHeader.Text : SetText ( headerData.text )
--text options
detailsFramework : SetFontColor ( columnHeader.Text , self.options . text_color )
detailsFramework : SetFontSize ( columnHeader.Text , self.options . text_size )
detailsFramework : SetFontOutline ( columnHeader.Text , self.options . text_shadow )
--point
if ( not headerData.icon ) then
columnHeader.Text : SetPoint ( " left " , columnHeader , " left " , self.options . padding , 0 )
else
columnHeader.Text : SetPoint ( " left " , columnHeader.Icon , " right " , self.options . padding , 0 )
end
columnHeader.Text : Show ( )
end
--column header index
columnHeader.columnIndex = headerIndex
if ( headerData.canSort ) then
columnHeader.order = " DESC "
columnHeader.Arrow : SetTexture ( self.options . arrow_up_texture )
else
columnHeader.Arrow : Hide ( )
end
if ( headerData.selected ) then
columnHeader.Arrow : Show ( )
columnHeader.Arrow : SetAlpha ( .843 )
self : UpdateSortArrow ( columnHeader , true , columnHeader.order )
self.columnSelected = headerIndex
else
if ( headerData.canSort ) then
self : UpdateSortArrow ( columnHeader , false , columnHeader.order )
end
end
--size
if ( headerData.width ) then
columnHeader : SetWidth ( headerData.width )
end
if ( headerData.height ) then
columnHeader : SetHeight ( headerData.height )
end
columnHeader.XPosition = self.HeaderWidth -- + self.options.padding
columnHeader.YPosition = self.HeaderHeight -- + self.options.padding
columnHeader.columnAlign = headerData.align or " left "
columnHeader.columnOffset = headerData.offset or 0
--add the header piece size to the total header size
local growDirection = string.lower ( self.options . grow_direction )
if ( growDirection == " right " or growDirection == " left " ) then
self.HeaderWidth = self.HeaderWidth + columnHeader : GetWidth ( ) + self.options . padding
self.HeaderHeight = math.max ( self.HeaderHeight , columnHeader : GetHeight ( ) )
elseif ( growDirection == " top " or growDirection == " bottom " ) then
self.HeaderWidth = math.max ( self.HeaderWidth , columnHeader : GetWidth ( ) )
self.HeaderHeight = self.HeaderHeight + columnHeader : GetHeight ( ) + self.options . padding
end
columnHeader : Show ( )
columnHeader.InUse = true
end ,
--reset column header backdrop
--@self: main header frame
ResetColumnHeaderBackdrop = function ( self , columnHeader )
columnHeader : SetBackdrop ( self.options . header_backdrop )
columnHeader : SetBackdropColor ( unpack ( self.options . header_backdrop_color ) )
columnHeader : SetBackdropBorderColor ( unpack ( self.options . header_backdrop_border_color ) )
end ,
--@self: main header frame
SetBackdropColorForSelectedColumnHeader = function ( self , columnHeader )
columnHeader : SetBackdropColor ( unpack ( self.options . header_backdrop_color_selected ) )
end ,
--clear the column header
--@self: main header frame
ClearColumnHeader = function ( self , columnHeader )
columnHeader : SetSize ( self.options . header_width , self.options . header_height )
self : ResetColumnHeaderBackdrop ( columnHeader )
columnHeader : ClearAllPoints ( )
columnHeader.Icon : SetTexture ( " " )
columnHeader.Icon : Hide ( )
columnHeader.Text : SetText ( " " )
columnHeader.Text : Hide ( )
end ,
--get the next column header, create one if doesn't exists
--@self: main header frame
GetNextHeader = function ( self )
local nextHeader = self.NextHeader
local columnHeader = self.columnHeadersCreated [ nextHeader ]
if ( not columnHeader ) then
--create a new column header
local newHeader = CreateFrame ( " button " , " $parentHeaderIndex " .. nextHeader , self , " BackdropTemplate " )
newHeader : SetScript ( " OnClick " , detailsFramework.HeaderFunctions . OnClick )
--header icon
detailsFramework : CreateImage ( newHeader , " " , self.options . header_height , self.options . header_height , " ARTWORK " , nil , " Icon " , " $parentIcon " )
--header separator
detailsFramework : CreateImage ( newHeader , " " , 1 , 1 , " ARTWORK " , nil , " Separator " , " $parentSeparator " )
--header name text
detailsFramework : CreateLabel ( newHeader , " " , self.options . text_size , self.options . text_color , " GameFontNormal " , " Text " , " $parentText " , " ARTWORK " )
--header selected and order icon
detailsFramework : CreateImage ( newHeader , self.options . arrow_up_texture , 12 , 12 , " ARTWORK " , nil , " Arrow " , " $parentArrow " )
newHeader.Arrow : SetPoint ( " right " , newHeader , " right " , - 1 , 0 )
newHeader.Separator : Hide ( )
newHeader.Arrow : Hide ( )
self : UpdateSortArrow ( newHeader , false , " DESC " )
tinsert ( self.columnHeadersCreated , newHeader )
columnHeader = newHeader
end
self : ClearColumnHeader ( columnHeader )
self.NextHeader = self.NextHeader + 1
return columnHeader
end ,
NextHeader = 1 ,
HeaderWidth = 0 ,
HeaderHeight = 0 ,
}
local default_header_options = {
backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
backdrop_color = { 0 , 0 , 0 , 0.2 } ,
backdrop_border_color = { 0.1 , 0.1 , 0.1 , .2 } ,
text_color = { 1 , 1 , 1 , 1 } ,
text_size = 10 ,
text_shadow = false ,
grow_direction = " RIGHT " ,
padding = 2 ,
--each piece of the header
header_backdrop = { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
header_backdrop_color = { 0 , 0 , 0 , 0.5 } ,
header_backdrop_color_selected = { 0.3 , 0.3 , 0.3 , 0.5 } ,
header_backdrop_border_color = { 0 , 0 , 0 , 0 } ,
header_width = 120 ,
header_height = 20 ,
arrow_up_texture = [[Interface\Buttons\Arrow-Up-Down]] ,
arrow_up_texture_coords = { 0 , 1 , 6 / 16 , 1 } ,
arrow_up_size = { 12 , 11 } ,
arrow_down_texture = [[Interface\Buttons\Arrow-Down-Down]] ,
arrow_down_texture_coords = { 0 , 1 , 0 , 11 / 16 } ,
arrow_down_size = { 12 , 11 } ,
arrow_alpha = 0.659 ,
use_line_separators = false ,
line_separator_color = { .1 , .1 , .1 , .6 } ,
line_separator_width = 1 ,
line_separator_height = 200 ,
line_separator_gap_align = false ,
}
function detailsFramework : CreateHeader ( parent , headerTable , options , frameName )
local newHeader = CreateFrame ( " frame " , frameName or " $parentHeaderLine " , parent , " BackdropTemplate " )
detailsFramework : Mixin ( newHeader , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( newHeader , detailsFramework.HeaderCoreFunctions )
newHeader : BuildOptionsTable ( default_header_options , options )
newHeader : SetBackdrop ( newHeader.options . backdrop )
newHeader : SetBackdropColor ( unpack ( newHeader.options . backdrop_color ) )
newHeader : SetBackdropBorderColor ( unpack ( newHeader.options . backdrop_border_color ) )
newHeader : SetHeaderTable ( headerTable )
return newHeader
end
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--radio group
local default_radiogroup_options = {
width = 1 ,
height = 1 ,
backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
backdrop_color = { 0 , 0 , 0 , 0.2 } ,
backdrop_border_color = { 0.1 , 0.1 , 0.1 , .2 } ,
is_radio = false ,
}
detailsFramework.RadioGroupCoreFunctions = {
Disable = function ( self )
local frameList = self : GetAllCheckboxes ( )
for _ , checkbox in ipairs ( frameList ) do
checkbox = checkbox.GetCapsule and checkbox : GetCapsule ( ) or checkbox
checkbox : Disable ( )
end
end ,
Enable = function ( self )
local frameList = self : GetAllCheckboxes ( )
for _ , checkbox in ipairs ( frameList ) do
checkbox = checkbox.GetCapsule and checkbox : GetCapsule ( ) or checkbox
checkbox : Enable ( )
end
end ,
DeselectAll = function ( self )
local frameList = self : GetAllCheckboxes ( )
for _ , checkbox in ipairs ( frameList ) do
checkbox = checkbox.GetCapsule and checkbox : GetCapsule ( ) or checkbox
checkbox : SetValue ( false )
end
end ,
FadeIn = function ( self )
local frameList = self : GetAllCheckboxes ( )
for _ , checkbox in ipairs ( frameList ) do
checkbox : SetAlpha ( 1 )
end
end ,
FadeOut = function ( self )
local frameList = self : GetAllCheckboxes ( )
for _ , checkbox in ipairs ( frameList ) do
checkbox : SetAlpha ( .7 )
end
end ,
SetFadeState = function ( self , state )
if ( state ) then
self : FadeIn ( )
else
self : FadeOut ( )
end
end ,
GetAllCheckboxes = function ( self )
return { self : GetChildren ( ) }
end ,
GetCheckbox = function ( self , checkboxId )
local allCheckboxes = self : GetAllCheckboxes ( )
local checkbox = allCheckboxes [ checkboxId ]
if ( not checkbox ) then
checkbox = self : CreateCheckbox ( )
end
return checkbox
end ,
CreateCheckbox = function ( self )
local checkbox = detailsFramework : CreateSwitch ( self , function ( ) end , false , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , detailsFramework : GetTemplate ( " switch " , " OPTIONS_CHECKBOX_BRIGHT_TEMPLATE " ) )
checkbox : SetAsCheckBox ( )
checkbox.Icon = detailsFramework : CreateImage ( checkbox , " " , 16 , 16 )
checkbox.Label = detailsFramework : CreateLabel ( checkbox , " " )
return checkbox
end ,
ResetAllCheckboxes = function ( self )
local radioCheckboxes = self : GetAllCheckboxes ( )
for i = 1 , # radioCheckboxes do
local checkBox = radioCheckboxes [ i ]
checkBox : Hide ( )
end
end ,
--if the list of checkboxes are a radio group
RadioOnClick = function ( checkbox , fixedParam , value )
--turn off all checkboxes
checkbox : GetParent ( ) : DeselectAll ( )
--turn on the clicked checkbox
checkbox : SetValue ( true )
--callback
if ( checkbox._callback ) then
detailsFramework : QuickDispatch ( checkbox._callback , fixedParam , checkbox._optionid )
end
end ,
RefreshCheckbox = function ( self , checkbox , optionTable , optionId )
checkbox = checkbox.GetCapsule and checkbox : GetCapsule ( ) or checkbox
local setFunc = self.options . is_radio and self.RadioOnClick or optionTable.set
checkbox : SetSwitchFunction ( setFunc )
checkbox._callback = optionTable.callback
checkbox._set = self.options . is_radio and optionTable.callback or optionTable.set
checkbox._optionid = optionId
checkbox : SetFixedParameter ( optionTable.param or optionId )
local isChecked = type ( optionTable.get ) == " function " and detailsFramework : Dispatch ( optionTable.get ) or false
checkbox : SetValue ( isChecked )
checkbox.Label : SetText ( optionTable.name )
if ( optionTable.texture ) then
checkbox.Icon : SetTexture ( optionTable.texture )
checkbox.Icon : SetPoint ( " left " , checkbox , " right " , 2 , 0 )
checkbox.Label : SetPoint ( " left " , checkbox.Icon , " right " , 2 , 0 )
if ( optionTable.texcoord ) then
checkbox.Icon : SetTexCoord ( unpack ( optionTable.texcoord ) )
else
checkbox.Icon : SetTexCoord ( 0 , 1 , 0 , 1 )
end
else
checkbox.Icon : SetTexture ( " " )
checkbox.Label : SetPoint ( " left " , checkbox , " right " , 2 , 0 )
end
end ,
Refresh = function ( self )
self : ResetAllCheckboxes ( )
local radioOptions = self : GetOptions ( )
local radioCheckboxes = self : GetAllCheckboxes ( )
for optionId , optionsTable in ipairs ( radioOptions ) do
local checkbox = self : GetCheckbox ( optionId )
checkbox.OptionID = optionId
checkbox : Show ( )
self : RefreshCheckbox ( checkbox , optionsTable , optionId )
end
--sending false to automatically use the radio group children
self : ArrangeFrames ( false , self.AnchorOptions )
end ,
SetOptions = function ( self , radioOptions )
self.RadioOptionsTable = radioOptions
self : Refresh ( )
end ,
GetOptions = function ( self )
return self.RadioOptionsTable
end ,
}
--[=[
radionOptions : an index table with options for the radio group { name = " " , set = func ( self , param , value ) , param = value , get = func , texture = " " , texcoord = { } }
set function receives as self the checkbox , use : GetParent ( ) to get the radion group frame
if get function return nil or false the checkbox isn ' t checked
name : the name of the frame
options : override options for default_radiogroup_options table
anchorOptions : override options for default_framelayout_options table
--]=]
function detailsFramework : CreateCheckboxGroup ( parent , radioOptions , name , options , anchorOptions )
local f = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
detailsFramework : Mixin ( f , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( f , detailsFramework.RadioGroupCoreFunctions )
detailsFramework : Mixin ( f , detailsFramework.LayoutFrame )
f : BuildOptionsTable ( default_radiogroup_options , options )
f : SetSize ( f.options . width , f.options . height )
f : SetBackdrop ( f.options . backdrop )
f : SetBackdropColor ( unpack ( f.options . backdrop_color ) )
f : SetBackdropBorderColor ( unpack ( f.options . backdrop_border_color ) )
f.AnchorOptions = anchorOptions or { }
if ( f.options . title ) then
local titleLabel = detailsFramework : CreateLabel ( f , f.options . title , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
titleLabel : SetPoint ( " bottomleft " , f , " topleft " , 0 , 2 )
f.Title = titleLabel
end
f : SetOptions ( radioOptions )
return f
end
function detailsFramework : CreateRadionGroup ( parent , radioOptions , name , options , anchorOptions ) --alias for miss spelled old function
return detailsFramework : CreateRadioGroup ( parent , radioOptions , name , options , anchorOptions )
end
function detailsFramework : CreateRadioGroup ( parent , radioOptions , name , options , anchorOptions )
options = options or { }
options.is_radio = true
return detailsFramework : CreateCheckboxGroup ( parent , radioOptions , name , options , anchorOptions )
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--load conditions panel
--this is the table prototype to hold load conditions settings
local default_load_conditions = {
class = { } ,
spec = { } ,
race = { } ,
talent = { } ,
pvptalent = { } ,
group = { } ,
role = { } ,
affix = { } ,
encounter_ids = { } ,
map_ids = { } ,
}
local default_load_conditions_frame_options = {
title = " Details! Framework: Load Conditions " ,
name = " Object " ,
}
function detailsFramework : CreateLoadFilterParser ( callback )
local f = CreateFrame ( " frame " )
f : RegisterEvent ( " PLAYER_ENTERING_WORLD " )
if IS_WOW_PROJECT_MAINLINE then
f : RegisterEvent ( " PLAYER_SPECIALIZATION_CHANGED " )
f : RegisterEvent ( " PLAYER_TALENT_UPDATE " )
end
f : RegisterEvent ( " PLAYER_ROLES_ASSIGNED " )
f : RegisterEvent ( " ZONE_CHANGED_NEW_AREA " )
if IS_WOW_PROJECT_MAINLINE then
f : RegisterEvent ( " CHALLENGE_MODE_START " )
end
f : RegisterEvent ( " ENCOUNTER_START " )
f : RegisterEvent ( " PLAYER_REGEN_ENABLED " )
f : SetScript ( " OnEvent " , function ( self , event , ... )
if ( event == " ENCOUNTER_START " ) then
local encounterID = ...
f.EncounterIDCached = encounterID
elseif ( event == " ENCOUNTER_END " ) then
f.EncounterIDCached = nil
elseif ( event == " PLAYER_REGEN_ENABLED " ) then
--f.EncounterIDCached = nil
--when the player dies during an encounter, the game is triggering regen enabled
elseif ( event == " PLAYER_SPECIALIZATION_CHANGED " ) then
if ( DetailsFrameworkLoadConditionsPanel and DetailsFrameworkLoadConditionsPanel : IsShown ( ) ) then
DetailsFrameworkLoadConditionsPanel : Refresh ( )
end
local unit = ...
if ( not unit or not UnitIsUnit ( " player " , unit ) ) then
return
end
elseif ( event == " PLAYER_ROLES_ASSIGNED " ) then
local assignedRole = UnitGroupRolesAssigned ( " player " )
if ( assignedRole == " NONE " ) then
local spec = DetailsFramework.GetSpecialization ( )
if ( spec ) then
assignedRole = DetailsFramework.GetSpecializationRole ( spec )
end
end
if ( detailsFramework.CurrentPlayerRole == assignedRole ) then
return
end
detailsFramework.CurrentPlayerRole = assignedRole
end
--print("Plater Script Update:", event, ...)
detailsFramework : QuickDispatch ( callback , f.EncounterIDCached )
end )
end
function detailsFramework : PassLoadFilters ( loadTable , encounterID )
--class
local passLoadClass
if ( loadTable.class . Enabled ) then
local _ , classFileName = UnitClass ( " player " )
if ( not loadTable.class [ classFileName ] ) then
return false
else
passLoadClass = true
end
end
--spec
if ( IS_WOW_PROJECT_MAINLINE and loadTable.spec . Enabled ) then
local canCheckTalents = true
if ( passLoadClass ) then
--if is allowed to load on this class, check if the talents isn't from another class
local _ , classFileName = UnitClass ( " player " )
local specsForThisClass = detailsFramework : GetClassSpecIDs ( classFileName )
canCheckTalents = false
for _ , specID in ipairs ( specsForThisClass ) do
if ( loadTable.spec [ specID ] or loadTable.spec [ specID .. " " ] ) then
--theres a talent for this class
canCheckTalents = true
break
end
end
end
if ( canCheckTalents ) then
local specIndex = DetailsFramework.GetSpecialization ( )
if ( specIndex ) then
local specID = DetailsFramework.GetSpecializationInfo ( specIndex )
if not specID or ( not loadTable.spec [ specID ] and not loadTable.spec [ specID .. " " ] ) then
return false
end
else
return false
end
end
end
--race
if ( loadTable.race . Enabled ) then
local raceName , raceFileName , raceID = UnitRace ( " player " )
if ( not loadTable.race [ raceFileName ] ) then
return false
end
end
--talents
if ( IS_WOW_PROJECT_MAINLINE and loadTable.talent . Enabled ) then
local talentsInUse = detailsFramework : GetCharacterTalents ( false , true )
local hasTalent
for talentID , _ in pairs ( talentsInUse ) do
if talentID and ( loadTable.talent [ talentID ] or loadTable.talent [ talentID .. " " ] ) then
hasTalent = true
break
end
end
if ( not hasTalent ) then
return false
end
end
--pvptalent
if ( IS_WOW_PROJECT_MAINLINE and loadTable.pvptalent . Enabled ) then
local talentsInUse = detailsFramework : GetCharacterPvPTalents ( false , true )
local hasTalent
for talentID , _ in pairs ( talentsInUse ) do
if talentID and ( loadTable.pvptalent [ talentID ] or loadTable.pvptalent [ talentID .. " " ] ) then
hasTalent = true
break
end
end
if ( not hasTalent ) then
return false
end
end
--group
if ( loadTable.group . Enabled ) then
local _ , zoneType = GetInstanceInfo ( )
if ( not loadTable.group [ zoneType ] ) then
return
end
end
--role
if ( loadTable.role . Enabled ) then
local assignedRole = UnitGroupRolesAssigned ( " player " )
if ( assignedRole == " NONE " ) then
local spec = DetailsFramework.GetSpecialization ( )
if ( spec ) then
assignedRole = DetailsFramework.GetSpecializationRole ( spec )
end
end
if ( not loadTable.role [ assignedRole ] ) then
return false
end
end
--affix
if ( IS_WOW_PROJECT_MAINLINE and loadTable.affix . Enabled ) then
local isInMythicDungeon = C_ChallengeMode.IsChallengeModeActive ( )
if ( not isInMythicDungeon ) then
return false
end
local level , affixes , wasEnergized = C_ChallengeMode.GetActiveKeystoneInfo ( )
local hasAffix = false
for _ , affixID in ipairs ( affixes ) do
if affixID and ( loadTable.affix [ affixID ] or loadTable.affix [ affixID .. " " ] ) then
hasAffix = true
break
end
end
if ( not hasAffix ) then
return false
end
end
--encounter id
if ( loadTable.encounter_ids . Enabled ) then
if ( not encounterID ) then
return
end
local hasEncounter
for _ , ID in pairs ( loadTable.encounter_ids ) do
if ( ID == encounterID ) then
hasEncounter = true
break
end
if ( not hasEncounter ) then
return false
end
end
end
--map id
if ( loadTable.map_ids . Enabled ) then
local _ , _ , _ , _ , _ , _ , _ , zoneMapID = GetInstanceInfo ( )
local uiMapID = C_Map.GetBestMapForUnit ( " player " )
local hasMapID
for _ , ID in pairs ( loadTable.map_ids ) do
if ( ID == zoneMapID or ID == uiMapID ) then
hasMapID = true
break
end
if ( not hasMapID ) then
return false
end
end
end
return true
end
--this func will deploy the default values from the prototype into the config table
function detailsFramework : UpdateLoadConditionsTable ( configTable )
configTable = configTable or { }
detailsFramework.table . deploy ( configTable , default_load_conditions )
return configTable
end
--/run Plater.OpenOptionsPanel()PlaterOptionsPanelContainer:SelectIndex (Plater, 14)
function detailsFramework : OpenLoadConditionsPanel ( optionsTable , callback , frameOptions )
frameOptions = frameOptions or { }
detailsFramework.table . deploy ( frameOptions , default_load_conditions_frame_options )
detailsFramework : UpdateLoadConditionsTable ( optionsTable )
if ( not DetailsFrameworkLoadConditionsPanel ) then
local loadConditionsFrame = detailsFramework : CreateSimplePanel ( UIParent , 970 , 505 , " Load Conditions " , " DetailsFrameworkLoadConditionsPanel " )
loadConditionsFrame : SetBackdropColor ( 0 , 0 , 0 , 1 )
loadConditionsFrame.AllRadioGroups = { }
loadConditionsFrame.AllTextEntries = { }
loadConditionsFrame.OptionsTable = optionsTable
detailsFramework : ApplyStandardBackdrop ( loadConditionsFrame , false , 1.1 )
local xStartAt = 10
local x2StartAt = 500
local anchorPositions = {
class = { xStartAt , - 70 } ,
spec = { xStartAt , - 170 } ,
race = { xStartAt , - 210 } ,
role = { xStartAt , - 310 } ,
talent = { xStartAt , - 350 } ,
pvptalent = { x2StartAt , - 70 } ,
group = { x2StartAt , - 210 } ,
affix = { x2StartAt , - 270 } ,
encounter_ids = { x2StartAt , - 420 } ,
map_ids = { x2StartAt , - 460 } ,
}
local editingLabel = detailsFramework : CreateLabel ( loadConditionsFrame , " Load Conditions For: " )
local editingWhatLabel = detailsFramework : CreateLabel ( loadConditionsFrame , " " )
editingLabel : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , 10 , - 35 )
editingWhatLabel : SetPoint ( " left " , editingLabel , " right " , 2 , 0 )
--this label store the name of what is being edited
loadConditionsFrame.EditingLabel = editingWhatLabel
--when the user click on an option, run the callback
loadConditionsFrame.RunCallback = function ( )
detailsFramework : Dispatch ( loadConditionsFrame.CallbackFunc )
end
--when the user click on an option or when the panel is opened
--check if there's an option enabled and fadein all options, fadeout otherwise
loadConditionsFrame.OnRadioStateChanged = function ( radioGroup , subConfigTable )
subConfigTable.Enabled = nil
subConfigTable.Enabled = next ( subConfigTable ) and true or nil
radioGroup : SetFadeState ( subConfigTable.Enabled )
end
--create the radio group for character class
loadConditionsFrame.OnRadioCheckboxClick = function ( self , key , value )
--hierarchy: DBKey ["class"] key ["HUNTER"] value TRUE
local DBKey = self : GetParent ( ) . DBKey
loadConditionsFrame.OptionsTable [ DBKey ] [ key and key .. " " ] = value and true or nil
if not value then -- cleanup "number" type values
loadConditionsFrame.OptionsTable [ DBKey ] [ key ] = nil
end
loadConditionsFrame.OnRadioStateChanged ( self : GetParent ( ) , loadConditionsFrame.OptionsTable [ DBKey ] )
loadConditionsFrame.RunCallback ( )
end
--create the radio group for classes
local classes = { }
for _ , classTable in pairs ( detailsFramework : GetClassList ( ) ) do
tinsert ( classes , {
name = classTable.Name ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = classTable.FileString ,
get = function ( ) return loadConditionsFrame.OptionsTable . class [ classTable.FileString ] end ,
texture = classTable.Texture ,
texcoord = classTable.TexCoord ,
} )
end
local classGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , classes , name , { width = 200 , height = 200 , title = " Character Class " } , { offset_x = 130 , amount_per_line = 3 } )
classGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.class [ 1 ] , anchorPositions.class [ 2 ] )
classGroup.DBKey = " class "
tinsert ( loadConditionsFrame.AllRadioGroups , classGroup )
--create the radio group for character spec
if IS_WOW_PROJECT_MAINLINE then
local specs = { }
for _ , specID in ipairs ( detailsFramework : GetClassSpecIDs ( select ( 2 , UnitClass ( " player " ) ) ) ) do
local specID , specName , specDescription , specIcon , specBackground , specRole , specClass = DetailsFramework.GetSpecializationInfoByID ( specID )
tinsert ( specs , {
name = specName ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = specID ,
get = function ( ) return loadConditionsFrame.OptionsTable . spec [ specID ] or loadConditionsFrame.OptionsTable . spec [ specID .. " " ] end ,
texture = specIcon ,
} )
end
local specGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , specs , name , { width = 200 , height = 200 , title = " Character Spec " } , { offset_x = 130 , amount_per_line = 4 } )
specGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.spec [ 1 ] , anchorPositions.spec [ 2 ] )
specGroup.DBKey = " spec "
tinsert ( loadConditionsFrame.AllRadioGroups , specGroup )
end
--create radio group for character races
local raceList = { }
for _ , raceTable in ipairs ( detailsFramework : GetCharacterRaceList ( ) ) do
tinsert ( raceList , {
name = raceTable.Name ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = raceTable.FileString ,
get = function ( ) return loadConditionsFrame.OptionsTable . race [ raceTable.FileString ] end ,
} )
end
local raceGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , raceList , name , { width = 200 , height = 200 , title = " Character Race " } )
raceGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.race [ 1 ] , anchorPositions.race [ 2 ] )
raceGroup.DBKey = " race "
tinsert ( loadConditionsFrame.AllRadioGroups , raceGroup )
--create radio group for talents
if IS_WOW_PROJECT_MAINLINE then
local talentList = { }
for _ , talentTable in ipairs ( detailsFramework : GetCharacterTalents ( ) ) do
tinsert ( talentList , {
name = talentTable.Name ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = talentTable.ID ,
get = function ( ) return loadConditionsFrame.OptionsTable . talent [ talentTable.ID ] or loadConditionsFrame.OptionsTable . talent [ talentTable.ID .. " " ] end ,
texture = talentTable.Texture ,
} )
end
local talentGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , talentList , name , { width = 200 , height = 200 , title = " Characer Talents " } , { offset_x = 150 , amount_per_line = 3 } )
talentGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.talent [ 1 ] , anchorPositions.talent [ 2 ] )
talentGroup.DBKey = " talent "
tinsert ( loadConditionsFrame.AllRadioGroups , talentGroup )
loadConditionsFrame.TalentGroup = talentGroup
do
--create a frame to show talents selected in other specs or characters
local otherTalents = CreateFrame ( " frame " , nil , loadConditionsFrame , " BackdropTemplate " )
otherTalents : SetSize ( 26 , 26 )
otherTalents : SetPoint ( " left " , talentGroup.Title . widget , " right " , 10 , - 2 )
otherTalents.Texture = detailsFramework : CreateImage ( otherTalents , [[Interface\BUTTONS\AdventureGuideMicrobuttonAlert]] , 24 , 24 )
otherTalents.Texture : SetAllPoints ( )
local removeTalent = function ( _ , _ , talentID )
loadConditionsFrame.OptionsTable . talent [ talentID ] = nil
GameCooltip2 : Hide ( )
loadConditionsFrame.OnRadioStateChanged ( talentGroup , loadConditionsFrame.OptionsTable [ talentGroup.DBKey ] )
loadConditionsFrame.CanShowTalentWarning ( )
end
local buildTalentMenu = function ( )
local playerTalents = detailsFramework : GetCharacterTalents ( )
local indexedTalents = { }
for _ , talentTable in ipairs ( playerTalents ) do
tinsert ( indexedTalents , talentTable.ID )
end
--talents selected to load
GameCooltip2 : AddLine ( " select a talent to remove it (added from a different spec or character) " , " " , 1 , " orange " , " orange " , 9 )
GameCooltip2 : AddLine ( " $div " , nil , nil , - 1 , - 1 )
for talentID , _ in pairs ( loadConditionsFrame.OptionsTable . talent ) do
if ( type ( talentID ) == " number " and not detailsFramework.table . find ( indexedTalents , talentID ) ) then
local talentID , name , texture , selected , available = GetTalentInfoByID ( talentID )
if ( name ) then
GameCooltip2 : AddLine ( name )
GameCooltip2 : AddIcon ( texture , 1 , 1 , 16 , 16 , .1 , .9 , .1 , .9 )
GameCooltip2 : AddMenu ( 1 , removeTalent , talentID )
end
end
end
end
otherTalents.CoolTip = {
Type = " menu " ,
BuildFunc = buildTalentMenu ,
OnEnterFunc = function ( self ) end ,
OnLeaveFunc = function ( self ) end ,
FixedValue = " none " ,
ShowSpeed = 0.05 ,
Options = function ( )
GameCooltip2 : SetOption ( " TextFont " , " Friz Quadrata TT " )
GameCooltip2 : SetOption ( " TextColor " , " orange " )
GameCooltip2 : SetOption ( " TextSize " , 12 )
GameCooltip2 : SetOption ( " FixedWidth " , 220 )
GameCooltip2 : SetOption ( " ButtonsYMod " , - 4 )
GameCooltip2 : SetOption ( " YSpacingMod " , - 4 )
GameCooltip2 : SetOption ( " IgnoreButtonAutoHeight " , true )
GameCooltip2 : SetColor ( 1 , 0.5 , 0.5 , 0.5 , 0 )
local preset2_backdrop = { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , edgeFile = [[Interface\Buttons\WHITE8X8]] , tile = true , edgeSize = 1 , tileSize = 16 , insets = { left = 0 , right = 0 , top = 0 , bottom = 0 } }
local gray_table = { 0.37 , 0.37 , 0.37 , 0.95 }
local black_table = { 0.2 , 0.2 , 0.2 , 1 }
GameCooltip2 : SetBackdrop ( 1 , preset2_backdrop , gray_table , black_table )
GameCooltip2 : SetBackdrop ( 2 , preset2_backdrop , gray_table , black_table )
end ,
}
GameCooltip2 : CoolTipInject ( otherTalents )
function loadConditionsFrame . CanShowTalentWarning ( )
local playerTalents = detailsFramework : GetCharacterTalents ( )
local indexedTalents = { }
for _ , talentTable in ipairs ( playerTalents ) do
tinsert ( indexedTalents , talentTable.ID )
end
for talentID , _ in pairs ( loadConditionsFrame.OptionsTable . talent ) do
if ( type ( talentID ) == " number " and not detailsFramework.table . find ( indexedTalents , talentID ) ) then
otherTalents : Show ( )
return
end
end
otherTalents : Hide ( )
end
end
end
--create radio group for pvp talents
if IS_WOW_PROJECT_MAINLINE then
local pvpTalentList = { }
for _ , talentTable in ipairs ( detailsFramework : GetCharacterPvPTalents ( ) ) do
tinsert ( pvpTalentList , {
name = talentTable.Name ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = talentTable.ID ,
get = function ( ) return loadConditionsFrame.OptionsTable . pvptalent [ talentTable.ID ] or loadConditionsFrame.OptionsTable . pvptalent [ talentTable.ID .. " " ] end ,
texture = talentTable.Texture ,
} )
end
local pvpTalentGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , pvpTalentList , name , { width = 200 , height = 200 , title = " Characer PvP Talents " } , { offset_x = 150 , amount_per_line = 3 } )
pvpTalentGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.pvptalent [ 1 ] , anchorPositions.pvptalent [ 2 ] )
pvpTalentGroup.DBKey = " pvptalent "
tinsert ( loadConditionsFrame.AllRadioGroups , pvpTalentGroup )
loadConditionsFrame.PvPTalentGroup = pvpTalentGroup
do
--create a frame to show talents selected in other specs or characters
local otherTalents = CreateFrame ( " frame " , nil , loadConditionsFrame , " BackdropTemplate " )
otherTalents : SetSize ( 26 , 26 )
otherTalents : SetPoint ( " left " , pvpTalentGroup.Title . widget , " right " , 10 , - 2 )
otherTalents.Texture = detailsFramework : CreateImage ( otherTalents , [[Interface\BUTTONS\AdventureGuideMicrobuttonAlert]] , 24 , 24 )
otherTalents.Texture : SetAllPoints ( )
local removeTalent = function ( _ , _ , talentID )
loadConditionsFrame.OptionsTable . pvptalent [ talentID ] = nil
GameCooltip2 : Hide ( )
loadConditionsFrame.OnRadioStateChanged ( pvpTalentGroup , loadConditionsFrame.OptionsTable [ pvpTalentGroup.DBKey ] )
loadConditionsFrame.CanShowPvPTalentWarning ( )
end
local buildTalentMenu = function ( )
local playerTalents = detailsFramework : GetCharacterPvPTalents ( )
local indexedTalents = { }
for _ , talentTable in ipairs ( playerTalents ) do
tinsert ( indexedTalents , talentTable.ID )
end
--talents selected to load
GameCooltip2 : AddLine ( " select a talent to remove it (added from a different spec or character) " , " " , 1 , " orange " , " orange " , 9 )
GameCooltip2 : AddLine ( " $div " , nil , nil , - 1 , - 1 )
for talentID , _ in pairs ( loadConditionsFrame.OptionsTable . pvptalent ) do
if ( type ( talentID ) == " number " and not detailsFramework.table . find ( indexedTalents , talentID ) ) then
local _ , name , texture = GetPvpTalentInfoByID ( talentID )
if ( name ) then
GameCooltip2 : AddLine ( name )
GameCooltip2 : AddIcon ( texture , 1 , 1 , 16 , 16 , .1 , .9 , .1 , .9 )
GameCooltip2 : AddMenu ( 1 , removeTalent , talentID )
end
end
end
end
otherTalents.CoolTip = {
Type = " menu " ,
BuildFunc = buildTalentMenu ,
OnEnterFunc = function ( self ) end ,
OnLeaveFunc = function ( self ) end ,
FixedValue = " none " ,
ShowSpeed = 0.05 ,
Options = function ( )
GameCooltip2 : SetOption ( " TextFont " , " Friz Quadrata TT " )
GameCooltip2 : SetOption ( " TextColor " , " orange " )
GameCooltip2 : SetOption ( " TextSize " , 12 )
GameCooltip2 : SetOption ( " FixedWidth " , 220 )
GameCooltip2 : SetOption ( " ButtonsYMod " , - 4 )
GameCooltip2 : SetOption ( " YSpacingMod " , - 4 )
GameCooltip2 : SetOption ( " IgnoreButtonAutoHeight " , true )
GameCooltip2 : SetColor ( 1 , 0.5 , 0.5 , 0.5 , 0 )
local preset2_backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeFile = [[Interface\Buttons\WHITE8X8]] , tile = true , edgeSize = 1 , tileSize = 16 , insets = { left = 0 , right = 0 , top = 0 , bottom = 0 } }
local gray_table = { 0.37 , 0.37 , 0.37 , 0.95 }
local black_table = { 0.2 , 0.2 , 0.2 , 1 }
GameCooltip2 : SetBackdrop ( 1 , preset2_backdrop , gray_table , black_table )
GameCooltip2 : SetBackdrop ( 2 , preset2_backdrop , gray_table , black_table )
end ,
}
GameCooltip2 : CoolTipInject ( otherTalents )
function loadConditionsFrame . CanShowPvPTalentWarning ( )
local playerTalents = detailsFramework : GetCharacterPvPTalents ( )
local indexedTalents = { }
for _ , talentTable in ipairs ( playerTalents ) do
tinsert ( indexedTalents , talentTable.ID )
end
for talentID , _ in pairs ( loadConditionsFrame.OptionsTable . pvptalent ) do
if ( type ( talentID ) == " number " and not detailsFramework.table . find ( indexedTalents , talentID ) ) then
otherTalents : Show ( )
return
end
end
otherTalents : Hide ( )
end
end
end
--create radio for group types
local groupTypes = { }
for _ , groupTable in ipairs ( detailsFramework : GetGroupTypes ( ) ) do
tinsert ( groupTypes , {
name = groupTable.Name ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = groupTable.ID ,
get = function ( ) return loadConditionsFrame.OptionsTable . group [ groupTable.ID ] or loadConditionsFrame.OptionsTable . group [ groupTable.ID .. " " ] end ,
} )
end
local groupTypesGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , groupTypes , name , { width = 200 , height = 200 , title = " Group Types " } )
groupTypesGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.group [ 1 ] , anchorPositions.group [ 2 ] )
groupTypesGroup.DBKey = " group "
tinsert ( loadConditionsFrame.AllRadioGroups , groupTypesGroup )
--create radio for character roles
local roleTypes = { }
for _ , roleTable in ipairs ( detailsFramework : GetRoleTypes ( ) ) do
tinsert ( roleTypes , {
name = roleTable.Texture .. " " .. roleTable.Name ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = roleTable.ID ,
get = function ( ) return loadConditionsFrame.OptionsTable . role [ roleTable.ID ] or loadConditionsFrame.OptionsTable . role [ roleTable.ID .. " " ] end ,
} )
end
local roleTypesGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , roleTypes , name , { width = 200 , height = 200 , title = " Role Types " } )
roleTypesGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.role [ 1 ] , anchorPositions.role [ 2 ] )
roleTypesGroup.DBKey = " role "
tinsert ( loadConditionsFrame.AllRadioGroups , roleTypesGroup )
--create radio group for mythic+ affixes
if IS_WOW_PROJECT_MAINLINE then
local affixes = { }
for i = 2 , 1000 do
local affixName , desc , texture = C_ChallengeMode.GetAffixInfo ( i )
if ( affixName ) then
tinsert ( affixes , {
name = affixName ,
set = loadConditionsFrame.OnRadioCheckboxClick ,
param = i ,
get = function ( ) return loadConditionsFrame.OptionsTable . affix [ i ] or loadConditionsFrame.OptionsTable . affix [ i .. " " ] end ,
texture = texture ,
} )
end
end
local affixTypesGroup = detailsFramework : CreateCheckboxGroup ( loadConditionsFrame , affixes , name , { width = 200 , height = 200 , title = " M+ Affixes " } )
affixTypesGroup : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.affix [ 1 ] , anchorPositions.affix [ 2 ] )
affixTypesGroup.DBKey = " affix "
tinsert ( loadConditionsFrame.AllRadioGroups , affixTypesGroup )
end
--text entries functions
local textEntryRefresh = function ( self )
local idList = loadConditionsFrame.OptionsTable [ self.DBKey ]
self : SetText ( " " )
for _ , id in pairs ( idList ) do
if tonumber ( id ) then
self : SetText ( self : GetText ( ) .. " " .. id )
end
end
self : SetText ( self : GetText ( ) : gsub ( " ^ " , " " ) )
end
local textEntryOnEnterPressed = function ( _ , self )
wipe ( loadConditionsFrame.OptionsTable [ self.DBKey ] )
local text = self : GetText ( )
for _ , ID in ipairs ( { strsplit ( " " , text ) } ) do
ID = detailsFramework : trim ( ID )
ID = tonumber ( ID )
if ( ID ) then
tinsert ( loadConditionsFrame.OptionsTable [ self.DBKey ] , ID )
loadConditionsFrame.OptionsTable [ self.DBKey ] . Enabled = true
end
end
end
--create the text entry to type the encounter ID
local encounterIDLabel = detailsFramework : CreateLabel ( loadConditionsFrame , " Encounter ID " , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
local encounterIDEditbox = detailsFramework : CreateTextEntry ( loadConditionsFrame , function ( ) end , 200 , 20 , " EncounterEditbox " , _ , _ , detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " ) )
encounterIDLabel : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.encounter_ids [ 1 ] , anchorPositions.encounter_ids [ 2 ] )
encounterIDEditbox : SetPoint ( " topleft " , encounterIDLabel , " bottomleft " , 0 , - 2 )
encounterIDEditbox.DBKey = " encounter_ids "
encounterIDEditbox.Refresh = textEntryRefresh
encounterIDEditbox.tooltip = " Enter multiple IDs separating with a whitespace. \n Example: 35 45 95 \n \n Sanctum of Domination: \n "
for _ , encounterTable in ipairs ( detailsFramework : GetCLEncounterIDs ( ) ) do
encounterIDEditbox.tooltip = encounterIDEditbox.tooltip .. encounterTable.ID .. " - " .. encounterTable.Name .. " \n "
end
encounterIDEditbox : SetHook ( " OnEnterPressed " , textEntryOnEnterPressed )
tinsert ( loadConditionsFrame.AllTextEntries , encounterIDEditbox )
--create the text entry for map ID
local mapIDLabel = detailsFramework : CreateLabel ( loadConditionsFrame , " Map ID " , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
local mapIDEditbox = detailsFramework : CreateTextEntry ( loadConditionsFrame , function ( ) end , 200 , 20 , " MapEditbox " , _ , _ , detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " ) )
mapIDLabel : SetPoint ( " topleft " , loadConditionsFrame , " topleft " , anchorPositions.map_ids [ 1 ] , anchorPositions.map_ids [ 2 ] )
mapIDEditbox : SetPoint ( " topleft " , mapIDLabel , " bottomleft " , 0 , - 2 )
mapIDEditbox.DBKey = " map_ids "
mapIDEditbox.Refresh = textEntryRefresh
mapIDEditbox.tooltip = " Enter multiple IDs separating with a whitespace \n Example: 35 45 95 "
mapIDEditbox : SetHook ( " OnEnterPressed " , textEntryOnEnterPressed )
tinsert ( loadConditionsFrame.AllTextEntries , mapIDEditbox )
function loadConditionsFrame . Refresh ( self )
if IS_WOW_PROJECT_MAINLINE then
--update the talents (might have changed if the player changed its specialization)
local talentList = { }
for _ , talentTable in ipairs ( detailsFramework : GetCharacterTalents ( ) ) do
tinsert ( talentList , {
name = talentTable.Name ,
set = DetailsFrameworkLoadConditionsPanel.OnRadioCheckboxClick ,
param = talentTable.ID ,
get = function ( ) return DetailsFrameworkLoadConditionsPanel.OptionsTable . talent [ talentTable.ID ] or DetailsFrameworkLoadConditionsPanel.OptionsTable . talent [ talentTable.ID .. " " ] end ,
texture = talentTable.Texture ,
} )
end
DetailsFrameworkLoadConditionsPanel.TalentGroup : SetOptions ( talentList )
end
if IS_WOW_PROJECT_MAINLINE then
local pvpTalentList = { }
for _ , talentTable in ipairs ( detailsFramework : GetCharacterPvPTalents ( ) ) do
tinsert ( pvpTalentList , {
name = talentTable.Name ,
set = DetailsFrameworkLoadConditionsPanel.OnRadioCheckboxClick ,
param = talentTable.ID ,
get = function ( ) return DetailsFrameworkLoadConditionsPanel.OptionsTable . pvptalent [ talentTable.ID ] or DetailsFrameworkLoadConditionsPanel.OptionsTable . pvptalent [ talentTable.ID .. " " ] end ,
texture = talentTable.Texture ,
} )
end
DetailsFrameworkLoadConditionsPanel.PvPTalentGroup : SetOptions ( pvpTalentList )
end
--refresh the radio group
for _ , radioGroup in ipairs ( DetailsFrameworkLoadConditionsPanel.AllRadioGroups ) do
radioGroup : Refresh ( )
DetailsFrameworkLoadConditionsPanel.OnRadioStateChanged ( radioGroup , DetailsFrameworkLoadConditionsPanel.OptionsTable [ radioGroup.DBKey ] )
end
--refresh text entries
for _ , textEntry in ipairs ( DetailsFrameworkLoadConditionsPanel.AllTextEntries ) do
textEntry : Refresh ( )
end
if IS_WOW_PROJECT_MAINLINE then
DetailsFrameworkLoadConditionsPanel.CanShowTalentWarning ( )
DetailsFrameworkLoadConditionsPanel.CanShowPvPTalentWarning ( )
end
end
end
--set the options table
DetailsFrameworkLoadConditionsPanel.OptionsTable = optionsTable
--set the callback func
DetailsFrameworkLoadConditionsPanel.CallbackFunc = callback
DetailsFrameworkLoadConditionsPanel.OptionsTable = optionsTable
--set title
DetailsFrameworkLoadConditionsPanel.EditingLabel : SetText ( frameOptions.name )
DetailsFrameworkLoadConditionsPanel.Title : SetText ( frameOptions.title )
--show the panel to the user
DetailsFrameworkLoadConditionsPanel : Show ( )
DetailsFrameworkLoadConditionsPanel : Refresh ( )
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--simple data scroll
detailsFramework.DataScrollFunctions = {
RefreshScroll = function ( self , data , offset , totalLines )
local filter = self.Filter
local currentData = { }
if ( type ( filter ) == " string " and filter ~= " " ) then
for i = 1 , # data do
for o = 1 , # data [ i ] do
if ( data [ i ] [ o ] : find ( filter ) ) then
tinsert ( currentData , data [ i ] )
break
end
end
end
else
currentData = data
end
if ( self.SortAlphabetical ) then
table.sort ( currentData , function ( t1 , t2 ) return t1 [ 1 ] < t2 [ 1 ] end )
end
--update the scroll
for i = 1 , totalLines do
local index = i + offset
local thisData = currentData [ index ]
if ( thisData ) then
local line = self : GetLine ( i )
line : Update ( index , thisData )
end
end
end ,
CreateLine = function ( self , index )
--create a new line
local line = CreateFrame ( " button " , " $parentLine " .. index , self , " BackdropTemplate " )
line.Update = self.options . update_line_func
--set its parameters
line : SetPoint ( " topleft " , self , " topleft " , 1 , - ( ( index - 1 ) * ( self.options . line_height + 1 ) ) - 1 )
line : SetSize ( self.options . width - 2 , self.options . line_height )
line : RegisterForClicks ( " LeftButtonDown " , " RightButtonDown " )
line : SetScript ( " OnEnter " , self.options . on_enter )
line : SetScript ( " OnLeave " , self.options . on_leave )
line : SetScript ( " OnClick " , self.options . on_click )
line : SetBackdrop ( self.options . backdrop )
line : SetBackdropColor ( unpack ( self.options . backdrop_color ) )
line : SetBackdropBorderColor ( unpack ( self.options . backdrop_border_color ) )
local title = detailsFramework : CreateLabel ( line , " " , detailsFramework : GetTemplate ( " font " , self.options . title_template ) )
local date = detailsFramework : CreateLabel ( line , " " , detailsFramework : GetTemplate ( " font " , self.options . title_template ) )
local text = detailsFramework : CreateLabel ( line , " " , detailsFramework : GetTemplate ( " font " , self.options . text_tempate ) )
title.textsize = 14
date.textsize = 14
text : SetSize ( self.options . width - 20 , self.options . line_height )
text : SetJustifyV ( " top " )
--setup anchors
if ( self.options . show_title ) then
title : SetPoint ( " topleft " , line , " topleft " , 2 , 0 )
date : SetPoint ( " topright " , line , " topright " , - 2 , 0 )
text : SetPoint ( " topleft " , title , " bottomleft " , 0 , - 4 )
else
text : SetPoint ( " topleft " , line , " topleft " , 2 , 0 )
end
line.Title = title
line.Date = date
line.Text = text
line.backdrop_color = self.options . backdrop_color or { .1 , .1 , .1 , .3 }
line.backdrop_color_highlight = self.options . backdrop_color_highlight or { .3 , .3 , .3 , .5 }
return line
end ,
LineOnEnter = function ( self )
self : SetBackdropColor ( unpack ( self.backdrop_color_highlight ) )
end ,
LineOnLeave = function ( self )
self : SetBackdropColor ( unpack ( self.backdrop_color ) )
end ,
OnClick = function ( self )
end ,
UpdateLine = function ( line , lineIndex , data )
local parent = line : GetParent ( )
if ( parent.options . show_title ) then
line.Title . text = data [ 2 ] or " "
line.Date . text = data [ 3 ] or " "
line.Text . text = data [ 4 ] or " "
else
line.Text . text = data [ 2 ] or " "
end
if ( line : GetParent ( ) . OnUpdateLineHook ) then
detailsFramework : CoreDispatch ( ( line : GetName ( ) or " ScrollBoxDataScrollUpdateLineHook " ) .. " :UpdateLineHook() " , line : GetParent ( ) . OnUpdateLineHook , line , lineIndex , data )
end
end ,
}
local default_datascroll_options = {
width = 400 ,
height = 700 ,
line_amount = 10 ,
line_height = 20 ,
show_title = true ,
backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
backdrop_color = { 0 , 0 , 0 , 0.2 } ,
backdrop_color_highlight = { .2 , .2 , .2 , 0.4 } ,
backdrop_border_color = { 0.1 , 0.1 , 0.1 , .2 } ,
title_template = " ORANGE_FONT_TEMPLATE " ,
text_tempate = " OPTIONS_FONT_TEMPLATE " ,
create_line_func = detailsFramework.DataScrollFunctions . CreateLine ,
update_line_func = detailsFramework.DataScrollFunctions . UpdateLine ,
refresh_func = detailsFramework.DataScrollFunctions . RefreshScroll ,
on_enter = detailsFramework.DataScrollFunctions . LineOnEnter ,
on_leave = detailsFramework.DataScrollFunctions . LineOnLeave ,
on_click = detailsFramework.DataScrollFunctions . OnClick ,
data = { } ,
}
--[=[
Create a scroll frame to show text in an organized way
Functions in the options table can be overritten to customize the layout
@ parent = the parent of the frame
@ name = the frame name to use in the CreateFrame call
@ options = options table to override default values from the table above
--]=]
function detailsFramework : CreateDataScrollFrame ( parent , name , options )
--call the mixin with a dummy table to built the default options before the frame creation
--this is done because CreateScrollBox needs parameters at creation time
local optionsTable = { }
detailsFramework.OptionsFunctions . BuildOptionsTable ( optionsTable , default_datascroll_options , options )
optionsTable = optionsTable.options
--scroll frame
local newScroll = detailsFramework : CreateScrollBox ( parent , name , optionsTable.refresh_func , optionsTable.data , optionsTable.width , optionsTable.height , optionsTable.line_amount , optionsTable.line_height )
detailsFramework : ReskinSlider ( newScroll )
detailsFramework : Mixin ( newScroll , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( newScroll , detailsFramework.LayoutFrame )
newScroll : BuildOptionsTable ( default_datascroll_options , options )
--create the scrollbox lines
for i = 1 , newScroll.options . line_amount do
newScroll : CreateLine ( newScroll.options . create_line_func )
end
newScroll : Refresh ( )
return newScroll
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--"WHAT's NEW" window
local default_newsframe_options = {
width = 400 ,
height = 700 ,
line_amount = 16 ,
line_height = 40 ,
backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
backdrop_color = { 0 , 0 , 0 , 0.2 } ,
backdrop_border_color = { 0.1 , 0.1 , 0.1 , .2 } ,
title = " What's New? " ,
show_title = true ,
}
detailsFramework.NewsFrameFunctions = {
}
--[=[
Get the amount of news that the player didn ' t see yet
@ newsTable = an indexed table of tables
@ lastNewsTime = last time the player opened the news window
--]=]
function detailsFramework : GetNumNews ( newsTable , lastNewsTime )
local now = time ( )
local nonReadNews = 0
for _ , news in ipairs ( newsTable ) do
if ( news [ 1 ] > lastNewsTime ) then
nonReadNews = nonReadNews + 1
end
end
return nonReadNews
end
--[=[
Creates a panel with a scroll to show texts organized in separated lines
@ parent = the parent of the frame
@ name = the frame name to use in the CreateFrame call
@ options = options table to override default values from the table above
@ newsTable = an indexed table of tables
@ db = ( optional ) an empty table from the addon database to store the position of the frame between game sessions
--]=]
function detailsFramework : CreateNewsFrame ( parent , name , options , newsTable , db )
local f = detailsFramework : CreateSimplePanel ( parent , 400 , 700 , options and options.title or default_newsframe_options.title , name , { UseScaleBar = db and true } , db )
f : SetFrameStrata ( " MEDIUM " )
detailsFramework : ApplyStandardBackdrop ( f )
detailsFramework : Mixin ( f , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( f , detailsFramework.LayoutFrame )
f : BuildOptionsTable ( default_newsframe_options , options )
f : SetSize ( f.options . width , f.options . height )
f : SetBackdrop ( f.options . backdrop )
f : SetBackdropColor ( unpack ( f.options . backdrop_color ) )
f : SetBackdropBorderColor ( unpack ( f.options . backdrop_border_color ) )
local scrollOptions = {
data = newsTable ,
width = f.options . width - 32 , --frame distance from walls and scroll bar space
height = f.options . height - 40 + ( not f.options . show_title and 20 or 0 ) ,
line_amount = f.options . line_amount ,
line_height = f.options . line_height ,
}
local newsScroll = detailsFramework : CreateDataScrollFrame ( f , " $parentScroll " , scrollOptions )
if ( not f.options . show_title ) then
f.TitleBar : Hide ( )
newsScroll : SetPoint ( " topleft " , f , " topleft " , 5 , - 10 )
else
newsScroll : SetPoint ( " topleft " , f , " topleft " , 5 , - 30 )
end
f.NewsScroll = newsScroll
return f
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--statusbar info
--[[
authorTable = {
{
authorName = " author name 1 " ,
link = " twitter.com/author1Handle " ,
}
}
] ]
function detailsFramework : BuildStatusbarAuthorInfo ( f , addonBy , authorsNameString )
local authorName = detailsFramework : CreateLabel ( f , " " .. ( addonBy or " An addon by " ) .. " |cFFFFFFFF " .. ( authorsNameString or " Terciob " ) .. " |r " )
authorName.textcolor = " silver "
local discordLabel = detailsFramework : CreateLabel ( f , " Discord: " )
discordLabel.textcolor = " silver "
local options_dropdown_template = detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local discordTextEntry = detailsFramework : CreateTextEntry ( f , function ( ) end , 200 , 18 , " DiscordTextBox " , _ , _ , options_dropdown_template )
discordTextEntry : SetText ( " https://discord.gg/AGSzAZX " )
discordTextEntry : SetFrameLevel ( 5000 )
authorName : SetPoint ( " left " , f , " left " , 2 , 0 )
discordLabel : SetPoint ( " left " , authorName , " right " , 20 , 0 )
discordTextEntry : SetPoint ( " left " , discordLabel , " right " , 2 , 0 )
--format
authorName : SetAlpha ( .6 )
discordLabel : SetAlpha ( .6 )
discordTextEntry : SetAlpha ( .6 )
discordTextEntry : SetBackdropBorderColor ( 1 , 1 , 1 , 0 )
discordTextEntry : SetHook ( " OnEditFocusGained " , function ( )
discordTextEntry : HighlightText ( )
end )
f.authorName = authorName
f.discordLabel = discordLabel
f.discordTextEntry = discordTextEntry
end
local statusbar_default_options = {
attach = " bottom " , --bottomleft from statusbar attach to bottomleft of the frame | other option is "top": topleft attach to bottomleft
}
function detailsFramework : CreateStatusBar ( f , options )
local statusBar = CreateFrame ( " frame " , nil , f , " BackdropTemplate " )
detailsFramework : Mixin ( statusBar , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( statusBar , detailsFramework.LayoutFrame )
statusBar : BuildOptionsTable ( statusbar_default_options , options )
if ( statusBar.options . attach == " bottom " ) then
statusBar : SetPoint ( " bottomleft " , f , " bottomleft " )
statusBar : SetPoint ( " bottomright " , f , " bottomright " )
else
statusBar : SetPoint ( " topleft " , f , " bottomleft " )
statusBar : SetPoint ( " topright " , f , " bottomright " )
end
statusBar : SetHeight ( 20 )
detailsFramework : ApplyStandardBackdrop ( statusBar )
statusBar : SetAlpha ( 0.8 )
return statusBar
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--statusbar mixin
--[=[
collection of functions to embed into a statusbar
statusBar : GetTexture ( )
statusBar : SetTexture ( texture )
statusBar : SetColor ( unparsed color )
statusBar : GetColor ( )
statusBar :
statusBar :
--]=]
detailsFramework.StatusBarFunctions = {
SetTexture = function ( self , texture , isTemporary )
self.barTexture : SetTexture ( texture )
if ( not isTemporary ) then
self.barTexture . currentTexture = texture
end
end ,
ResetTexture = function ( self )
self.barTexture : SetTexture ( self.barTexture . currentTexture )
end ,
GetTexture = function ( self )
return self.barTexture : GetTexture ( )
end ,
SetAtlas = function ( self , atlasName )
self.barTexture : SetAtlas ( atlasName )
end ,
GetAtlas = function ( self )
self.barTexture : GetAtlas ( )
end ,
SetTexCoord = function ( self , ... )
return self.barTexture : SetTexCoord ( ... )
end ,
GetTexCoord = function ( self )
return self.barTexture : GetTexCoord ( )
end ,
SetColor = function ( self , r , g , b , a )
r , g , b , a = detailsFramework : ParseColors ( r , g , b , a )
self : SetStatusBarColor ( r , g , b , a )
end ,
GetColor = function ( self )
return self : GetStatusBarColor ( )
end ,
SetMaskTexture = function ( self , ... )
if ( not self : HasTextureMask ( ) ) then
return
end
self.barTextureMask : SetTexture ( ... )
end ,
GetMaskTexture = function ( self )
if ( not self : HasTextureMask ( ) ) then
return
end
self.barTextureMask : GetTexture ( )
end ,
--SetMaskTexCoord = function(self, ...) --MaskTexture doesn't not support texcoord
-- if (not self:HasTextureMask()) then
-- return
-- end
-- self.barTextureMask:SetTexCoord(...)
--end,
--GetMaskTexCoord = function(self, ...)
-- if (not self:HasTextureMask()) then
-- return
-- end
-- self.barTextureMask:GetTexCoord()
--end,
SetMaskAtlas = function ( self , atlasName )
if ( not self : HasTextureMask ( ) ) then
return
end
self.barTextureMask : SetAtlas ( atlasName )
end ,
GetMaskAtlas = function ( self )
if ( not self : HasTextureMask ( ) ) then
return
end
self.barTextureMask : GetAtlas ( )
end ,
AddMaskTexture = function ( self , object )
if ( not self : HasTextureMask ( ) ) then
return
end
if ( object.GetObjectType and object : GetObjectType ( ) == " Texture " ) then
object : AddMaskTexture ( self.barTextureMask )
else
detailsFramework : Msg ( " Invalid 'Texture' to object:AddMaskTexture(Texture) " , debugstack ( ) )
end
end ,
CreateTextureMask = function ( self )
local barTexture = self : GetStatusBarTexture ( ) or self.barTexture
if ( not barTexture ) then
detailsFramework : Msg ( " Object doesn't not have a statubar texture, create one and object:SetStatusBarTexture(textureObject) " , debugstack ( ) )
return
end
if ( self.barTextureMask ) then
return self.barTextureMask
end
--statusbar texture mask
self.barTextureMask = self : CreateMaskTexture ( nil , " artwork " )
self.barTextureMask : SetAllPoints ( )
self.barTextureMask : SetTexture ( [[Interface\CHATFRAME\CHATFRAMEBACKGROUND]] )
--border texture
self.barBorderTextureForMask = self : CreateTexture ( nil , " artwork " , nil , 7 )
self.barBorderTextureForMask : SetAllPoints ( )
self.barBorderTextureForMask : Hide ( )
barTexture : AddMaskTexture ( self.barTextureMask )
return self.barTextureMask
end ,
HasTextureMask = function ( self )
if ( not self.barTextureMask ) then
detailsFramework : Msg ( " Object doesn't not have a texture mask, create one using object:CreateTextureMask() " , debugstack ( ) )
return false
end
return true
end ,
SetBorderTexture = function ( self , texture )
if ( not self : HasTextureMask ( ) ) then
return
end
texture = texture or " "
self.barBorderTextureForMask : SetTexture ( texture )
if ( texture == " " ) then
self.barBorderTextureForMask : Hide ( )
else
self.barBorderTextureForMask : Show ( )
end
end ,
GetBorderTexture = function ( self )
if ( not self : HasTextureMask ( ) ) then
return
end
return self.barBorderTextureForMask : GetTexture ( )
end ,
SetBorderColor = function ( self , r , g , b , a )
r , g , b , a = detailsFramework : ParseColors ( r , g , b , a )
if ( self.barBorderTextureForMask and self.barBorderTextureForMask : IsShown ( ) ) then
self.barBorderTextureForMask : SetVertexColor ( r , g , b , a )
--if there's a square border on the widget, remove its color
if ( self.border and self.border . UpdateSizes and self.border . SetVertexColor ) then
self.border : SetVertexColor ( 0 , 0 , 0 , 0 )
end
return
end
if ( self.border and self.border . UpdateSizes and self.border . SetVertexColor ) then
self.border : SetVertexColor ( r , g , b , a )
--adjust the mask border texture ask well in case the user set the mask color texture before setting a texture on it
if ( self.barBorderTextureForMask ) then
self.barBorderTextureForMask : SetVertexColor ( r , g , b , a )
end
return
end
end ,
GetBorderColor = function ( self )
if ( self.barBorderTextureForMask and self.barBorderTextureForMask : IsShown ( ) ) then
return self.barBorderTextureForMask : GetVertexColor ( )
end
if ( self.border and self.border . UpdateSizes and self.border . GetVertexColor ) then
return self.border : GetVertexColor ( )
end
end ,
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--health bar frame
--[=[
DF : CreateHealthBar ( parent , name , settingsOverride )
creates a health bar to show an unit health
@ parent = frame to pass for the CreateFrame function
@ name = absolute name of the frame , if omitted it uses the parent ' s name .. "HealthBar"
@ settingsOverride = table with keys and values to replace the defaults from the framework
methods :
healthbar : SetUnit ( unit )
healthBar : GetTexture ( )
healthBar : SetTexture ( texture )
--]=]
--debug performance isn't placed anywhere
--how to use debug performance: I don't remember
--Details:Dump (debugPerformance)
local debugPerformance = {
eventCall = { } ,
unitCall = { } ,
functionCall = { } ,
CPUUsageByFunction = { } ,
}
local function CalcPerformance ( type , data )
if ( type == " event " ) then
debugPerformance.eventCall [ data ] = ( debugPerformance.eventCall [ data ] or 0 ) + 1
elseif ( type == " unit " ) then
debugPerformance.unitCall [ data ] = ( debugPerformance.unitCall [ data ] or 0 ) + 1
elseif ( type == " call " ) then
debugPerformance.functionCall [ data ] = ( debugPerformance.functionCall [ data ] or 0 ) + 1
end
end
function DF_CalcCpuUsage ( name )
local cpu = debugPerformance.CPUUsageByFunction [ name ] or { usage = 0 , last = 0 , active = false }
debugPerformance.CPUUsageByFunction [ name ] = cpu
if ( cpu.active ) then
cpu.active = false
local diff = debugprofilestop ( ) - cpu.last
cpu.usage = cpu.usage + diff
else
cpu.active = true
cpu.last = debugprofilestop ( )
end
end
function UnitFrameStats ( )
for functionName , functionTable in pairs ( debugPerformance.CPUUsageByFunction ) do
debugPerformance.CPUUsageByFunction [ functionName ] = floor ( functionTable.usage )
end
for functionName , functionTable in pairs ( debugPerformance.CPUUsageByFunction ) do
debugPerformance.CPUUsageByFunction [ functionName ] = { usage = 0 , last = 0 , active = false }
end
end
--end of performance calcs
--healthBar meta prototype
local healthBarMetaPrototype = {
WidgetType = " healthBar " ,
dversion = detailsFramework.dversion ,
}
--check if there's a metaPrototype already existing
if ( _G [ detailsFramework.GlobalWidgetControlNames [ " healthBar " ] ] ) then
--get the already existing metaPrototype
local oldMetaPrototype = _G [ detailsFramework.GlobalWidgetControlNames [ " healthBar " ] ]
--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 ( healthBarMetaPrototype ) do
oldMetaPrototype [ funcName ] = healthBarMetaPrototype [ funcName ]
end
end
else
--first time loading the framework
_G [ detailsFramework.GlobalWidgetControlNames [ " healthBar " ] ] = healthBarMetaPrototype
end
local healthBarMetaFunctions = _G [ detailsFramework.GlobalWidgetControlNames [ " healthBar " ] ]
detailsFramework : Mixin ( healthBarMetaFunctions , detailsFramework.ScriptHookMixin )
--hook list
local defaultHooksForHealthBar = {
OnHide = { } ,
OnShow = { } ,
OnHealthChange = { } ,
OnHealthMaxChange = { } ,
}
--use the hook already existing
healthBarMetaFunctions.HookList = healthBarMetaFunctions.HookList or defaultHooksForHealthBar
--copy the non existing values from a new version to the already existing hook table
detailsFramework.table . deploy ( healthBarMetaFunctions.HookList , defaultHooksForHealthBar )
--Health Bar Meta Functions
--health bar settings
healthBarMetaFunctions.Settings = {
CanTick = false , --if true calls the method 'OnTick' every tick, the function needs to be overloaded, it receives self and deltaTime as parameters
ShowHealingPrediction = true , --when casting a healing pass, show the amount of health that spell will heal
ShowShields = true , --indicator of the amount of damage absortion the unit has
--appearance
BackgroundColor = detailsFramework : CreateColorTable ( .2 , .2 , .2 , .8 ) ,
Texture = [[Interface\RaidFrame\Raid-Bar-Hp-Fill]] ,
ShieldIndicatorTexture = [[Interface\RaidFrame\Shield-Fill]] ,
ShieldGlowTexture = [[Interface\RaidFrame\Shield-Overshield]] ,
ShieldGlowWidth = 16 ,
--default size
Width = 100 ,
Height = 20 ,
}
healthBarMetaFunctions.HealthBarEvents = {
{ " PLAYER_ENTERING_WORLD " } ,
{ " UNIT_HEALTH " , true } ,
{ " UNIT_MAXHEALTH " , true } ,
{ ( IS_WOW_PROJECT_NOT_MAINLINE ) and " UNIT_HEALTH_FREQUENT " , true } , -- this one is classic-only...
{ " UNIT_HEAL_PREDICTION " , true } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_ABSORB_AMOUNT_CHANGED " , true } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_HEAL_ABSORB_AMOUNT_CHANGED " , true } ,
}
--setup the castbar to be used by another unit
healthBarMetaFunctions.SetUnit = function ( self , unit , displayedUnit )
if ( self.unit ~= unit or self.displayedUnit ~= displayedUnit or unit == nil ) then
self.unit = unit
self.displayedUnit = displayedUnit or unit
--register events
if ( unit ) then
self.currentHealth = UnitHealth ( unit ) or 0
self.currentHealthMax = UnitHealthMax ( unit ) or 0
for _ , eventTable in ipairs ( self.HealthBarEvents ) do
local event = eventTable [ 1 ]
local isUnitEvent = eventTable [ 2 ]
if event then
if ( isUnitEvent ) then
self : RegisterUnitEvent ( event , self.displayedUnit , self.unit )
else
self : RegisterEvent ( event )
end
end
end
--check for settings and update some events
if ( not self.Settings . ShowHealingPrediction ) then
self : UnregisterEvent ( " UNIT_HEAL_PREDICTION " )
if IS_WOW_PROJECT_MAINLINE then
self : UnregisterEvent ( " UNIT_HEAL_ABSORB_AMOUNT_CHANGED " )
end
self.incomingHealIndicator : Hide ( )
self.healAbsorbIndicator : Hide ( )
end
if ( not self.Settings . ShowShields ) then
if IS_WOW_PROJECT_MAINLINE then
self : UnregisterEvent ( " UNIT_ABSORB_AMOUNT_CHANGED " )
end
self.shieldAbsorbIndicator : Hide ( )
self.shieldAbsorbGlow : Hide ( )
end
--set scripts
self : SetScript ( " OnEvent " , self.OnEvent )
if ( self.Settings . CanTick ) then
self : SetScript ( " OnUpdate " , self.OnTick )
end
self : PLAYER_ENTERING_WORLD ( self.unit , self.displayedUnit )
else
--remove all registered events
for _ , eventTable in ipairs ( self.HealthBarEvents ) do
local event = eventTable [ 1 ]
if event then
self : UnregisterEvent ( event )
end
end
--remove scripts
self : SetScript ( " OnEvent " , nil )
self : SetScript ( " OnUpdate " , nil )
self : Hide ( )
end
end
end
healthBarMetaFunctions.Initialize = function ( self )
PixelUtil.SetWidth ( self , self.Settings . Width , 1 )
PixelUtil.SetHeight ( self , self.Settings . Height , 1 )
self : SetTexture ( self.Settings . Texture )
self.background : SetAllPoints ( )
self.background : SetColorTexture ( self.Settings . BackgroundColor : GetColor ( ) )
--setpoint of these widgets are set inside the function that updates the incoming heal
self.incomingHealIndicator : SetTexture ( self : GetTexture ( ) )
self.healAbsorbIndicator : SetTexture ( self : GetTexture ( ) )
self.healAbsorbIndicator : SetVertexColor ( .1 , .8 , .8 )
self.shieldAbsorbIndicator : SetTexture ( self.Settings . ShieldIndicatorTexture , true , true )
self.shieldAbsorbGlow : SetWidth ( self.Settings . ShieldGlowWidth )
self.shieldAbsorbGlow : SetTexture ( self.Settings . ShieldGlowTexture )
self.shieldAbsorbGlow : SetBlendMode ( " ADD " )
self.shieldAbsorbGlow : SetPoint ( " topright " , self , " topright " , 8 , 0 )
self.shieldAbsorbGlow : SetPoint ( " bottomright " , self , " bottomright " , 8 , 0 )
self.shieldAbsorbGlow : Hide ( )
self : SetUnit ( nil )
end
--call every tick
healthBarMetaFunctions.OnTick = function ( self , deltaTime ) end --if overrided, set 'CanTick' to true on the settings table
--when an event happen for this unit, send it to the apropriate function
healthBarMetaFunctions.OnEvent = function ( self , event , ... )
local eventFunc = self [ event ]
if ( eventFunc ) then
--the function doesn't receive which event was, only 'self' and the parameters
eventFunc ( self , ... )
end
end
--when the unit max health is changed
healthBarMetaFunctions.UpdateMaxHealth = function ( self )
local maxHealth = UnitHealthMax ( self.displayedUnit )
self : SetMinMaxValues ( 0 , maxHealth )
self.currentHealthMax = maxHealth
self : RunHooksForWidget ( " OnHealthMaxChange " , self , self.displayedUnit )
end
healthBarMetaFunctions.UpdateHealth = function ( self )
-- update max health regardless to avoid weird wrong values on UpdateMaxHealth sometimes
-- local maxHealth = UnitHealthMax (self.displayedUnit)
-- self:SetMinMaxValues(0, maxHealth)
-- self.currentHealthMax = maxHealth
self.oldHealth = self.currentHealth
local health = UnitHealth ( self.displayedUnit )
self.currentHealth = health
PixelUtil.SetStatusBarValue ( self , health )
self : RunHooksForWidget ( " OnHealthChange " , self , self.displayedUnit )
end
--health and absorbs prediction
healthBarMetaFunctions.UpdateHealPrediction = function ( self )
local currentHealth = self.currentHealth
local currentHealthMax = self.currentHealthMax
local healthPercent = currentHealth / currentHealthMax
if ( not currentHealthMax or currentHealthMax <= 0 ) then
return
end
--order is: the health of the unit > damage absorb > heal absorb > incoming heal
local width = self : GetWidth ( )
if ( self.Settings . ShowHealingPrediction ) then
--incoming heal on the unit from all sources
local unitHealIncoming = self.displayedUnit and UnitGetIncomingHeals ( self.displayedUnit ) or 0
--heal absorbs
local unitHealAbsorb = IS_WOW_PROJECT_MAINLINE and self.displayedUnit and UnitGetTotalHealAbsorbs ( self.displayedUnit ) or 0
if ( unitHealIncoming > 0 ) then
--calculate what is the percent of health incoming based on the max health the player has
local incomingPercent = unitHealIncoming / currentHealthMax
self.incomingHealIndicator : Show ( )
self.incomingHealIndicator : SetWidth ( max ( 1 , min ( width * incomingPercent , abs ( healthPercent - 1 ) * width ) ) )
self.incomingHealIndicator : SetPoint ( " topleft " , self , " topleft " , width * healthPercent , 0 )
self.incomingHealIndicator : SetPoint ( " bottomleft " , self , " bottomleft " , width * healthPercent , 0 )
else
self.incomingHealIndicator : Hide ( )
end
if ( unitHealAbsorb > 0 ) then
local healAbsorbPercent = unitHealAbsorb / currentHealthMax
self.healAbsorbIndicator : Show ( )
self.healAbsorbIndicator : SetWidth ( max ( 1 , min ( width * healAbsorbPercent , abs ( healthPercent - 1 ) * width ) ) )
self.healAbsorbIndicator : SetPoint ( " topleft " , self , " topleft " , width * healthPercent , 0 )
self.healAbsorbIndicator : SetPoint ( " bottomleft " , self , " bottomleft " , width * healthPercent , 0 )
else
self.healAbsorbIndicator : Hide ( )
end
end
if ( self.Settings . ShowShields and IS_WOW_PROJECT_MAINLINE ) then
--damage absorbs
local unitDamageAbsorb = self.displayedUnit and UnitGetTotalAbsorbs ( self.displayedUnit ) or 0
if ( unitDamageAbsorb > 0 ) then
local damageAbsorbPercent = unitDamageAbsorb / currentHealthMax
self.shieldAbsorbIndicator : Show ( )
--set the width where the max width size is what is lower: the absorb size or the missing amount of health in the health bar
--/dump NamePlate1PlaterUnitFrameHealthBar.shieldAbsorbIndicator:GetSize()
self.shieldAbsorbIndicator : SetWidth ( max ( 1 , min ( width * damageAbsorbPercent , abs ( healthPercent - 1 ) * width ) ) )
self.shieldAbsorbIndicator : SetPoint ( " topleft " , self , " topleft " , width * healthPercent , 0 )
self.shieldAbsorbIndicator : SetPoint ( " bottomleft " , self , " bottomleft " , width * healthPercent , 0 )
--if the absorb percent pass 100%, show the glow
if ( ( healthPercent + damageAbsorbPercent ) > 1 ) then
self.shieldAbsorbGlow : Show ( )
else
self.shieldAbsorbGlow : Hide ( )
end
else
self.shieldAbsorbIndicator : Hide ( )
self.shieldAbsorbGlow : Hide ( )
end
else
self.shieldAbsorbIndicator : Hide ( )
self.shieldAbsorbGlow : Hide ( )
end
end
--Health Events
healthBarMetaFunctions.PLAYER_ENTERING_WORLD = function ( self , ... )
self : UpdateMaxHealth ( )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
healthBarMetaFunctions.UNIT_HEALTH = function ( self , ... )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
healthBarMetaFunctions.UNIT_HEALTH_FREQUENT = function ( self , ... )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
healthBarMetaFunctions.UNIT_MAXHEALTH = function ( self , ... )
self : UpdateMaxHealth ( )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
healthBarMetaFunctions.UNIT_HEAL_PREDICTION = function ( self , ... )
self : UpdateMaxHealth ( )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
healthBarMetaFunctions.UNIT_ABSORB_AMOUNT_CHANGED = function ( self , ... )
self : UpdateMaxHealth ( )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
healthBarMetaFunctions.UNIT_HEAL_ABSORB_AMOUNT_CHANGED = function ( self , ... )
self : UpdateMaxHealth ( )
self : UpdateHealth ( )
self : UpdateHealPrediction ( )
end
-- ~healthbar
function detailsFramework : CreateHealthBar ( parent , name , settingsOverride )
assert ( name or parent : GetName ( ) , " DetailsFramework:CreateHealthBar parameter 'name' omitted and parent has no name. " )
local healthBar = CreateFrame ( " StatusBar " , name or ( parent : GetName ( ) .. " HealthBar " ) , parent , " BackdropTemplate " )
do --layers
--background
healthBar.background = healthBar : CreateTexture ( nil , " background " )
healthBar.background : SetDrawLayer ( " background " , - 6 )
--artwork
--healing incoming
healthBar.incomingHealIndicator = healthBar : CreateTexture ( nil , " artwork " )
healthBar.incomingHealIndicator : SetDrawLayer ( " artwork " , 4 )
--current shields on the unit
healthBar.shieldAbsorbIndicator = healthBar : CreateTexture ( nil , " artwork " )
healthBar.shieldAbsorbIndicator : SetDrawLayer ( " artwork " , 5 )
--debuff absorbing heal
healthBar.healAbsorbIndicator = healthBar : CreateTexture ( nil , " artwork " )
healthBar.healAbsorbIndicator : SetDrawLayer ( " artwork " , 6 )
--the shield fills all the bar, show that cool glow
healthBar.shieldAbsorbGlow = healthBar : CreateTexture ( nil , " artwork " )
healthBar.shieldAbsorbGlow : SetDrawLayer ( " artwork " , 7 )
--statusbar texture
healthBar.barTexture = healthBar : CreateTexture ( nil , " artwork " )
healthBar : SetStatusBarTexture ( healthBar.barTexture )
end
--mixins
detailsFramework : Mixin ( healthBar , healthBarMetaFunctions )
detailsFramework : Mixin ( healthBar , detailsFramework.StatusBarFunctions )
healthBar : CreateTextureMask ( )
healthBar : SetTexture ( [[Interface\WorldStateFrame\WORLDSTATEFINALSCORE-HIGHLIGHT]] )
--settings and hooks
local settings = detailsFramework.table . copy ( { } , healthBarMetaFunctions.Settings )
if ( settingsOverride ) then
detailsFramework.table . copy ( settings , settingsOverride )
end
healthBar.Settings = settings
--hook list
healthBar.HookList = detailsFramework.table . copy ( { } , healthBarMetaFunctions.HookList )
--initialize the cast bar
healthBar : Initialize ( )
return healthBar
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--power bar frame
--[=[
DF : CreatePowerBar ( parent , name , settingsOverride )
creates statusbar frame to show the unit power bar
@ parent = frame to pass for the CreateFrame function
@ name = absolute name of the frame , if omitted it uses the parent ' s name .. "PPowerBar"
@ settingsOverride = table with keys and values to replace the defaults from the framework
--]=]
detailsFramework.PowerFrameFunctions = {
WidgetType = " powerBar " ,
HookList = {
OnHide = { } ,
OnShow = { } ,
} ,
Settings = {
--misc
ShowAlternatePower = true , --if true it'll show alternate power over the regular power the unit uses
ShowPercentText = true , --if true show a text with the current energy percent
HideIfNoPower = true , --if true and the UnitMaxPower returns zero, it'll hide the power bar with self:Hide()
CanTick = false , --if it calls the OnTick function every tick
--appearance
BackgroundColor = detailsFramework : CreateColorTable ( .2 , .2 , .2 , .8 ) ,
Texture = [[Interface\RaidFrame\Raid-Bar-Resource-Fill]] ,
--default size
Width = 100 ,
Height = 20 ,
} ,
PowerBarEvents = {
{ " PLAYER_ENTERING_WORLD " } ,
{ " UNIT_DISPLAYPOWER " , true } ,
{ " UNIT_POWER_BAR_SHOW " , true } ,
{ " UNIT_POWER_BAR_HIDE " , true } ,
{ " UNIT_MAXPOWER " , true } ,
{ " UNIT_POWER_UPDATE " , true } ,
{ " UNIT_POWER_FREQUENT " , true } ,
} ,
--setup the castbar to be used by another unit
SetUnit = function ( self , unit , displayedUnit )
if ( self.unit ~= unit or self.displayedUnit ~= displayedUnit or unit == nil ) then
self.unit = unit
self.displayedUnit = displayedUnit or unit
--register events
if ( unit ) then
for _ , eventTable in ipairs ( self.PowerBarEvents ) do
local event = eventTable [ 1 ]
local isUnitEvent = eventTable [ 2 ]
if ( isUnitEvent ) then
self : RegisterUnitEvent ( event , self.displayedUnit )
else
self : RegisterEvent ( event )
end
end
--set scripts
self : SetScript ( " OnEvent " , self.OnEvent )
if ( self.Settings . CanTick ) then
self : SetScript ( " OnUpdate " , self.OnTick )
end
self : Show ( )
self : UpdatePowerBar ( )
else
--remove all registered events
for _ , eventTable in ipairs ( self.PowerBarEvents ) do
local event = eventTable [ 1 ]
self : UnregisterEvent ( event )
end
--remove scripts
self : SetScript ( " OnEvent " , nil )
self : SetScript ( " OnUpdate " , nil )
self : Hide ( )
end
end
end ,
Initialize = function ( self )
PixelUtil.SetWidth ( self , self.Settings . Width )
PixelUtil.SetHeight ( self , self.Settings . Height )
self : SetTexture ( self.Settings . Texture )
self.background : SetAllPoints ( )
self.background : SetColorTexture ( self.Settings . BackgroundColor : GetColor ( ) )
if ( self.Settings . ShowPercentText ) then
self.percentText : Show ( )
PixelUtil.SetPoint ( self.percentText , " center " , self , " center " , 0 , 0 )
detailsFramework : SetFontSize ( self.percentText , 9 )
detailsFramework : SetFontColor ( self.percentText , " white " )
detailsFramework : SetFontOutline ( self.percentText , " OUTLINE " )
else
self.percentText : Hide ( )
end
self : SetUnit ( nil )
end ,
--call every tick
OnTick = function ( self , deltaTime ) end , --if overrided, set 'CanTick' to true on the settings table
--when an event happen for this unit, send it to the apropriate function
OnEvent = function ( self , event , ... )
local eventFunc = self [ event ]
if ( eventFunc ) then
--the function doesn't receive which event was, only 'self' and the parameters
eventFunc ( self , ... )
end
end ,
UpdatePowerBar = function ( self )
self : UpdatePowerInfo ( )
self : UpdateMaxPower ( )
self : UpdatePower ( )
self : UpdatePowerColor ( )
end ,
--power update
UpdateMaxPower = function ( self )
self.currentPowerMax = UnitPowerMax ( self.displayedUnit , self.powerType )
self : SetMinMaxValues ( self.minPower , self.currentPowerMax )
if ( self.currentPowerMax == 0 and self.Settings . HideIfNoPower ) then
self : Hide ( )
end
end ,
UpdatePower = function ( self )
self.currentPower = UnitPower ( self.displayedUnit , self.powerType )
PixelUtil.SetStatusBarValue ( self , self.currentPower )
if ( self.Settings . ShowPercentText ) then
self.percentText : SetText ( floor ( self.currentPower / self.currentPowerMax * 100 ) .. " % " )
end
end ,
--when a event different from unit_power_update is triggered, update which type of power the unit should show
UpdatePowerInfo = function ( self )
if ( IS_WOW_PROJECT_MAINLINE and self.Settings . ShowAlternatePower ) then -- not available in classic
local barID = UnitPowerBarID ( self.displayedUnit )
local barInfo = GetUnitPowerBarInfoByID ( barID )
--local name, tooltip, cost = GetUnitPowerBarStringsByID(barID);
--barInfo.barType,barInfo.minPower, barInfo.startInset, barInfo.endInset, barInfo.smooth, barInfo.hideFromOthers, barInfo.showOnRaid, barInfo.opaqueSpark, barInfo.opaqueFlash, barInfo.anchorTop, name, tooltip, cost, barInfo.ID, barInfo.forcePercentage, barInfo.sparkUnderFrame;
if ( barInfo and barInfo.showOnRaid and IsInGroup ( ) ) then
self.powerType = ALTERNATE_POWER_INDEX
self.minPower = barInfo.minPower
return
end
end
self.powerType = UnitPowerType ( self.displayedUnit )
self.minPower = 0
end ,
--tint the bar with the color of the power, e.g. blue for a mana bar
UpdatePowerColor = function ( self )
if ( not UnitIsConnected ( self.unit ) ) then
self : SetStatusBarColor ( .5 , .5 , .5 )
return
end
if ( self.powerType == ALTERNATE_POWER_INDEX ) then
--don't change this, keep the same color as the game tints on CompactUnitFrame.lua
self : SetStatusBarColor ( 0.7 , 0.7 , 0.6 )
return
end
local powerColor = PowerBarColor [ self.powerType ] --don't appear to be, but PowerBarColor is a global table with all power colors /run Details:Dump (PowerBarColor)
if ( powerColor ) then
self : SetStatusBarColor ( powerColor.r , powerColor.g , powerColor.b )
return
end
local _ , _ , r , g , b = UnitPowerType ( self.displayedUnit )
if ( r ) then
self : SetStatusBarColor ( r , g , b )
return
end
--if everything else fails, tint as rogue energy
powerColor = PowerBarColor [ " ENERGY " ]
self : SetStatusBarColor ( powerColor.r , powerColor.g , powerColor.b )
end ,
--events
PLAYER_ENTERING_WORLD = function ( self , ... )
self : UpdatePowerBar ( )
end ,
UNIT_DISPLAYPOWER = function ( self , ... )
self : UpdatePowerBar ( )
end ,
UNIT_POWER_BAR_SHOW = function ( self , ... )
self : UpdatePowerBar ( )
end ,
UNIT_POWER_BAR_HIDE = function ( self , ... )
self : UpdatePowerBar ( )
end ,
UNIT_MAXPOWER = function ( self , ... )
self : UpdateMaxPower ( )
self : UpdatePower ( )
end ,
UNIT_POWER_UPDATE = function ( self , ... )
self : UpdatePower ( )
end ,
UNIT_POWER_FREQUENT = function ( self , ... )
self : UpdatePower ( )
end ,
}
detailsFramework : Mixin ( detailsFramework.PowerFrameFunctions , detailsFramework.ScriptHookMixin )
-- ~powerbar
function detailsFramework : CreatePowerBar ( parent , name , settingsOverride )
assert ( name or parent : GetName ( ) , " DetailsFramework:CreatePowerBar parameter 'name' omitted and parent has no name. " )
local powerBar = CreateFrame ( " StatusBar " , name or ( parent : GetName ( ) .. " PowerBar " ) , parent , " BackdropTemplate " )
do --layers
--background
powerBar.background = powerBar : CreateTexture ( nil , " background " )
powerBar.background : SetDrawLayer ( " background " , - 6 )
--artwork
powerBar.barTexture = powerBar : CreateTexture ( nil , " artwork " )
powerBar : SetStatusBarTexture ( powerBar.barTexture )
--overlay
powerBar.percentText = powerBar : CreateFontString ( nil , " overlay " , " GameFontNormal " )
end
--mixins
detailsFramework : Mixin ( powerBar , detailsFramework.PowerFrameFunctions )
detailsFramework : Mixin ( powerBar , detailsFramework.StatusBarFunctions )
powerBar : CreateTextureMask ( )
powerBar : SetTexture ( [[Interface\WorldStateFrame\WORLDSTATEFINALSCORE-HIGHLIGHT]] )
--settings and hooks
local settings = detailsFramework.table . copy ( { } , detailsFramework.PowerFrameFunctions . Settings )
if ( settingsOverride ) then
detailsFramework.table . copy ( settings , settingsOverride )
end
powerBar.Settings = settings
local hookList = detailsFramework.table . copy ( { } , detailsFramework.PowerFrameFunctions . HookList )
powerBar.HookList = hookList
--initialize the cast bar
powerBar : Initialize ( )
return powerBar
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--cast bar frame
--[=[
DF : CreateCastBar ( parent , name , settingsOverride )
creates a cast bar to show an unit cast
@ parent = frame to pass for the CreateFrame function
@ name = absolute name of the frame , if omitted it uses the parent ' s name .. "CastBar"
@ settingsOverride = table with keys and values to replace the defaults from the framework
--]=]
detailsFramework.CastFrameFunctions = {
WidgetType = " castBar " ,
HookList = {
OnHide = { } ,
OnShow = { } ,
--can be regular cast or channel
OnCastStart = { } ,
} ,
CastBarEvents = {
{ " UNIT_SPELLCAST_INTERRUPTED " } ,
{ " UNIT_SPELLCAST_DELAYED " } ,
{ " UNIT_SPELLCAST_CHANNEL_START " } ,
{ " UNIT_SPELLCAST_CHANNEL_UPDATE " } ,
{ " UNIT_SPELLCAST_CHANNEL_STOP " } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_SPELLCAST_EMPOWER_START " } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_SPELLCAST_EMPOWER_UPDATE " } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_SPELLCAST_EMPOWER_STOP " } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_SPELLCAST_INTERRUPTIBLE " } ,
{ ( IS_WOW_PROJECT_MAINLINE ) and " UNIT_SPELLCAST_NOT_INTERRUPTIBLE " } ,
{ " PLAYER_ENTERING_WORLD " } ,
{ " UNIT_SPELLCAST_START " , true } ,
{ " UNIT_SPELLCAST_STOP " , true } ,
{ " UNIT_SPELLCAST_FAILED " , true } ,
} ,
Settings = {
NoFadeEffects = false , --if true it won't play fade effects when a cast if finished
ShowTradeSkills = false , --if true, it shows cast for trade skills, e.g. creating an icon with blacksmith
ShowShield = true , --if true, shows the shield above the spell icon for non interruptible casts
CanTick = true , --if true it will run its OnTick function every tick.
ShowCastTime = true , --if true, show the remaining time to finish the cast, lazy tick must be enabled
FadeInTime = 0.1 , --amount of time in seconds to go from zero to 100% alpha when starting to cast
FadeOutTime = 0.5 , --amount of time in seconds to go from 100% to zero alpha when the cast finishes
CanLazyTick = true , --if true, it'll execute the lazy tick function, it ticks in a much slower pace comparece with the regular tick
LazyUpdateCooldown = 0.2 , --amount of time to wait for the next lazy update, this updates non critical things like the cast timer
ShowEmpoweredDuration = true , --full hold time for empowered spells
FillOnInterrupt = true ,
HideSparkOnInterrupt = true ,
--default size
Width = 100 ,
Height = 20 ,
--colour the castbar statusbar by the type of the cast
Colors = {
Casting = detailsFramework : CreateColorTable ( 1 , 0.73 , .1 , 1 ) ,
Channeling = detailsFramework : CreateColorTable ( 1 , 0.73 , .1 , 1 ) ,
Finished = detailsFramework : CreateColorTable ( 0 , 1 , 0 , 1 ) ,
NonInterruptible = detailsFramework : CreateColorTable ( .7 , .7 , .7 , 1 ) ,
Failed = detailsFramework : CreateColorTable ( .4 , .4 , .4 , 1 ) ,
Interrupted = detailsFramework : CreateColorTable ( .965 , .754 , .154 , 1 ) ,
} ,
--appearance
BackgroundColor = detailsFramework : CreateColorTable ( .2 , .2 , .2 , .8 ) ,
Texture = [[Interface\TargetingFrame\UI-StatusBar]] ,
BorderShieldWidth = 10 ,
BorderShieldHeight = 12 ,
BorderShieldCoords = { 0.26171875 , 0.31640625 , 0.53125 , 0.65625 } ,
BorderShieldTexture = 1300837 ,
SpellIconWidth = 10 ,
SpellIconHeight = 10 ,
ShieldIndicatorTexture = [[Interface\RaidFrame\Shield-Fill]] ,
ShieldGlowTexture = [[Interface\RaidFrame\Shield-Overshield]] ,
SparkTexture = [[Interface\CastingBar\UI-CastingBar-Spark]] ,
SparkWidth = 16 ,
SparkHeight = 16 ,
SparkOffset = 0 ,
} ,
Initialize = function ( self )
self.unit = " unutilized unit "
self.lazyUpdateCooldown = self.Settings . LazyUpdateCooldown
self.Colors = self.Settings . Colors
self : SetUnit ( nil )
PixelUtil.SetWidth ( self , self.Settings . Width )
PixelUtil.SetHeight ( self , self.Settings . Height )
self.background : SetColorTexture ( self.Settings . BackgroundColor : GetColor ( ) )
self.background : SetAllPoints ( )
self.extraBackground : SetColorTexture ( 0 , 0 , 0 , 1 )
self.extraBackground : SetVertexColor ( self.Settings . BackgroundColor : GetColor ( ) )
self.extraBackground : SetAllPoints ( )
self : SetTexture ( self.Settings . Texture )
self.BorderShield : SetPoint ( " center " , self , " left " , 0 , 0 )
self.BorderShield : SetTexture ( self.Settings . BorderShieldTexture )
self.BorderShield : SetTexCoord ( unpack ( self.Settings . BorderShieldCoords ) )
self.BorderShield : SetSize ( self.Settings . BorderShieldWidth , self.Settings . BorderShieldHeight )
self.Icon : SetPoint ( " center " , self , " left " , 2 , 0 )
self.Icon : SetSize ( self.Settings . SpellIconWidth , self.Settings . SpellIconHeight )
self.Spark : SetTexture ( self.Settings . SparkTexture )
self.Spark : SetSize ( self.Settings . SparkWidth , self.Settings . SparkHeight )
self.percentText : SetPoint ( " right " , self , " right " , - 2 , 0 )
self.percentText : SetJustifyH ( " right " )
self.fadeOutAnimation . alpha1 : SetDuration ( self.Settings . FadeOutTime )
self.fadeInAnimation . alpha1 : SetDuration ( self.Settings . FadeInTime )
end ,
SetDefaultColor = function ( self , colorType , r , g , b , a )
assert ( type ( colorType ) == " string " , " DetailsFramework: CastBar:SetDefaultColor require a string in the first argument. " )
self.Colors [ colorType ] : SetColor ( r , g , b , a )
end ,
--this get a color suggestion based on the type of cast being shown in the cast bar
GetCastColor = function ( self )
if ( not self.canInterrupt ) then
return self.Colors . NonInterruptible
elseif ( self.channeling ) then
return self.Colors . Channeling
elseif ( self.failed ) then
return self.Colors . Failed
elseif ( self.interrupted ) then
return self.Colors . Interrupted
elseif ( self.finished ) then
return self.Colors . Finished
else
return self.Colors . Casting
end
end ,
--update all colors of the cast bar
UpdateCastColor = function ( self )
local castColor = self : GetCastColor ( )
self : SetColor ( castColor ) --SetColor handles with ParseColors()
end ,
--initial checks to know if this is a valid cast and should show the cast bar, if this fails the cast bar won't show
IsValid = function ( self , unit , castName , isTradeSkill , ignoreVisibility )
if ( not ignoreVisibility and not self : IsShown ( ) ) then
return false
end
if ( not self.Settings . ShowTradeSkills ) then
if ( isTradeSkill ) then
return false
end
end
if ( not castName ) then
return false
end
return true
end ,
--handle the interrupt state of the cast
--this does not change the cast bar color because this function is called inside the start cast where is already handles the cast color
UpdateInterruptState = function ( self )
if ( self.Settings . ShowShield and not self.canInterrupt ) then
self.BorderShield : Show ( )
else
self.BorderShield : Hide ( )
end
end ,
--this check if the cast did reach 100% in the statusbar, mostly called from OnTick
CheckCastIsDone = function ( self , event , isFinished )
--check max value
if ( not isFinished and not self.finished ) then
if ( self.casting ) then
if ( self.value >= self.maxValue ) then
isFinished = true
end
elseif ( self.channeling ) then
if ( self.value > self.maxValue or self.value <= 0 ) then
isFinished = true
end
end
--check if passed an event (not begin used at the moment)
if ( event ) then
if ( event == UNIT_SPELLCAST_STOP or event == UNIT_SPELLCAST_CHANNEL_STOP ) then
isFinished = true
end
end
end
--the cast is finished
if ( isFinished ) then
if ( self.casting ) then
self.UNIT_SPELLCAST_STOP ( self , self.unit , self.unit , self.castID , self.spellID )
elseif ( self.channeling ) then
self.UNIT_SPELLCAST_CHANNEL_STOP ( self , self.unit , self.unit , self.castID , self.spellID )
end
return true
end
end ,
--setup the castbar to be used by another unit
SetUnit = function ( self , unit , displayedUnit )
if ( self.unit ~= unit or self.displayedUnit ~= displayedUnit or unit == nil ) then
self.unit = unit
self.displayedUnit = displayedUnit or unit
--reset the cast bar
self.casting = nil
self.channeling = nil
self.caninterrupt = nil
--register events
if ( unit ) then
for _ , eventTable in ipairs ( self.CastBarEvents ) do
local event = eventTable [ 1 ]
local isUnitEvent = eventTable [ 2 ]
if event then
if ( isUnitEvent ) then
self : RegisterUnitEvent ( event , unit )
else
self : RegisterEvent ( event )
end
end
end
--set scripts
self : SetScript ( " OnEvent " , self.OnEvent )
self : SetScript ( " OnShow " , self.OnShow )
self : SetScript ( " OnHide " , self.OnHide )
if ( self.Settings . CanTick ) then
self : SetScript ( " OnUpdate " , self.OnTick )
end
--check is can show the cast time text
if ( self.Settings . ShowCastTime and self.Settings . CanLazyTick ) then
self.percentText : Show ( )
else
self.percentText : Hide ( )
end
--setup animtions
self : CancelScheduleToHide ( )
--self:PLAYER_ENTERING_WORLD (unit, unit)
self : OnEvent ( " PLAYER_ENTERING_WORLD " , unit , unit )
else
for _ , eventTable in ipairs ( self.CastBarEvents ) do
local event = eventTable [ 1 ]
if event then
self : UnregisterEvent ( event )
end
end
--register main events
self : SetScript ( " OnUpdate " , nil )
self : SetScript ( " OnEvent " , nil )
self : SetScript ( " OnShow " , nil )
self : SetScript ( " OnHide " , nil )
self : Hide ( )
end
end
end ,
--executed after a scheduled to hide timer is done
DoScheduledHide = function ( timerObject )
timerObject.castBar . scheduledHideTime = nil
--just to make sure it isn't casting
if ( not timerObject.castBar . casting and not timerObject.castBar . channeling ) then
if ( not timerObject.castBar . Settings.NoFadeEffects ) then
timerObject.castBar : Animation_FadeOut ( )
else
timerObject.castBar : Hide ( )
end
end
end ,
HasScheduledHide = function ( self )
return self.scheduledHideTime and not self.scheduledHideTime : IsCancelled ( )
end ,
CancelScheduleToHide = function ( self )
if ( self : HasScheduledHide ( ) ) then
self.scheduledHideTime : Cancel ( )
end
end ,
--after an interrupt, do not immediately hide the cast bar, let it up for short amount of time to give feedback to the player
ScheduleToHide = function ( self , delay )
if ( not delay ) then
if ( self.scheduledHideTime and not self.scheduledHideTime : IsCancelled ( ) ) then
self.scheduledHideTime : Cancel ( )
end
self.scheduledHideTime = nil
return
end
--already have a scheduled timer?
if ( self.scheduledHideTime and not self.scheduledHideTime : IsCancelled ( ) ) then
self.scheduledHideTime : Cancel ( )
end
self.scheduledHideTime = C_Timer.NewTimer ( delay , self.DoScheduledHide )
self.scheduledHideTime . castBar = self
end ,
OnHide = function ( self )
--just in case some other effects made it have a different alpha since SetUnit won't load if the unit is the same.
self : SetAlpha ( 1 )
--cancel any timer to hide scheduled
self : CancelScheduleToHide ( )
end ,
--just update the current value if a spell is being cast since it wasn't running its tick function during the hide state
--everything else should be in the correct state
OnShow = function ( self )
self.flashTexture : Hide ( )
if ( self.unit ) then
if ( self.casting ) then
local name , text , texture , startTime = UnitCastingInfo ( self.unit )
if ( name ) then
--[[if not self.spellStartTime then
self : UpdateCastingInfo ( self.unit )
end ] ] --
self.value = GetTime ( ) - self.spellStartTime
end
self : RunHooksForWidget ( " OnShow " , self , self.unit )
elseif ( self.channeling ) then
local name , text , texture , endTime = UnitChannelInfo ( self.unit )
if ( name ) then
--[[if not self.spellEndTime then
self : UpdateChannelInfo ( self.unit )
end ] ] --
self.value = self.spellEndTime - GetTime ( )
end
self : RunHooksForWidget ( " OnShow " , self , self.unit )
end
end
end ,
--it's triggering several events since it's not registered for the unit with RegisterUnitEvent
OnEvent = function ( self , event , ... )
local arg1 = ...
local unit = self.unit
if ( event == " PLAYER_ENTERING_WORLD " ) then
local newEvent = self.PLAYER_ENTERING_WORLD ( self , unit , ... )
if ( newEvent ) then
self.OnEvent ( self , newEvent , unit )
return
end
elseif ( arg1 ~= unit ) then
return
end
local eventFunc = self [ event ]
if ( eventFunc ) then
eventFunc ( self , unit , ... )
end
end ,
OnTick_LazyTick = function ( self )
--run the lazy tick if allowed
if ( self.Settings . CanLazyTick ) then
--update the cast time
if ( self.Settings . ShowCastTime ) then
if ( self.casting ) then
self.percentText : SetText ( format ( " %.1f " , abs ( self.value - self.maxValue ) ) )
elseif ( self.channeling ) then
local remainingTime = abs ( self.value )
if ( remainingTime > 999 ) then
self.percentText : SetText ( " " )
else
self.percentText : SetText ( format ( " %.1f " , remainingTime ) )
end
else
self.percentText : SetText ( " " )
end
end
return true
else
return false
end
end ,
--tick function for regular casts
OnTick_Casting = function ( self , deltaTime )
self.value = self.value + deltaTime
if ( self : CheckCastIsDone ( ) ) then
return
else
self : SetValue ( self.value )
end
--update spark position
local sparkPosition = self.value / self.maxValue * self : GetWidth ( )
self.Spark : SetPoint ( " center " , self , " left " , sparkPosition + self.Settings . SparkOffset , 0 )
--in order to allow the lazy tick run, it must return true, it tell that the cast didn't finished
return true
end ,
--tick function for channeling casts
OnTick_Channeling = function ( self , deltaTime )
self.value = self.value - deltaTime
if ( self : CheckCastIsDone ( ) ) then
return
else
self : SetValue ( self.value )
end
--update spark position
local sparkPosition = self.value / self.maxValue * self : GetWidth ( )
self.Spark : SetPoint ( " center " , self , " left " , sparkPosition + self.Settings . SparkOffset , 0 )
return true
end ,
OnTick = function ( self , deltaTime )
if ( self.casting ) then
if ( not self : OnTick_Casting ( deltaTime ) ) then
return
end
--lazy tick
self.lazyUpdateCooldown = self.lazyUpdateCooldown - deltaTime
if ( self.lazyUpdateCooldown < 0 ) then
self : OnTick_LazyTick ( )
self.lazyUpdateCooldown = self.Settings . LazyUpdateCooldown
end
elseif ( self.channeling ) then
if ( not self : OnTick_Channeling ( deltaTime ) ) then
return
end
--lazy tick
self.lazyUpdateCooldown = self.lazyUpdateCooldown - deltaTime
if ( self.lazyUpdateCooldown < 0 ) then
self : OnTick_LazyTick ( )
self.lazyUpdateCooldown = self.Settings . LazyUpdateCooldown
end
end
end ,
--animation start script
Animation_FadeOutStarted = function ( self )
end ,
--animation finished script
Animation_FadeOutFinished = function ( self )
local castBar = self : GetParent ( )
castBar : SetAlpha ( 1 )
castBar : Hide ( )
end ,
--animation start script
Animation_FadeInStarted = function ( self )
end ,
--animation finished script
Animation_FadeInFinished = function ( self )
local castBar = self : GetParent ( )
castBar : Show ( )
castBar : SetAlpha ( 1 )
end ,
--animation calls
Animation_FadeOut = function ( self )
self : ScheduleToHide ( false )
if ( self.fadeInAnimation : IsPlaying ( ) ) then
self.fadeInAnimation : Stop ( )
end
if ( not self.fadeOutAnimation : IsPlaying ( ) ) then
self.fadeOutAnimation : Play ( )
end
end ,
Animation_FadeIn = function ( self )
self : ScheduleToHide ( false )
if ( self.fadeOutAnimation : IsPlaying ( ) ) then
self.fadeOutAnimation : Stop ( )
end
if ( not self.fadeInAnimation : IsPlaying ( ) ) then
self.fadeInAnimation : Play ( )
end
end ,
Animation_Flash = function ( self )
if ( not self.flashAnimation : IsPlaying ( ) ) then
self.flashAnimation : Play ( )
end
end ,
Animation_StopAllAnimations = function ( self )
if ( self.flashAnimation : IsPlaying ( ) ) then
self.flashAnimation : Stop ( )
end
if ( self.fadeOutAnimation : IsPlaying ( ) ) then
self.fadeOutAnimation : Stop ( )
end
if ( self.fadeInAnimation : IsPlaying ( ) ) then
self.fadeInAnimation : Stop ( )
end
end ,
PLAYER_ENTERING_WORLD = function ( self , unit , arg1 )
local isChannel = UnitChannelInfo ( unit )
local isRegularCast = UnitCastingInfo ( unit )
if ( isChannel ) then
self.channeling = true
self : UpdateChannelInfo ( unit )
return self.unit == arg1 and " UNIT_SPELLCAST_CHANNEL_START "
elseif ( isRegularCast ) then
self.casting = true
self : UpdateCastingInfo ( unit )
return self.unit == arg1 and " UNIT_SPELLCAST_START "
else
self.casting = nil
self.channeling = nil
self.failed = nil
self.finished = nil
self.interrupted = nil
self.Spark : Hide ( )
self : Hide ( )
end
end ,
UpdateCastingInfo = function ( self , unit )
local name , text , texture , startTime , endTime , isTradeSkill , castID , notInterruptible , spellID = UnitCastingInfo ( unit )
--is valid?
if ( not self : IsValid ( unit , name , isTradeSkill , true ) ) then
return
end
--setup cast
self.casting = true
self.channeling = nil
self.interrupted = nil
self.failed = nil
self.finished = nil
self.canInterrupt = not notInterruptible
self.spellID = spellID
self.castID = castID
self.spellName = name
self.spellTexture = texture
self.spellStartTime = startTime / 1000
self.spellEndTime = endTime / 1000
self.value = GetTime ( ) - self.spellStartTime
self.maxValue = self.spellEndTime - self.spellStartTime
self : SetMinMaxValues ( 0 , self.maxValue )
self : SetValue ( self.value )
self : SetAlpha ( 1 )
self.Icon : SetTexture ( texture )
self.Icon : Show ( )
self.Text : SetText ( text or name )
if ( self.Settings . ShowCastTime and self.Settings . CanLazyTick ) then
self.percentText : Show ( )
end
self.flashTexture : Hide ( )
self : Animation_StopAllAnimations ( )
self : SetAlpha ( 1 )
--set the statusbar color
self : UpdateCastColor ( )
if ( not self : IsShown ( ) ) then
self : Animation_FadeIn ( )
end
self.Spark : Show ( )
self : Show ( )
--update the interrupt cast border
self : UpdateInterruptState ( )
end ,
UNIT_SPELLCAST_START = function ( self , unit )
self : UpdateCastingInfo ( unit )
self : RunHooksForWidget ( " OnCastStart " , self , self.unit , " UNIT_SPELLCAST_START " )
end ,
UpdateChannelInfo = function ( self , unit , ... )
local name , text , texture , startTime , endTime , isTradeSkill , notInterruptible , spellID , _ , numStages = UnitChannelInfo ( unit )
--is valid?
if ( not self : IsValid ( unit , name , isTradeSkill , true ) ) then
return
end
--empowered?
self.empStages = { }
if numStages and numStages > 0 then
self.holdAtMaxTime = GetUnitEmpowerHoldAtMaxTime ( unit )
self.empowered = true
local lastStageEndTime = 0
for i = 1 , numStages do
self.empStages [ i ] = {
start = lastStageEndTime ,
finish = lastStageEndTime - GetUnitEmpowerStageDuration ( unit , i - 1 ) / 1000 ,
}
lastStageEndTime = self.empStages [ i ] . finish
if startTime / 1000 + lastStageEndTime <= GetTime ( ) then
self.curStage = i
end
end
if ( self.Settings . ShowEmpoweredDuration ) then
endTime = endTime + self.holdAtMaxTime
end
else
self.holdAtMaxTime = 0
self.empowered = false
self.curStage = 0
end
--setup cast
self.casting = nil
self.channeling = true
self.interrupted = nil
self.failed = nil
self.finished = nil
self.canInterrupt = not notInterruptible
self.spellID = spellID
self.castID = castID
self.spellName = name
self.spellTexture = texture
self.spellStartTime = startTime / 1000
self.spellEndTime = endTime / 1000
self.value = self.spellEndTime - GetTime ( )
self.maxValue = self.spellEndTime - self.spellStartTime
self.numStages = numStages
self : SetMinMaxValues ( 0 , self.maxValue )
self : SetValue ( self.value )
self : SetAlpha ( 1 )
self.Icon : SetTexture ( texture )
self.Icon : Show ( )
self.Text : SetText ( text )
if ( self.Settings . ShowCastTime and self.Settings . CanLazyTick ) then
self.percentText : Show ( )
end
self.flashTexture : Hide ( )
self : Animation_StopAllAnimations ( )
self : SetAlpha ( 1 )
--set the statusbar color
self : UpdateCastColor ( )
if ( not self : IsShown ( ) ) then
self : Animation_FadeIn ( )
end
self.Spark : Show ( )
self : Show ( )
--update the interrupt cast border
self : UpdateInterruptState ( )
end ,
UNIT_SPELLCAST_CHANNEL_START = function ( self , unit , ... )
self : UpdateChannelInfo ( unit , ... )
self : RunHooksForWidget ( " OnCastStart " , self , self.unit , " UNIT_SPELLCAST_CHANNEL_START " )
end ,
UNIT_SPELLCAST_STOP = function ( self , unit , ... )
local unitID , castID , spellID = ...
if ( self.castID == castID ) then
if ( self.interrupted ) then
if ( self.Settings . HideSparkOnInterrupt ) then
self.Spark : Hide ( )
end
else
self.Spark : Hide ( )
end
self.percentText : Hide ( )
local value = self : GetValue ( )
local _ , maxValue = self : GetMinMaxValues ( )
if ( self.interrupted ) then
if ( self.Settings . FillOnInterrupt ) then
self : SetValue ( self.maxValue or maxValue or 1 )
end
else
self : SetValue ( self.maxValue or maxValue or 1 )
end
self.casting = nil
self.finished = true
if ( not self : HasScheduledHide ( ) ) then
--check if settings has no fade option or if its parents are not visible
if ( not self : IsVisible ( ) ) then
self : Hide ( )
elseif ( self.Settings . NoFadeEffects ) then
self : ScheduleToHide ( 0.3 )
else
self : Animation_Flash ( )
self : Animation_FadeOut ( )
end
end
self : UpdateCastColor ( )
end
end ,
UNIT_SPELLCAST_CHANNEL_STOP = function ( self , unit , ... )
local unitID , castID , spellID = ...
if ( self.channeling and castID == self.castID ) then
self.Spark : Hide ( )
self.percentText : Hide ( )
local value = self : GetValue ( )
local _ , maxValue = self : GetMinMaxValues ( )
self : SetValue ( self.maxValue or maxValue or 1 )
self.channeling = nil
self.finished = true
if ( not self : HasScheduledHide ( ) ) then
--check if settings has no fade option or if its parents are not visible
if ( not self : IsVisible ( ) ) then
self : Hide ( )
elseif ( self.Settings . NoFadeEffects ) then
self : ScheduleToHide ( 0.3 )
else
self : Animation_Flash ( )
self : Animation_FadeOut ( )
end
end
self : UpdateCastColor ( )
end
end ,
UNIT_SPELLCAST_EMPOWER_START = function ( self , unit , ... )
self : UNIT_SPELLCAST_CHANNEL_START ( unit , ... )
end ,
UNIT_SPELLCAST_EMPOWER_UPDATE = function ( self , unit , ... )
self : UNIT_SPELLCAST_CHANNEL_UPDATE ( unit , ... )
end ,
UNIT_SPELLCAST_EMPOWER_STOP = function ( self , unit , ... )
self : UNIT_SPELLCAST_CHANNEL_STOP ( unit , ... )
end ,
UNIT_SPELLCAST_FAILED = function ( self , unit , ... )
local unitID , castID , spellID = ...
if ( ( self.casting or self.channeling ) and castID == self.castID and not self.fadeOut ) then
self.casting = nil
self.channeling = nil
self.failed = true
self.finished = true
self : SetValue ( self.maxValue or select ( 2 , self : GetMinMaxValues ( ) ) or 1 )
--set the statusbar color
self : UpdateCastColor ( )
self.Spark : Hide ( )
self.percentText : Hide ( )
self.Text : SetText ( FAILED ) --auto locale within the global namespace
self : ScheduleToHide ( 1 )
end
end ,
UNIT_SPELLCAST_INTERRUPTED = function ( self , unit , ... )
local unitID , castID , spellID = ...
if ( ( self.casting or self.channeling ) and castID == self.castID and not self.fadeOut ) then
self.casting = nil
self.channeling = nil
self.interrupted = true
self.finished = true
if ( self.Settings . FillOnInterrupt ) then
self : SetValue ( self.maxValue or select ( 2 , self : GetMinMaxValues ( ) ) or 1 )
end
if ( self.Settings . HideSparkOnInterrupt ) then
self.Spark : Hide ( )
end
local castColor = self : GetCastColor ( )
self : SetColor ( castColor ) --SetColor handles with ParseColors()
self.percentText : Hide ( )
self.Text : SetText ( INTERRUPTED ) --auto locale within the global namespace
self : ScheduleToHide ( 1 )
end
end ,
UNIT_SPELLCAST_DELAYED = function ( self , unit , ... )
local name , text , texture , startTime , endTime , isTradeSkill , castID , notInterruptible = UnitCastingInfo ( unit )
if ( not self : IsValid ( unit , name , isTradeSkill ) ) then
return
end
--update the cast time
self.spellStartTime = startTime / 1000
self.spellEndTime = endTime / 1000
self.value = GetTime ( ) - self.spellStartTime
self.maxValue = self.spellEndTime - self.spellStartTime
self : SetMinMaxValues ( 0 , self.maxValue )
end ,
UNIT_SPELLCAST_CHANNEL_UPDATE = function ( self , unit , ... )
local name , text , texture , startTime , endTime , isTradeSkill , notInterruptible , spellID , _ , numStages = UnitChannelInfo ( unit )
if ( not self : IsValid ( unit , name , isTradeSkill ) ) then
return
end
--update the cast time
self.spellStartTime = startTime / 1000
self.spellEndTime = endTime / 1000
self.value = self.spellEndTime - GetTime ( )
if ( self.value < 0 ) then
self.value = 0
end
self.maxValue = self.spellEndTime - self.spellStartTime
self : SetMinMaxValues ( 0 , self.maxValue )
self : SetValue ( self.value )
end ,
--cast changed its state to interruptable
UNIT_SPELLCAST_INTERRUPTIBLE = function ( self , unit , ... )
self.canInterrupt = true
self : UpdateCastColor ( )
self : UpdateInterruptState ( )
end ,
--cast changed its state to non interruptable
UNIT_SPELLCAST_NOT_INTERRUPTIBLE = function ( self , unit , ... )
self.canInterrupt = false
self : UpdateCastColor ( )
self : UpdateInterruptState ( )
end ,
}
detailsFramework : Mixin ( detailsFramework.CastFrameFunctions , detailsFramework.ScriptHookMixin )
-- for classic era use LibClassicCasterino:
local LibCC = LibStub ( " LibClassicCasterino " , true )
if IS_WOW_PROJECT_CLASSIC_ERA and LibCC then
local fCast = CreateFrame ( " frame " )
local getCastBar = function ( unitId )
local plateFrame = C_NamePlate.GetNamePlateForUnit ( unitId )
if ( not plateFrame ) then
return
end
local castBar = plateFrame.unitFrame and plateFrame.unitFrame . castBar
if ( not castBar ) then
return
end
return castBar
end
local triggerCastEvent = function ( castBar , event , unitId , ... )
if ( castBar and castBar.OnEvent ) then
castBar.OnEvent ( castBar , event , unitId )
end
end
local funcCast = function ( event , unitId , ... )
local castBar = getCastBar ( unitId )
if ( castBar ) then
triggerCastEvent ( castBar , event , unitId )
end
end
fCast.UNIT_SPELLCAST_START = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_STOP = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_DELAYED = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_FAILED = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_INTERRUPTED = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_CHANNEL_START = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_CHANNEL_UPDATE = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
fCast.UNIT_SPELLCAST_CHANNEL_STOP = function ( self , event , unitId , ... )
triggerCastEvent ( getCastBar ( unitId ) , event , unitId )
end
if LibCC then
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_START " , funcCast )
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_DELAYED " , funcCast ) -- only for player
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_STOP " , funcCast )
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_FAILED " , funcCast )
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_INTERRUPTED " , funcCast )
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_CHANNEL_START " , funcCast )
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_CHANNEL_UPDATE " , funcCast ) -- only for player
LibCC.RegisterCallback ( fCast , " UNIT_SPELLCAST_CHANNEL_STOP " , funcCast )
UnitCastingInfo = function ( unit )
return LibCC : UnitCastingInfo ( unit )
end
UnitChannelInfo = function ( unit )
return LibCC : UnitChannelInfo ( unit )
end
end
end -- end classic era
-- ~castbar
function detailsFramework : CreateCastBar ( parent , name , settingsOverride )
assert ( name or parent : GetName ( ) , " DetailsFramework:CreateCastBar parameter 'name' omitted and parent has no name. " )
local castBar = CreateFrame ( " StatusBar " , name or ( parent : GetName ( ) .. " CastBar " ) , parent , " BackdropTemplate " )
do --layers
--these widgets was been made with back compatibility in mind
--they are using the same names as the retail game uses on the nameplate castbar
--this should make Plater core and Plater scripts made by users compatible with the new unit frame made on the framework
--background
castBar.background = castBar : CreateTexture ( nil , " background " , nil , - 6 )
castBar.extraBackground = castBar : CreateTexture ( nil , " background " , nil , - 5 )
--overlay
castBar.Text = castBar : CreateFontString ( nil , " overlay " , " SystemFont_Shadow_Small " )
castBar.Text : SetDrawLayer ( " overlay " , 1 )
castBar.Text : SetPoint ( " center " , 0 , 0 )
castBar.BorderShield = castBar : CreateTexture ( nil , " overlay " , nil , 5 )
castBar.BorderShield : Hide ( )
castBar.Icon = castBar : CreateTexture ( nil , " overlay " , nil , 4 )
castBar.Icon : Hide ( )
castBar.Spark = castBar : CreateTexture ( nil , " overlay " , nil , 3 )
castBar.Spark : SetBlendMode ( " ADD " )
--time left on the cast
castBar.percentText = castBar : CreateFontString ( nil , " overlay " , " SystemFont_Shadow_Small " )
castBar.percentText : SetDrawLayer ( " overlay " , 7 )
--statusbar texture
castBar.barTexture = castBar : CreateTexture ( nil , " artwork " , nil , - 6 )
castBar : SetStatusBarTexture ( castBar.barTexture )
--animations fade in and out
local fadeOutAnimationHub = detailsFramework : CreateAnimationHub ( castBar , detailsFramework.CastFrameFunctions . Animation_FadeOutStarted , detailsFramework.CastFrameFunctions . Animation_FadeOutFinished )
fadeOutAnimationHub.alpha1 = detailsFramework : CreateAnimation ( fadeOutAnimationHub , " ALPHA " , 1 , 1 , 1 , 0 )
castBar.fadeOutAnimation = fadeOutAnimationHub
local fadeInAnimationHub = detailsFramework : CreateAnimationHub ( castBar , detailsFramework.CastFrameFunctions . Animation_FadeInStarted , detailsFramework.CastFrameFunctions . Animation_FadeInFinished )
fadeInAnimationHub.alpha1 = detailsFramework : CreateAnimation ( fadeInAnimationHub , " ALPHA " , 1 , 0.150 , 0 , 1 )
castBar.fadeInAnimation = fadeInAnimationHub
--animatios flash
local flashTexture = castBar : CreateTexture ( nil , " overlay " , nil , 7 )
flashTexture : SetColorTexture ( 1 , 1 , 1 , 1 )
flashTexture : SetAllPoints ( )
flashTexture : SetAlpha ( 0 )
flashTexture : Hide ( )
flashTexture : SetBlendMode ( " ADD " )
castBar.flashTexture = flashTexture
local flashAnimationHub = detailsFramework : CreateAnimationHub ( flashTexture , function ( ) flashTexture : Show ( ) end , function ( ) flashTexture : Hide ( ) end )
detailsFramework : CreateAnimation ( flashAnimationHub , " ALPHA " , 1 , 0.2 , 0 , 0.8 )
detailsFramework : CreateAnimation ( flashAnimationHub , " ALPHA " , 2 , 0.2 , 1 , 0 )
castBar.flashAnimation = flashAnimationHub
end
--mixins
detailsFramework : Mixin ( castBar , detailsFramework.CastFrameFunctions )
detailsFramework : Mixin ( castBar , detailsFramework.StatusBarFunctions )
castBar : CreateTextureMask ( )
castBar : AddMaskTexture ( castBar.flashTexture )
castBar : AddMaskTexture ( castBar.background )
castBar : AddMaskTexture ( castBar.extraBackground )
castBar : SetTexture ( [[Interface\WorldStateFrame\WORLDSTATEFINALSCORE-HIGHLIGHT]] )
--settings and hooks
local settings = detailsFramework.table . copy ( { } , detailsFramework.CastFrameFunctions . Settings )
if ( settingsOverride ) then
detailsFramework.table . copy ( settings , settingsOverride )
end
castBar.Settings = settings
local hookList = detailsFramework.table . copy ( { } , detailsFramework.CastFrameFunctions . HookList )
castBar.HookList = hookList
--initialize the cast bar
castBar : Initialize ( )
return castBar
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--border frame
--[=[
DF : CreateBorderFrame ( parent , name )
creates a frame with 4 child textures attached to each one of the 4 sides of a frame
@ parent = parent frame to pass to CreateFrame function
@ name = name of the frame , if omitted a random name is created
--]=]
detailsFramework.BorderFunctions = {
SetBorderColor = function ( self , r , g , b , a )
r , g , b , a = detailsFramework : ParseColors ( r , g , b , a )
for _ , texture in ipairs ( self.allTextures ) do
texture : SetVertexColor ( r , g , b , a )
end
end ,
SetBorderThickness = function ( self , newThickness )
PixelUtil.SetWidth ( self.leftBorder , newThickness , newThickness )
PixelUtil.SetWidth ( self.rightBorder , newThickness , newThickness )
PixelUtil.SetHeight ( self.topBorder , newThickness , newThickness )
PixelUtil.SetHeight ( self.bottomBorder , newThickness , newThickness )
end ,
WidgetType = " border " ,
}
-- ~borderframe
function detailsFramework : CreateBorderFrame ( parent , name )
local parentName = name or " DetailsFrameworkBorderFrame " .. tostring ( math.random ( 1 , 100000000 ) )
local f = CreateFrame ( " frame " , parentName , parent , " BackdropTemplate " )
f : SetFrameLevel ( f : GetFrameLevel ( ) + 1 )
f : SetAllPoints ( )
detailsFramework : Mixin ( f , detailsFramework.BorderFunctions )
f.allTextures = { }
--create left border
local leftBorder = f : CreateTexture ( nil , " overlay " )
leftBorder : SetDrawLayer ( " overlay " , 7 )
leftBorder : SetColorTexture ( 1 , 1 , 1 , 1 )
tinsert ( f.allTextures , leftBorder )
f.leftBorder = leftBorder
PixelUtil.SetPoint ( leftBorder , " topright " , f , " topleft " , 0 , 1 , 0 , 1 )
PixelUtil.SetPoint ( leftBorder , " bottomright " , f , " bottomleft " , 0 , - 1 , 0 , - 1 )
PixelUtil.SetWidth ( leftBorder , 1 , 1 )
--create right border
local rightBorder = f : CreateTexture ( nil , " overlay " )
rightBorder : SetDrawLayer ( " overlay " , 7 )
rightBorder : SetColorTexture ( 1 , 1 , 1 , 1 )
tinsert ( f.allTextures , rightBorder )
f.rightBorder = rightBorder
PixelUtil.SetPoint ( rightBorder , " topleft " , f , " topright " , 0 , 1 , 0 , 1 )
PixelUtil.SetPoint ( rightBorder , " bottomleft " , f , " bottomright " , 0 , - 1 , 0 , - 1 )
PixelUtil.SetWidth ( rightBorder , 1 , 1 )
--create top border
local topBorder = f : CreateTexture ( nil , " overlay " )
topBorder : SetDrawLayer ( " overlay " , 7 )
topBorder : SetColorTexture ( 1 , 1 , 1 , 1 )
tinsert ( f.allTextures , topBorder )
f.topBorder = topBorder
PixelUtil.SetPoint ( topBorder , " bottomleft " , f , " topleft " , 0 , 0 , 0 , 0 )
PixelUtil.SetPoint ( topBorder , " bottomright " , f , " topright " , 0 , 0 , 0 , 0 )
PixelUtil.SetHeight ( topBorder , 1 , 1 )
--create border
local bottomBorder = f : CreateTexture ( nil , " overlay " )
bottomBorder : SetDrawLayer ( " overlay " , 7 )
bottomBorder : SetColorTexture ( 1 , 1 , 1 , 1 )
tinsert ( f.allTextures , bottomBorder )
f.bottomBorder = bottomBorder
PixelUtil.SetPoint ( bottomBorder , " topleft " , f , " bottomleft " , 0 , 0 , 0 , 0 )
PixelUtil.SetPoint ( bottomBorder , " topright " , f , " bottomright " , 0 , 0 , 0 , 0 )
PixelUtil.SetHeight ( bottomBorder , 1 , 1 )
return f
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--unit frame
--[=[
DF : CreateUnitFrame ( parent , name , settingsOverride )
creates a very basic unit frame with a healthbar , castbar and power bar
each unit frame has a . Settings table which isn ' t shared among other unit frames created with this method
all members names are the same as the unit frame from the retail game
@ parent = frame to pass for the CreateFrame function
@ name = absolute name of the frame , if omitted a random name is created
@ settingsOverride = table with keys and values to replace the defaults from the framework
--]=]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--unit frame
--return true if the unit has been claimed by another player (health bar is gray)
local isUnitTapDenied = function ( unit )
return unit and not UnitPlayerControlled ( unit ) and UnitIsTapDenied ( unit )
end
detailsFramework.UnitFrameFunctions = {
WidgetType = " unitFrame " ,
Settings = {
--unit frames
ClearUnitOnHide = true , --if tue it'll set the unit to nil when the unit frame is set to hide
ShowCastBar = true , --if this is false, the cast bar for the unit won't be shown
ShowPowerBar = true , --if true it'll show the power bar for the unit, e.g. the mana bar
ShowUnitName = true , --if false, the unit name won't show
ShowBorder = true , --if false won't show the border frame
--health bar color
CanModifyHealhBarColor = true , --if false it won't change the color of the health bar
ColorByAggro = false , --if true it'll color the healthbar with red color when the unit has aggro on player
FixedHealthColor = false , --color override with a table {r=1, g=1, b=1}
UseFriendlyClassColor = true , --make the healthbar class color for friendly players
UseEnemyClassColor = true , --make the healthbar class color for enemy players
--misc
ShowTargetOverlay = true , --shows a highlighht for the player current target
BorderColor = detailsFramework : CreateColorTable ( 0 , 0 , 0 , 1 ) , --border color, set to alpha zero for no border
CanTick = false , --if true it'll run the OnTick event
--size
Width = 100 ,
Height = 20 ,
PowerBarHeight = 4 ,
CastBarHeight = 8 ,
} ,
UnitFrameEvents = {
--run for all units
{ " PLAYER_ENTERING_WORLD " } ,
{ " PARTY_MEMBER_DISABLE " } ,
{ " PARTY_MEMBER_ENABLE " } ,
{ " PLAYER_TARGET_CHANGED " } ,
--run for one unit
{ " UNIT_NAME_UPDATE " , true } ,
{ " UNIT_CONNECTION " , true } ,
{ " UNIT_ENTERED_VEHICLE " , true } ,
{ " UNIT_EXITED_VEHICLE " , true } ,
{ " UNIT_PET " , true } ,
{ " UNIT_THREAT_LIST_UPDATE " , true } ,
} ,
--used when a event is triggered to quickly check if is a unit event
IsUnitEvent = {
[ " UNIT_NAME_UPDATE " ] = true ,
[ " UNIT_CONNECTION " ] = true ,
[ " UNIT_ENTERED_VEHICLE " ] = true ,
[ " UNIT_EXITED_VEHICLE " ] = true ,
[ " UNIT_PET " ] = true ,
[ " UNIT_THREAT_LIST_UPDATE " ] = true ,
} ,
Initialize = function ( self )
self.border : SetBorderColor ( self.Settings . BorderColor )
PixelUtil.SetWidth ( self , self.Settings . Width , 1 )
PixelUtil.SetHeight ( self , self.Settings . Height , 1 )
PixelUtil.SetPoint ( self.powerBar , " bottomleft " , self , " bottomleft " , 0 , 0 , 1 , 1 )
PixelUtil.SetPoint ( self.powerBar , " bottomright " , self , " bottomright " , 0 , 0 , 1 , 1 )
PixelUtil.SetHeight ( self.powerBar , self.Settings . PowerBarHeight , 1 )
--make the castbar overlap the powerbar
PixelUtil.SetPoint ( self.castBar , " bottomleft " , self , " bottomleft " , 0 , 0 , 1 , 1 )
PixelUtil.SetPoint ( self.castBar , " bottomright " , self , " bottomright " , 0 , 0 , 1 , 1 )
PixelUtil.SetHeight ( self.castBar , self.Settings . CastBarHeight , 1 )
end ,
SetHealthBarColor = function ( self , r , g , b , a )
self.healthBar : SetColor ( r , g , b , a )
end ,
--register all events which will be used by the unit frame
RegisterEvents = function ( self )
--register events
for index , eventTable in ipairs ( self.UnitFrameEvents ) do
local event , isUnitEvent = unpack ( eventTable )
if ( not isUnitEvent ) then
self : RegisterEvent ( event )
else
self : RegisterUnitEvent ( event , self.unit , self.displayedUnit ~= unit and self.displayedUnit or nil )
end
end
--check settings and unregister events for disabled features
if ( not self.Settings . ColorByAggro ) then
self : UnregisterEvent ( " UNIT_THREAT_LIST_UPDATE " )
end
--set scripts
self : SetScript ( " OnEvent " , self.OnEvent )
self : SetScript ( " OnHide " , self.OnHide )
if ( self.Settings . CanTick ) then
self : SetScript ( " OnUpdate " , self.OnTick )
end
end ,
--unregister events, called when this unit frame losses its unit
UnregisterEvents = function ( self )
for index , eventTable in ipairs ( self.UnitFrameEvents ) do
local event , firstUnit , secondUnit = unpack ( eventTable )
self : UnregisterEvent ( event )
end
self : SetScript ( " OnEvent " , nil )
self : SetScript ( " OnUpdate " , nil )
self : SetScript ( " OnHide " , nil )
end ,
--call every tick
OnTick = function ( self , deltaTime ) end , --if overrided, set 'CanTick' to true on the settings table
--when an event happen for this unit, send it to the apropriate function
OnEvent = function ( self , event , ... )
--run the function for this event
local eventFunc = self [ event ]
if ( eventFunc ) then
--is this event an unit event?
if ( self.IsUnitEvent [ event ] ) then
local unit = ...
--check if is for this unit (even if the event is registered only for the unit)
if ( unit == self.unit or unit == self.displayedUnit ) then
eventFunc ( self , ... )
end
else
eventFunc ( self , ... )
end
end
end ,
OnHide = function ( self )
if ( self.Settings . ClearUnitOnHide ) then
self : SetUnit ( nil )
end
end ,
--run if the unit currently shown is different than the new one
SetUnit = function ( self , unit )
if ( unit ~= self.unit or unit == nil ) then
self.unit = unit --absolute unit
self.displayedUnit = unit --~todo rename to 'displayedUnit' for back compatibility with older scripts in Plater
self.unitInVehicle = nil --true when the unit is in a vehicle
if ( unit ) then
self : RegisterEvents ( )
self.healthBar : SetUnit ( unit , self.displayedUnit )
--is using castbars?
if ( self.Settings . ShowCastBar ) then
self.castBar : SetUnit ( unit , self.displayedUnit )
else
self.castBar : SetUnit ( nil )
end
--is using powerbars?
if ( self.Settings . ShowPowerBar ) then
self.powerBar : SetUnit ( unit , self.displayedUnit )
else
self.powerBar : SetUnit ( nil )
end
--is using the border?
if ( self.Settings . ShowBorder ) then
self.border : Show ( )
else
self.border : Hide ( )
end
if ( not self.Settings . ShowUnitName ) then
self.unitName : Hide ( )
end
else
self : UnregisterEvents ( )
self.healthBar : SetUnit ( nil )
self.castBar : SetUnit ( nil )
self.powerBar : SetUnit ( nil )
end
self : UpdateUnitFrame ( )
end
end ,
--if the unit is controlling a vehicle, need to show the vehicle instead
--.unit and .displayedUnit is always the same execept when the unit is controlling a vehicle, then .displayedUnit is the unitID for the vehicle
--todo: see what 'UnitTargetsVehicleInRaidUI' is, there's a call for this in the CompactUnitFrame.lua but zero documentation
CheckVehiclePossession = function ( self )
--this unit is possessing a vehicle?
local unitPossessVehicle = ( IS_WOW_PROJECT_MAINLINE ) and UnitHasVehicleUI ( self.unit ) or false
if ( unitPossessVehicle ) then
if ( not self.unitInVehicle ) then
if ( UnitIsUnit ( " player " , self.unit ) ) then
self.displayedUnit = " vehicle "
self.unitInVehicle = true
self : RegisterEvents ( )
self : UpdateAllWidgets ( )
return true
end
local prefix , id , suffix = string.match ( self.unit , " ([^%d]+)([%d]*)(.*) " ) --CompactUnitFrame.lua
local vehicleUnitID = prefix .. " pet " .. id .. suffix
if ( UnitExists ( vehicleUnitID ) ) then
self.displayedUnit = vehicleUnitID
self.unitInVehicle = true
self : RegisterEvents ( )
self : UpdateAllWidgets ( )
return true
end
end
end
if ( self.unitInVehicle ) then
self.displayedUnit = self.unit
self.unitInVehicle = nil
self : RegisterEvents ( )
self : UpdateAllWidgets ( )
end
end ,
--find a color for the health bar, if a color has been passed in the arguments use it instead, 'CanModifyHealhBarColor' must be true for this function run
UpdateHealthColor = function ( self , r , g , b )
--check if color changes is disabled
if ( not self.Settings . CanModifyHealhBarColor ) then
return
end
local unit = self.displayedUnit
--check if a color has been passed within the parameters
if ( r ) then
--check if passed a special color
if ( type ( r ) ~= " number " ) then
r , g , b = detailsFramework : ParseColors ( r )
end
self : SetHealthBarColor ( r , g , b )
return
end
--check if there is a color override in the settings
if ( self.Settings . FixedHealthColor ) then
local FixedHealthColor = self.Settings . FixedHealthColor
r , g , b = FixedHealthColor.r , FixedHealthColor.g , FixedHealthColor.b
self : SetHealthBarColor ( r , g , b )
return
end
--check if the unit is a player
if ( UnitIsPlayer ( unit ) ) then
--check if the unit is disconnected (in case it is a player
if ( not UnitIsConnected ( unit ) ) then
self : SetHealthBarColor ( .5 , .5 , .5 )
return
end
--is a friendly or enemy player?
if ( UnitIsFriend ( " player " , unit ) ) then
if ( self.Settings . UseFriendlyClassColor ) then
local _ , className = UnitClass ( unit )
if ( className ) then
local classColor = RAID_CLASS_COLORS [ className ]
if ( classColor ) then
self : SetHealthBarColor ( classColor.r , classColor.g , classColor.b )
return
end
end
else
self : SetHealthBarColor ( 0 , 1 , 0 )
return
end
else
if ( self.Settings . UseEnemyClassColor ) then
local _ , className = UnitClass ( unit )
if ( className ) then
local classColor = RAID_CLASS_COLORS [ className ]
if ( classColor ) then
self : SetHealthBarColor ( classColor.r , classColor.g , classColor.b )
return
end
end
else
self : SetHealthBarColor ( 1 , 0 , 0 )
return
end
end
end
--is tapped?
if ( isUnitTapDenied ( unit ) ) then
self : SetHealthBarColor ( .6 , .6 , .6 )
return
end
--is this is a npc attacking the player?
if ( self.Settings . ColorByAggro ) then
local _ , threatStatus = UnitDetailedThreatSituation ( " player " , unit )
if ( threatStatus ) then
self : SetHealthBarColor ( 1 , 0 , 0 )
return
end
end
-- get the regular color by selection
r , g , b = UnitSelectionColor ( unit )
self : SetHealthBarColor ( r , g , b )
end ,
--misc
UpdateName = function ( self )
if ( not self.Settings . ShowUnitName ) then
return
end
--unit name without realm names by default
local name = UnitName ( self.unit )
self.unitName : SetText ( name )
self.unitName : Show ( )
end ,
--this runs when the player it self changes its target, need to update the current target overlay
--todo: add focus overlay
UpdateTargetOverlay = function ( self )
if ( not self.Settings . ShowTargetOverlay ) then
self.targetOverlay : Hide ( )
return
end
if ( UnitIsUnit ( self.displayedUnit , " target " ) ) then
self.targetOverlay : Show ( )
else
self.targetOverlay : Hide ( )
end
end ,
UpdateAllWidgets = function ( self )
if ( UnitExists ( self.displayedUnit ) ) then
local unit = self.unit
local displayedUnit = self.displayedUnit
self : SetUnit ( unit , displayedUnit )
--is using castbars?
if ( self.Settings . ShowCastBar ) then
self.castBar : SetUnit ( unit , displayedUnit )
end
--is using powerbars?
if ( self.Settings . ShowPowerBar ) then
self.powerBar : SetUnit ( unit , displayedUnit )
end
self : UpdateName ( )
self : UpdateTargetOverlay ( )
self : UpdateHealthColor ( )
end
end ,
--update the unit frame and its widgets
UpdateUnitFrame = function ( self )
local unitInVehicle = self : CheckVehiclePossession ( )
--if the unit is inside a vehicle, the vehicle possession function will call an update on all widgets
if ( not unitInVehicle ) then
self : UpdateAllWidgets ( )
end
end ,
--event handles
PLAYER_ENTERING_WORLD = function ( self , ... )
self : UpdateUnitFrame ( )
end ,
--update overlays when the player changes its target
PLAYER_TARGET_CHANGED = function ( self , ... )
self : UpdateTargetOverlay ( )
end ,
--unit received a name update
UNIT_NAME_UPDATE = function ( self , ... )
self : UpdateName ( )
end ,
--this is registered only if .settings.ColorByAggro is true
UNIT_THREAT_LIST_UPDATE = function ( self , ... )
if ( self.Settings . ColorByAggro ) then
self : UpdateHealthColor ( )
end
end ,
--vehicle
UNIT_ENTERED_VEHICLE = function ( self , ... )
self : UpdateUnitFrame ( )
end ,
UNIT_EXITED_VEHICLE = function ( self , ... )
self : UpdateUnitFrame ( )
end ,
--pet
UNIT_PET = function ( self , ... )
self : UpdateUnitFrame ( )
end ,
--player connection
UNIT_CONNECTION = function ( self , ... )
if ( UnitIsConnected ( self.unit ) ) then
self : UpdateUnitFrame ( )
end
end ,
PARTY_MEMBER_ENABLE = function ( self , ... )
if ( UnitIsConnected ( self.unit ) ) then
self : UpdateName ( )
end
end ,
}
-- ~unitframe
local globalBaseFrameLevel = 1 -- to be increased + used across each new plate
function detailsFramework : CreateUnitFrame ( parent , name , unitFrameSettingsOverride , healthBarSettingsOverride , castBarSettingsOverride , powerBarSettingsOverride )
local parentName = name or ( " DetailsFrameworkUnitFrame " .. tostring ( math.random ( 1 , 100000000 ) ) )
--create the main unit frame
local mewUnitFrame = CreateFrame ( " button " , parentName , parent , " BackdropTemplate " )
--base level
--local baseFrameLevel = f:GetFrameLevel()
local baseFrameLevel = globalBaseFrameLevel
globalBaseFrameLevel = globalBaseFrameLevel + 50
mewUnitFrame : SetFrameLevel ( baseFrameLevel )
--create the healthBar
local healthBar = detailsFramework : CreateHealthBar ( mewUnitFrame , false , healthBarSettingsOverride )
healthBar : SetFrameLevel ( baseFrameLevel + 1 )
mewUnitFrame.healthBar = healthBar
--create the power bar
local powerBar = detailsFramework : CreatePowerBar ( mewUnitFrame , false , powerBarSettingsOverride )
powerBar : SetFrameLevel ( baseFrameLevel + 2 )
mewUnitFrame.powerBar = powerBar
--create the castBar
local castBar = detailsFramework : CreateCastBar ( mewUnitFrame , false , castBarSettingsOverride )
castBar : SetFrameLevel ( baseFrameLevel + 3 )
mewUnitFrame.castBar = castBar
--border frame
local borderFrame = detailsFramework : CreateBorderFrame ( mewUnitFrame , mewUnitFrame : GetName ( ) .. " Border " )
borderFrame : SetFrameLevel ( mewUnitFrame : GetFrameLevel ( ) + 5 )
mewUnitFrame.border = borderFrame
--overlay frame (widgets that need to stay above the unit frame)
local overlayFrame = CreateFrame ( " frame " , " $parentOverlayFrame " , mewUnitFrame , " BackdropTemplate " )
overlayFrame : SetFrameLevel ( mewUnitFrame : GetFrameLevel ( ) + 6 )
mewUnitFrame.overlayFrame = overlayFrame
--unit frame layers
do
--artwork
mewUnitFrame.unitName = mewUnitFrame : CreateFontString ( nil , " artwork " , " GameFontHighlightSmall " )
PixelUtil.SetPoint ( mewUnitFrame.unitName , " topleft " , healthBar , " topleft " , 2 , - 2 , 1 , 1 )
--target overlay - it's parented in the healthbar so other widgets won't get the overlay
mewUnitFrame.targetOverlay = overlayFrame : CreateTexture ( nil , " artwork " )
mewUnitFrame.targetOverlay : SetTexture ( healthBar : GetTexture ( ) )
mewUnitFrame.targetOverlay : SetBlendMode ( " ADD " )
mewUnitFrame.targetOverlay : SetAlpha ( .5 )
mewUnitFrame.targetOverlay : SetAllPoints ( healthBar )
end
--mixins
--inject mixins
detailsFramework : Mixin ( mewUnitFrame , detailsFramework.UnitFrameFunctions )
--create the settings table and copy the overrides into it, the table is set into the frame after the mixin
local unitFrameSettings = detailsFramework.table . copy ( { } , detailsFramework.UnitFrameFunctions . Settings )
if ( unitFrameSettingsOverride ) then
unitFrameSettings = detailsFramework.table . copy ( unitFrameSettings , unitFrameSettingsOverride )
end
mewUnitFrame.Settings = unitFrameSettings
--initialize scripts
--unitframe
mewUnitFrame : Initialize ( )
return mewUnitFrame
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--horizontal scroll frame
local timeline_options = {
width = 400 ,
height = 700 ,
line_height = 20 ,
line_padding = 1 ,
show_elapsed_timeline = true ,
elapsed_timeline_height = 20 ,
--space to put the player/spell name and icons
header_width = 150 ,
--how many pixels will be use to represent 1 second
pixels_per_second = 20 ,
scale_min = 0.15 ,
scale_max = 1 ,
backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
backdrop_color = { 0 , 0 , 0 , 0.2 } ,
backdrop_color_highlight = { .2 , .2 , .2 , 0.4 } ,
backdrop_border_color = { 0.1 , 0.1 , 0.1 , .2 } ,
slider_backdrop = { edgeFile = [[Interface\Buttons\WHITE8X8]] , edgeSize = 1 , bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
slider_backdrop_color = { 0 , 0 , 0 , 0.2 } ,
slider_backdrop_border_color = { 0.1 , 0.1 , 0.1 , .2 } ,
title_template = " ORANGE_FONT_TEMPLATE " ,
text_tempate = " OPTIONS_FONT_TEMPLATE " ,
on_enter = function ( self )
self : SetBackdropColor ( unpack ( self.backdrop_color_highlight ) )
end ,
on_leave = function ( self )
self : SetBackdropColor ( unpack ( self.backdrop_color ) )
end ,
block_on_enter = function ( self )
end ,
block_on_leave = function ( self )
end ,
}
local elapsedtime_frame_options = {
backdrop = { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
backdrop_color = { .3 , .3 , .3 , .7 } ,
text_color = { 1 , 1 , 1 , 1 } ,
text_size = 12 ,
text_font = " Arial Narrow " ,
text_outline = " NONE " ,
height = 20 ,
distance = 200 , --distance in pixels between each label informing the time
distance_min = 50 , --minimum distance in pixels
draw_line = true , --if true it'll draw a vertical line to represent a segment
draw_line_color = { 1 , 1 , 1 , 0.2 } ,
draw_line_thickness = 1 ,
}
detailsFramework.TimeLineElapsedTimeFunctions = {
--get a label and update its appearance
GetLabel = function ( self , index )
local label = self.labels [ index ]
if ( not label ) then
label = self : CreateFontString ( nil , " artwork " , " GameFontNormal " )
label.line = self : CreateTexture ( nil , " artwork " )
label.line : SetColorTexture ( 1 , 1 , 1 )
label.line : SetPoint ( " topleft " , label , " bottomleft " , 0 , - 2 )
self.labels [ index ] = label
end
detailsFramework : SetFontColor ( label , self.options . text_color )
detailsFramework : SetFontSize ( label , self.options . text_size )
detailsFramework : SetFontFace ( label , self.options . text_font )
detailsFramework : SetFontOutline ( label , self.options . text_outline )
if ( self.options . draw_line ) then
label.line : SetVertexColor ( unpack ( self.options . draw_line_color ) )
label.line : SetWidth ( self.options . draw_line_thickness )
label.line : Show ( )
else
label.line : Hide ( )
end
return label
end ,
Reset = function ( self )
for i = 1 , # self.labels do
self.labels [ i ] : Hide ( )
end
end ,
Refresh = function ( self , elapsedTime , scale )
local parent = self : GetParent ( )
self : SetHeight ( self.options . height )
local effectiveArea = self : GetWidth ( ) --already scaled down width
local pixelPerSecond = elapsedTime / effectiveArea --how much 1 pixels correlate to time
local distance = self.options . distance --pixels between each segment
local minDistance = self.options . distance_min --min pixels between each segment
--scale the distance between each label showing the time with the parent's scale
distance = distance * scale
distance = max ( distance , minDistance )
local amountSegments = ceil ( effectiveArea / distance )
for i = 1 , amountSegments do
local label = self : GetLabel ( i )
local xOffset = distance * ( i - 1 )
label : SetPoint ( " left " , self , " left " , xOffset , 0 )
local secondsOfTime = pixelPerSecond * xOffset
label : SetText ( detailsFramework : IntegerToTimer ( floor ( secondsOfTime ) ) )
if ( label.line : IsShown ( ) ) then
label.line : SetHeight ( parent : GetParent ( ) : GetHeight ( ) )
end
label : Show ( )
end
end ,
}
--creates a frame to show the elapsed time in a row
function detailsFramework : CreateElapsedTimeFrame ( parent , name , options )
local elapsedTimeFrame = CreateFrame ( " frame " , name , parent , " BackdropTemplate " )
detailsFramework : Mixin ( elapsedTimeFrame , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( elapsedTimeFrame , detailsFramework.LayoutFrame )
detailsFramework : Mixin ( elapsedTimeFrame , detailsFramework.TimeLineElapsedTimeFunctions )
elapsedTimeFrame : BuildOptionsTable ( elapsedtime_frame_options , options )
elapsedTimeFrame : SetBackdrop ( elapsedTimeFrame.options . backdrop )
elapsedTimeFrame : SetBackdropColor ( unpack ( elapsedTimeFrame.options . backdrop_color ) )
elapsedTimeFrame.labels = { }
return elapsedTimeFrame
end
detailsFramework.TimeLineBlockFunctions = {
--self is the line
SetBlock = function ( self , index , blockInfo )
--get the block information
--see what is the current scale
--adjust the block position
local block = self : GetBlock ( index )
--need:
--the total time of the timeline
--the current scale of the timeline
--the elapsed time of this block
--icon of the block
--text
--background color
end ,
SetBlocksFromData = function ( self )
local parent = self : GetParent ( ) : GetParent ( )
local data = parent.data
local defaultColor = parent.defaultColor --guarantee to have a value
self : Show ( )
--none of these values are scaled, need to calculate
local pixelPerSecond = parent.pixelPerSecond
local totalLength = parent.totalLength
local scale = parent.currentScale
pixelPerSecond = pixelPerSecond * scale
local headerWidth = parent.headerWidth
--dataIndex stores which line index from the data this line will use
--lineData store members: .text .icon .timeline
local lineData = data.lines [ self.dataIndex ]
self.spellId = lineData.spellId
--if there's an icon, anchor the text at the right side of the icon
--this is the title and icon of the title
if ( lineData.icon ) then
self.icon : SetTexture ( lineData.icon )
if ( lineData.coords ) then
self.icon : SetTexCoord ( unpack ( lineData.coords ) )
else
self.icon : SetTexCoord ( .1 , .9 , .1 , .9 )
end
self.text : SetText ( lineData.text or " " )
self.text : SetPoint ( " left " , self.icon . widget , " right " , 2 , 0 )
else
self.icon : SetTexture ( nil )
self.text : SetText ( lineData.text or " " )
self.text : SetPoint ( " left " , self , " left " , 2 , 0 )
end
if ( self.dataIndex % 2 == 1 ) then
self : SetBackdropColor ( 0 , 0 , 0 , 0 )
else
local r , g , b , a = unpack ( self.backdrop_color )
self : SetBackdropColor ( r , g , b , a )
end
self : SetWidth ( 5000 )
local timelineData = lineData.timeline
local spellId = lineData.spellId
local useIconOnBlock = data.useIconOnBlocks
local baseFrameLevel = parent : GetFrameLevel ( ) + 10
for i = 1 , # timelineData do
local blockInfo = timelineData [ i ]
local timeInSeconds = blockInfo [ 1 ]
local length = blockInfo [ 2 ]
local isAura = blockInfo [ 3 ]
local auraDuration = blockInfo [ 4 ]
local blockSpellId = blockInfo [ 5 ]
local payload = blockInfo.payload
local xOffset = pixelPerSecond * timeInSeconds
local width = pixelPerSecond * length
if ( timeInSeconds < - 0.2 ) then
xOffset = xOffset / 2.5
end
local block = self : GetBlock ( i )
block : Show ( )
block : SetFrameLevel ( baseFrameLevel + i )
PixelUtil.SetPoint ( block , " left " , self , " left " , xOffset + headerWidth , 0 )
block.info . spellId = blockSpellId or spellId
block.info . time = timeInSeconds
block.info . duration = auraDuration
block.info . payload = payload
if ( useIconOnBlock ) then
local iconTexture = lineData.icon
if ( blockSpellId ) then
iconTexture = GetSpellTexture ( blockSpellId )
end
block.icon : SetTexture ( iconTexture )
block.icon : SetTexCoord ( .1 , .9 , .1 , .9 )
block.icon : SetAlpha ( .834 )
block.icon : SetSize ( self : GetHeight ( ) , self : GetHeight ( ) )
if ( timeInSeconds < - 0.2 ) then
block.icon : SetDesaturated ( true )
else
block.icon : SetDesaturated ( false )
end
PixelUtil.SetSize ( block , self : GetHeight ( ) , self : GetHeight ( ) )
if ( isAura ) then
block.auraLength : Show ( )
block.auraLength : SetWidth ( pixelPerSecond * isAura )
block : SetWidth ( max ( pixelPerSecond * isAura , 16 ) )
else
block.auraLength : Hide ( )
end
block.background : SetVertexColor ( 0 , 0 , 0 , 0 )
else
block.background : SetVertexColor ( 0 , 0 , 0 , 0 )
PixelUtil.SetSize ( block , max ( width , 16 ) , self : GetHeight ( ) )
block.auraLength : Hide ( )
end
end
end ,
GetBlock = function ( self , index )
local block = self.blocks [ index ]
if ( not block ) then
block = CreateFrame ( " frame " , nil , self , " BackdropTemplate " )
self.blocks [ index ] = block
local background = block : CreateTexture ( nil , " background " )
background : SetColorTexture ( 1 , 1 , 1 , 1 )
local icon = block : CreateTexture ( nil , " artwork " )
local text = block : CreateFontString ( nil , " artwork " )
local auraLength = block : CreateTexture ( nil , " border " )
background : SetAllPoints ( )
icon : SetPoint ( " left " )
text : SetPoint ( " left " , icon , " left " , 2 , 0 )
auraLength : SetPoint ( " topleft " , icon , " topleft " , 0 , 0 )
auraLength : SetPoint ( " bottomleft " , icon , " bottomleft " , 0 , 0 )
auraLength : SetColorTexture ( 1 , 1 , 1 , 1 )
auraLength : SetVertexColor ( 1 , 1 , 1 , 0.1 )
block.icon = icon
block.text = text
block.background = background
block.auraLength = auraLength
block : SetScript ( " OnEnter " , self : GetParent ( ) : GetParent ( ) . options.block_on_enter )
block : SetScript ( " OnLeave " , self : GetParent ( ) : GetParent ( ) . options.block_on_leave )
block : SetMouseClickEnabled ( false )
block.info = { }
end
return block
end ,
Reset = function ( self )
--attention, it doesn't reset icon texture, text and background color
for i = 1 , # self.blocks do
self.blocks [ i ] : Hide ( )
end
self : Hide ( )
end ,
}
detailsFramework.TimeLineFunctions = {
GetLine = function ( self , index )
local line = self.lines [ index ]
if ( not line ) then
--create a new line
line = CreateFrame ( " frame " , " $parentLine " .. index , self.body , " BackdropTemplate " )
detailsFramework : Mixin ( line , detailsFramework.TimeLineBlockFunctions )
self.lines [ index ] = line
local lineHeader = CreateFrame ( " frame " , nil , line , " BackdropTemplate " )
lineHeader : SetPoint ( " topleft " , line , " topleft " , 0 , 0 )
lineHeader : SetPoint ( " bottomleft " , line , " bottomleft " , 0 , 0 )
lineHeader : SetScript ( " OnEnter " , self.options . header_on_enter )
lineHeader : SetScript ( " OnLeave " , self.options . header_on_leave )
line.lineHeader = lineHeader
--store the individual textures that shows the timeline information
line.blocks = { }
line.SetBlock = detailsFramework.TimeLineBlockFunctions . SetBlock
line.GetBlock = detailsFramework.TimeLineBlockFunctions . GetBlock
--set its parameters
if ( self.options . show_elapsed_timeline ) then
line : SetPoint ( " topleft " , self.body , " topleft " , 1 , - ( ( index - 1 ) * ( self.options . line_height + 1 ) ) - 2 - self.options . elapsed_timeline_height )
else
line : SetPoint ( " topleft " , self.body , " topleft " , 1 , - ( ( index - 1 ) * ( self.options . line_height + 1 ) ) - 1 )
end
line : SetSize ( 1 , self.options . line_height ) --width is set when updating the frame
line : SetScript ( " OnEnter " , self.options . on_enter )
line : SetScript ( " OnLeave " , self.options . on_leave )
line : SetMouseClickEnabled ( false )
line : SetBackdrop ( self.options . backdrop )
line : SetBackdropColor ( unpack ( self.options . backdrop_color ) )
line : SetBackdropBorderColor ( unpack ( self.options . backdrop_border_color ) )
local icon = detailsFramework : CreateImage ( line , " " , self.options . line_height , self.options . line_height )
icon : SetPoint ( " left " , line , " left " , 2 , 0 )
line.icon = icon
local text = detailsFramework : CreateLabel ( line , " " , detailsFramework : GetTemplate ( " font " , self.options . title_template ) )
text : SetPoint ( " left " , icon.widget , " right " , 2 , 0 )
line.text = text
line.backdrop_color = self.options . backdrop_color or { .1 , .1 , .1 , .3 }
line.backdrop_color_highlight = self.options . backdrop_color_highlight or { .3 , .3 , .3 , .5 }
end
return line
end ,
ResetAllLines = function ( self )
for i = 1 , # self.lines do
self.lines [ i ] : Reset ( )
end
end ,
AdjustScale = function ( self , index )
end ,
--todo
--make the on enter and leave tooltips
--set icons and texts
--skin the sliders
RefreshTimeLine = function ( self )
--debug
--self.currentScale = 1
--calculate the total width
local pixelPerSecond = self.options . pixels_per_second
local totalLength = self.data . length or 1
local currentScale = self.currentScale
self.scaleSlider : Enable ( )
--how many pixels represent 1 second
local bodyWidth = totalLength * pixelPerSecond * currentScale
self.body : SetWidth ( bodyWidth + self.options . header_width )
self.body . effectiveWidth = bodyWidth
--reduce the default canvas size from the body with and don't allow the max value be negative
local newMaxValue = max ( bodyWidth - ( self : GetWidth ( ) - self.options . header_width ) , 0 )
--adjust the scale slider range
local oldMin , oldMax = self.horizontalSlider : GetMinMaxValues ( )
self.horizontalSlider : SetMinMaxValues ( 0 , newMaxValue )
self.horizontalSlider : SetValue ( detailsFramework : MapRangeClamped ( oldMin , oldMax , 0 , newMaxValue , self.horizontalSlider : GetValue ( ) ) )
local defaultColor = self.data . defaultColor or { 1 , 1 , 1 , 1 }
--cache values
self.pixelPerSecond = pixelPerSecond
self.totalLength = totalLength
self.defaultColor = defaultColor
self.headerWidth = self.options . header_width
--calculate the total height
local lineHeight = self.options . line_height
local linePadding = self.options . line_padding
local bodyHeight = ( lineHeight + linePadding ) * # self.data . lines
self.body : SetHeight ( bodyHeight )
self.verticalSlider : SetMinMaxValues ( 0 , max ( bodyHeight - self : GetHeight ( ) , 0 ) )
self.verticalSlider : SetValue ( 0 )
--refresh lines
self : ResetAllLines ( )
for i = 1 , # self.data . lines do
local line = self : GetLine ( i )
line.dataIndex = i --this index is used inside the line update function to know which data to get
line.lineHeader : SetWidth ( self.options . header_width )
line : SetBlocksFromData ( ) --the function to update runs within the line object
end
--refresh elapsed time frame
--the elapsed frame must have a width before the refresh function is called
self.elapsedTimeFrame : ClearAllPoints ( )
self.elapsedTimeFrame : SetPoint ( " topleft " , self.body , " topleft " , self.options . header_width , 0 )
self.elapsedTimeFrame : SetPoint ( " topright " , self.body , " topright " , 0 , 0 )
self.elapsedTimeFrame : Reset ( )
self.elapsedTimeFrame : Refresh ( self.data . length , self.currentScale )
end ,
SetData = function ( self , data )
self.data = data
self : RefreshTimeLine ( )
end ,
}
--creates a regular scroll in horizontal position
function detailsFramework : CreateTimeLineFrame ( parent , name , options , timelineOptions )
local width = options and options.width or timeline_options.width
local height = options and options.height or timeline_options.height
local scrollWidth = 800 --placeholder until the timeline receives data
local scrollHeight = 800 --placeholder until the timeline receives data
local frameCanvas = CreateFrame ( " scrollframe " , name , parent , " BackdropTemplate " )
detailsFramework : Mixin ( frameCanvas , detailsFramework.TimeLineFunctions )
detailsFramework : Mixin ( frameCanvas , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( frameCanvas , detailsFramework.LayoutFrame )
frameCanvas.data = { }
frameCanvas.lines = { }
frameCanvas.currentScale = 0.5
frameCanvas : SetSize ( width , height )
detailsFramework : ApplyStandardBackdrop ( frameCanvas )
local frameBody = CreateFrame ( " frame " , nil , frameCanvas , " BackdropTemplate " )
frameBody : SetSize ( scrollWidth , scrollHeight )
frameCanvas : SetScrollChild ( frameBody )
frameCanvas.body = frameBody
frameCanvas : BuildOptionsTable ( timeline_options , options )
--create elapsed time frame
frameCanvas.elapsedTimeFrame = detailsFramework : CreateElapsedTimeFrame ( frameBody , frameCanvas : GetName ( ) and frameCanvas : GetName ( ) .. " ElapsedTimeFrame " , timelineOptions )
--create horizontal slider
local horizontalSlider = CreateFrame ( " slider " , frameCanvas : GetName ( ) .. " HorizontalSlider " , parent , " BackdropTemplate " )
horizontalSlider.bg = horizontalSlider : CreateTexture ( nil , " background " )
horizontalSlider.bg : SetAllPoints ( true )
horizontalSlider.bg : SetTexture ( 0 , 0 , 0 , 0.5 )
frameCanvas.horizontalSlider = horizontalSlider
horizontalSlider : SetBackdrop ( frameCanvas.options . slider_backdrop )
horizontalSlider : SetBackdropColor ( unpack ( frameCanvas.options . slider_backdrop_color ) )
horizontalSlider : SetBackdropBorderColor ( unpack ( frameCanvas.options . slider_backdrop_border_color ) )
horizontalSlider.thumb = horizontalSlider : CreateTexture ( nil , " OVERLAY " )
horizontalSlider.thumb : SetTexture ( " Interface \\ Buttons \\ UI-ScrollBar-Knob " )
horizontalSlider.thumb : SetSize ( 24 , 24 )
horizontalSlider.thumb : SetVertexColor ( 0.6 , 0.6 , 0.6 , 0.95 )
horizontalSlider : SetThumbTexture ( horizontalSlider.thumb )
horizontalSlider : SetOrientation ( " horizontal " )
horizontalSlider : SetSize ( width + 20 , 20 )
horizontalSlider : SetPoint ( " topleft " , frameCanvas , " bottomleft " )
horizontalSlider : SetMinMaxValues ( 0 , scrollWidth )
horizontalSlider : SetValue ( 0 )
horizontalSlider : SetScript ( " OnValueChanged " , function ( self )
local _ , maxValue = horizontalSlider : GetMinMaxValues ( )
local stepValue = ceil ( ceil ( self : GetValue ( ) * maxValue ) / max ( maxValue , SMALL_FLOAT ) )
if ( stepValue ~= horizontalSlider.currentValue ) then
horizontalSlider.currentValue = stepValue
frameCanvas : SetHorizontalScroll ( stepValue )
end
end )
--create scale slider
local scaleSlider = CreateFrame ( " slider " , frameCanvas : GetName ( ) .. " ScaleSlider " , parent , " BackdropTemplate " )
scaleSlider.bg = scaleSlider : CreateTexture ( nil , " background " )
scaleSlider.bg : SetAllPoints ( true )
scaleSlider.bg : SetTexture ( 0 , 0 , 0 , 0.5 )
scaleSlider : Disable ( )
frameCanvas.scaleSlider = scaleSlider
scaleSlider : SetBackdrop ( frameCanvas.options . slider_backdrop )
scaleSlider : SetBackdropColor ( unpack ( frameCanvas.options . slider_backdrop_color ) )
scaleSlider : SetBackdropBorderColor ( unpack ( frameCanvas.options . slider_backdrop_border_color ) )
scaleSlider.thumb = scaleSlider : CreateTexture ( nil , " OVERLAY " )
scaleSlider.thumb : SetTexture ( " Interface \\ Buttons \\ UI-ScrollBar-Knob " )
scaleSlider.thumb : SetSize ( 24 , 24 )
scaleSlider.thumb : SetVertexColor ( 0.6 , 0.6 , 0.6 , 0.95 )
scaleSlider : SetThumbTexture ( scaleSlider.thumb )
scaleSlider : SetOrientation ( " horizontal " )
scaleSlider : SetSize ( width + 20 , 20 )
scaleSlider : SetPoint ( " topleft " , horizontalSlider , " bottomleft " , 0 , - 2 )
scaleSlider : SetMinMaxValues ( frameCanvas.options . scale_min , frameCanvas.options . scale_max )
scaleSlider : SetValue ( detailsFramework : GetRangeValue ( frameCanvas.options . scale_min , frameCanvas.options . scale_max , 0.5 ) )
scaleSlider : SetScript ( " OnValueChanged " , function ( self )
local stepValue = ceil ( self : GetValue ( ) * 100 ) / 100
if ( stepValue ~= frameCanvas.currentScale ) then
local current = stepValue
frameCanvas.currentScale = stepValue
frameCanvas : RefreshTimeLine ( )
end
end )
--create vertical slider
local verticalSlider = CreateFrame ( " slider " , frameCanvas : GetName ( ) .. " VerticalSlider " , parent , " BackdropTemplate " )
verticalSlider.bg = verticalSlider : CreateTexture ( nil , " background " )
verticalSlider.bg : SetAllPoints ( true )
verticalSlider.bg : SetTexture ( 0 , 0 , 0 , 0.5 )
frameCanvas.verticalSlider = verticalSlider
verticalSlider : SetBackdrop ( frameCanvas.options . slider_backdrop )
verticalSlider : SetBackdropColor ( unpack ( frameCanvas.options . slider_backdrop_color ) )
verticalSlider : SetBackdropBorderColor ( unpack ( frameCanvas.options . slider_backdrop_border_color ) )
verticalSlider.thumb = verticalSlider : CreateTexture ( nil , " OVERLAY " )
verticalSlider.thumb : SetTexture ( " Interface \\ Buttons \\ UI-ScrollBar-Knob " )
verticalSlider.thumb : SetSize ( 24 , 24 )
verticalSlider.thumb : SetVertexColor ( 0.6 , 0.6 , 0.6 , 0.95 )
verticalSlider : SetThumbTexture ( verticalSlider.thumb )
verticalSlider : SetOrientation ( " vertical " )
verticalSlider : SetSize ( 20 , height - 2 )
verticalSlider : SetPoint ( " topleft " , frameCanvas , " topright " , 0 , 0 )
verticalSlider : SetMinMaxValues ( 0 , scrollHeight )
verticalSlider : SetValue ( 0 )
verticalSlider : SetScript ( " OnValueChanged " , function ( self )
frameCanvas : SetVerticalScroll ( self : GetValue ( ) )
end )
--mouse scroll
frameCanvas : EnableMouseWheel ( true )
frameCanvas : SetScript ( " OnMouseWheel " , function ( self , delta )
local minValue , maxValue = horizontalSlider : GetMinMaxValues ( )
local currentHorizontal = horizontalSlider : GetValue ( )
if ( IsShiftKeyDown ( ) and delta < 0 ) then
local amountToScroll = frameBody : GetHeight ( ) / 20
verticalSlider : SetValue ( verticalSlider : GetValue ( ) + amountToScroll )
elseif ( IsShiftKeyDown ( ) and delta > 0 ) then
local amountToScroll = frameBody : GetHeight ( ) / 20
verticalSlider : SetValue ( verticalSlider : GetValue ( ) - amountToScroll )
elseif ( IsControlKeyDown ( ) and delta > 0 ) then
scaleSlider : SetValue ( min ( scaleSlider : GetValue ( ) + 0.1 , 1 ) )
elseif ( IsControlKeyDown ( ) and delta < 0 ) then
scaleSlider : SetValue ( max ( scaleSlider : GetValue ( ) - 0.1 , 0.15 ) )
elseif ( delta < 0 and currentHorizontal < maxValue ) then
local amountToScroll = frameBody : GetWidth ( ) / 20
horizontalSlider : SetValue ( currentHorizontal + amountToScroll )
elseif ( delta > 0 and maxValue > 1 ) then
local amountToScroll = frameBody : GetWidth ( ) / 20
horizontalSlider : SetValue ( currentHorizontal - amountToScroll )
end
end )
--mouse drag
frameBody : SetScript ( " OnMouseDown " , function ( self , button )
local x = GetCursorPosition ( )
self.MouseX = x
frameBody : SetScript ( " OnUpdate " , function ( self , deltaTime )
local x = GetCursorPosition ( )
local deltaX = self.MouseX - x
local current = horizontalSlider : GetValue ( )
horizontalSlider : SetValue ( current + ( deltaX * 1.2 ) * ( ( IsShiftKeyDown ( ) and 2 ) or ( IsAltKeyDown ( ) and 0.5 ) or 1 ) )
self.MouseX = x
end )
end )
frameBody : SetScript ( " OnMouseUp " , function ( self , button )
frameBody : SetScript ( " OnUpdate " , nil )
end )
return frameCanvas
end
--[=[
local f = CreateFrame ( " frame " , " TestFrame " , UIParent )
f : SetPoint ( " center " )
f : SetSize ( 900 , 420 )
f : SetBackdrop ( { bgFile = " Interface \\ Tooltips \\ UI-Tooltip-Background " , tile = true , tileSize = 16 , insets = { left = 1 , right = 1 , top = 0 , bottom = 1 } } )
local scroll = DF : CreateTimeLineFrame ( f , " $parentTimeLine " , { width = 880 , height = 400 } )
scroll : SetPoint ( " topleft " , f , " topleft " , 0 , 0 )
--need fake data to test fills
scroll : SetData ( {
length = 360 ,
defaultColor = { 1 , 1 , 1 , 1 } ,
lines = {
{ text = " player 1 " , icon = " " , timeline = {
--each table here is a block shown in the line
--is an indexed table with: [1] time [2] length [3] color (if false, use the default) [4] text [5] icon [6] tooltip: if number = spellID tooltip, if table is text lines
{ 1 , 10 } , { 13 , 11 } , { 25 , 7 } , { 36 , 5 } , { 55 , 18 } , { 76 , 30 } , { 105 , 20 } , { 130 , 11 } , { 155 , 11 } , { 169 , 7 } , { 199 , 16 } , { 220 , 18 } , { 260 , 10 } , { 290 , 23 } , { 310 , 30 } , { 350 , 10 }
}
} , --end of line 1
} ,
} )
f : Hide ( )
--scroll.body:SetScale(0.5)
--]=]
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--error message box
function detailsFramework : ShowErrorMessage ( errorMessage , titleText )
if ( not detailsFramework.ErrorMessagePanel ) then
local f = CreateFrame ( " frame " , " DetailsFrameworkErrorMessagePanel " , UIParent , " BackdropTemplate " )
f : SetSize ( 400 , 120 )
f : SetFrameStrata ( " FULLSCREEN " )
f : SetPoint ( " center " , UIParent , " center " , 0 , 100 )
f : EnableMouse ( true )
f : SetMovable ( true )
f : RegisterForDrag ( " LeftButton " )
f : SetScript ( " OnDragStart " , function ( ) f : StartMoving ( ) end )
f : SetScript ( " OnDragStop " , function ( ) f : StopMovingOrSizing ( ) end )
f : SetScript ( " OnMouseDown " , function ( self , button ) if ( button == " RightButton " ) then f : Hide ( ) end end )
tinsert ( UISpecialFrames , " DetailsFrameworkErrorMessagePanel " )
detailsFramework.ErrorMessagePanel = f
detailsFramework : CreateTitleBar ( f , " Details! Framework Error! " )
detailsFramework : ApplyStandardBackdrop ( f )
local errorLabel = f : CreateFontString ( nil , " overlay " , " GameFontNormal " )
errorLabel : SetPoint ( " top " , f , " top " , 0 , - 25 )
errorLabel : SetJustifyH ( " center " )
errorLabel : SetSize ( 360 , 66 )
f.errorLabel = errorLabel
local button_text_template = detailsFramework : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " )
local options_dropdown_template = detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local closeButton = detailsFramework : CreateButton ( f , nil , 60 , 20 , " close " , nil , nil , nil , nil , nil , nil , options_dropdown_template )
closeButton : SetPoint ( " bottom " , f , " bottom " , 0 , 5 )
f.closeButton = closeButton
closeButton : SetClickFunction ( function ( )
f : Hide ( )
end )
f.ShowAnimation = detailsFramework : CreateAnimationHub ( f , function ( )
f : SetBackdropBorderColor ( 0 , 0 , 0 , 0 )
f.TitleBar : SetBackdropBorderColor ( 0 , 0 , 0 , 0 )
end , function ( )
f : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
f.TitleBar : SetBackdropBorderColor ( 0 , 0 , 0 , 1 )
end )
detailsFramework : CreateAnimation ( f.ShowAnimation , " scale " , 1 , .075 , .2 , .2 , 1.1 , 1.1 , " center " , 0 , 0 )
detailsFramework : CreateAnimation ( f.ShowAnimation , " scale " , 2 , .075 , 1 , 1 , .90 , .90 , " center " , 0 , 0 )
f.FlashTexture = f : CreateTexture ( nil , " overlay " )
f.FlashTexture : SetColorTexture ( 1 , 1 , 1 , 1 )
f.FlashTexture : SetAllPoints ( )
f.FlashAnimation = detailsFramework : CreateAnimationHub ( f.FlashTexture , function ( ) f.FlashTexture : Show ( ) end , function ( ) f.FlashTexture : Hide ( ) end )
detailsFramework : CreateAnimation ( f.FlashAnimation , " alpha " , 1 , .075 , 0 , .05 )
detailsFramework : CreateAnimation ( f.FlashAnimation , " alpha " , 2 , .075 , .1 , 0 )
f : Hide ( )
end
detailsFramework.ErrorMessagePanel : Show ( )
detailsFramework.ErrorMessagePanel . errorLabel : SetText ( errorMessage )
detailsFramework.ErrorMessagePanel . TitleLabel : SetText ( titleText )
detailsFramework.ErrorMessagePanel . ShowAnimation : Play ( )
detailsFramework.ErrorMessagePanel . FlashAnimation : Play ( )
end
--[[
DF : SetPointOffsets ( frame , xOffset , yOffset )
Set an offset into the already existing offset of the frame
If passed xOffset : 1 and yOffset : 1 and the frame has 1 - 1 , the new offset will be 2 - 2
This function is great to create a 1 knob for distance
@ frame : a frame to have the offsets changed
@ xOffset : the amount to apply into the x offset
@ yOffset : the amount to apply into the y offset
--]]
function detailsFramework : SetPointOffsets ( frame , xOffset , yOffset )
for i = 1 , frame : GetNumPoints ( ) do
local anchor1 , anchorTo , anchor2 , x , y = frame : GetPoint ( i )
x = x or 0
y = y or 0
if ( x >= 0 ) then
xOffset = x + xOffset
elseif ( x < 0 ) then
xOffset = x - xOffset
end
if ( y >= 0 ) then
yOffset = y + yOffset
elseif ( y < 0 ) then
yOffset = y - yOffset
end
frame : SetPoint ( anchor1 , anchorTo , anchor2 , xOffset , yOffset )
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--list box
detailsFramework.ListboxFunctions = {
scrollRefresh = function ( self , data , offset , totalLines )
for i = 1 , totalLines do
local index = i + offset
local lineData = data [ index ] --what is shown in the textentries, array
if ( lineData ) then
local line = self : GetLine ( i )
line.dataIndex = index
line.deleteButton : SetClickFunction ( detailsFramework.ListboxFunctions . deleteEntry , data , index )
line.indexText : SetText ( index )
local amountEntries = # lineData
for o = 1 , amountEntries do
--data
local textEntry = line.widgets [ o ]
textEntry.dataTable = lineData
textEntry.dataTableIndex = o
local text = lineData [ o ]
textEntry : SetText ( text )
end
end
end
end ,
addEntry = function ( self )
local frameCanvas = self : GetParent ( )
local data = frameCanvas.data
local newEntry = { }
for i = 1 , frameCanvas.headerLength do
tinsert ( newEntry , " " )
end
tinsert ( data , newEntry )
frameCanvas.scrollBox : Refresh ( )
end ,
deleteEntry = function ( self , button , data , index )
tremove ( data , index )
--get the line, get the scrollframe
self : GetParent ( ) : GetParent ( ) : Refresh ( )
end ,
createScrollLine = function ( self , index )
local listBox = self : GetParent ( )
local line = CreateFrame ( " frame " , self : GetName ( ) .. " line_ " .. index , self , " BackdropTemplate " )
line : SetPoint ( " topleft " , self , " topleft " , 1 , - ( ( index - 1 ) * ( self.lineHeight + 1 ) ) - 1 )
line : SetSize ( self : GetWidth ( ) - 28 , self.lineHeight ) -- -28 space for the scrollbar
local options = listBox.options
line : SetBackdrop ( options.line_backdrop )
line : SetBackdropColor ( unpack ( options.line_backdrop_color ) )
line : SetBackdropBorderColor ( unpack ( options.line_backdrop_border_color ) )
detailsFramework : Mixin ( line , detailsFramework.HeaderFunctions )
line.widgets = { }
for i = 1 , ( listBox.headerLength + 2 ) do --+2 to add the delete button and index
local headerColumn = listBox.headerTable [ i ]
if ( headerColumn.isDelete ) then
local deleteButton = detailsFramework : CreateButton ( line , detailsFramework.ListboxFunctions . deleteEntry , 20 , self.lineHeight , " X " , listBox.data , index , nil , nil , nil , nil , detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " ) , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
line.deleteButton = deleteButton
line : AddFrameToHeaderAlignment ( deleteButton )
elseif ( headerColumn.isIndex ) then
local indexText = detailsFramework : CreateLabel ( line )
line.indexText = indexText
line : AddFrameToHeaderAlignment ( indexText )
elseif ( headerColumn.text ) then
local template = detailsFramework.table . copy ( { } , detailsFramework : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " ) )
template.backdropcolor = { .1 , .1 , .1 , .7 }
template.backdropbordercolor = { .2 , .2 , .2 , .6 }
local textEntry = detailsFramework : CreateTextEntry ( line , function ( ) end , headerColumn.width , self.lineHeight , nil , nil , nil , template )
textEntry : SetHook ( " OnEditFocusGained " , function ( ) textEntry : HighlightText ( 0 ) end )
textEntry : SetHook ( " OnEditFocusLost " , function ( )
textEntry : HighlightText ( 0 , 0 )
local text = textEntry.text
local dataTable = textEntry.dataTable
dataTable [ textEntry.dataTableIndex ] = text
end )
tinsert ( line.widgets , textEntry )
line : AddFrameToHeaderAlignment ( textEntry )
end
end
line : AlignWithHeader ( listBox.header , " left " )
return line
end ,
SetData = function ( frameCanvas , newData )
if ( type ( newData ) ~= " table " ) then
error ( " ListBox:SetData received an invalid newData on parameter 2. " )
return
end
frameCanvas.data = newData
frameCanvas.scrollBox : SetData ( newData )
frameCanvas.scrollBox : Refresh ( )
end ,
}
local listbox_options = {
width = 800 ,
height = 600 ,
auto_width = true ,
line_height = 16 ,
line_backdrop = { bgFile = [[Interface\Tooltips\UI-Tooltip-Background]] , tileSize = 64 , tile = true } ,
line_backdrop_color = { .1 , .1 , .1 , .6 } ,
line_backdrop_border_color = { 0 , 0 , 0 , .5 } ,
}
--@parent: parent frame
--@name: name of the frame to be created
--@data: table with current data to fill the column, this table are also used for values changed or added
--@options: table with options to overwrite the default setting from 'listbox_options'
--@header: a table to create a header widget
--@header_options: a table with options to overwrite the default header options
function detailsFramework : CreateListBox ( parent , name , data , options , headerTable , headerOptions )
options = options or { }
name = name or " ListboxUnamed_ " .. ( math.random ( 100000 , 1000000 ) )
--canvas
local frameCanvas = CreateFrame ( " scrollframe " , name , parent , " BackdropTemplate " )
detailsFramework : Mixin ( frameCanvas , detailsFramework.ListboxFunctions )
detailsFramework : Mixin ( frameCanvas , detailsFramework.OptionsFunctions )
detailsFramework : Mixin ( frameCanvas , detailsFramework.LayoutFrame )
frameCanvas.headerTable = headerTable
if ( not data or type ( data ) ~= " table " ) then
error ( " CreateListBox() parameter 3 'data' must be a table. " )
end
frameCanvas.data = data
frameCanvas.lines = { }
detailsFramework : ApplyStandardBackdrop ( frameCanvas )
frameCanvas : BuildOptionsTable ( listbox_options , options )
--header
--check for default values in the header
headerTable = headerTable or {
{ text = " Spell Id " , width = 70 } ,
{ text = " Spell Name " , width = 70 } ,
}
headerOptions = headerOptions or {
padding = 2 ,
}
--each header is an entry in the data, if the header has 4 indexes the data has sub tables with 4 indexes as well
frameCanvas.headerLength = # headerTable
--add the detele line column into the header frame
tinsert ( headerTable , 1 , { text = " # " , width = 20 , isIndex = true } ) --isDelete signals the createScrollLine() to make the delete button for the line
tinsert ( headerTable , { text = " Delete " , width = 50 , isDelete = true } ) --isDelete signals the createScrollLine() to make the delete button for the line
local header = detailsFramework : CreateHeader ( frameCanvas , headerTable , headerOptions )
--set the header point
header : SetPoint ( " topleft " , frameCanvas , " topleft " , 5 , - 5 )
frameCanvas.header = header
--auto size
if ( frameCanvas.options . auto_width ) then
local width = 10 --padding 5 on each side
width = width + 20 --scrollbar reserved space
local headerPadding = headerOptions.padding or 0
for _ , header in pairs ( headerTable ) do
if ( header.width ) then
width = width + header.width + headerPadding
end
end
frameCanvas.options . width = width
frameCanvas : SetWidth ( width )
end
local width = frameCanvas.options . width
local height = frameCanvas.options . height
frameCanvas : SetSize ( frameCanvas.options . width , height )
--scroll frame
local lineHeight = frameCanvas.options . line_height
--calc the size of the space occupied by the add button, header etc
local lineAmount = floor ( ( height - 60 ) / lineHeight )
-- -12 is padding: 5 on top, 7 bottom, 2 header scrollbar blank space | -24 to leave space to the add button
local scrollBox = detailsFramework : CreateScrollBox ( frameCanvas , " $parentScrollbox " , frameCanvas.scrollRefresh , data , width - 4 , height - header : GetHeight ( ) - 12 - 24 , lineAmount , lineHeight )
scrollBox : SetPoint ( " topleft " , header , " bottomleft " , 0 , - 2 )
scrollBox : SetPoint ( " topright " , header , " bottomright " , 0 , - 2 ) -- -20 for the scrollbar
detailsFramework : ReskinSlider ( scrollBox )
scrollBox.lineHeight = lineHeight
scrollBox.lineAmount = lineAmount
frameCanvas.scrollBox = scrollBox
for i = 1 , lineAmount do
scrollBox : CreateLine ( frameCanvas.createScrollLine )
end
scrollBox : Refresh ( )
--add line button
local addLineButton = detailsFramework : CreateButton ( frameCanvas , detailsFramework.ListboxFunctions . addEntry , 80 , 20 , " Add " , nil , nil , nil , nil , nil , nil , detailsFramework : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " ) , detailsFramework : GetTemplate ( " font " , " ORANGE_FONT_TEMPLATE " ) )
addLineButton : SetPoint ( " topleft " , scrollBox , " bottomleft " , 0 , - 4 )
return frameCanvas
end
--[=[ -- test case
local pframe = ListBoxTest or CreateFrame ( " frame " , " ListBoxTest " , UIParent )
pframe : SetSize ( 900 , 700 )
pframe : SetPoint ( " left " )
local data = { { 254154 , " spell name 1 " , 45 } , { 299154 , " spell name 2 " , 05 } , { 354154 , " spell name 3 " , 99 } }
local headerTable = {
{ text = " spell id " , width = 120 } ,
{ text = " spell name " , width = 180 } ,
{ text = " number " , width = 90 } ,
}
local listbox = DetailsFramework : CreateListBox ( pframe , " $parentlistbox " , data , nil , headerTable , nil )
listbox : SetPoint ( " topleft " , pframe , " topleft " , 10 , - 10 )
--]=]