--[[@TODO
Loadout and condition restrictions like character
Update condition filtering
Update set dropdowns to use sidebar filtering
New user UI , each tab should have a cleaner ui before creaitng a set
-- 1.0.0 breakpoint
Show restrictions for subsets within the loadout list ?
Equipment flyout
Equipment sets should store transmog ?
Loadout keybindings
Conditions need to support arena comp ?
Update new set text button based on tab ?
Set icons
Import / Export and custom links
When combining sets , adjust sets for the current player ,
eg moving essences because the character missing a ring / essence
Set save button ?
Show what will change when activating a condition
Zone Specific conditions
Conditions should support multiple bosses / affix combos ?
Conditions level support
Option to show minimap menu on mouse over
Trigger system for changing loadouts , run custom code when a set is changed ?
Duplicate sets button
] ]
local ADDON_NAME , Internal = ... ;
local L = Internal.L ;
local External = { }
_G [ ADDON_NAME ] = External
local GetCharacterInfo = Internal.GetCharacterInfo
local GetCharacterSlug = Internal.GetCharacterSlug
BTWLOADOUTS = ADDON_NAME
BTWLOADOUTS_LOADOUT = L [ " Loadout " ]
BTWLOADOUTS_LOADOUTS = L [ " Loadouts " ]
BTWLOADOUTS_TALENTS = L [ " Talents " ]
BTWLOADOUTS_PVP_TALENTS = L [ " PvP Talents " ]
BTWLOADOUTS_ESSENCES = L [ " Essences " ]
BTWLOADOUTS_SOULBINDS = L [ " Soulbinds " ]
BTWLOADOUTS_EQUIPMENT = L [ " Equipment " ]
BTWLOADOUTS_ACTION_BARS = L [ " Action Bars " ]
BTWLOADOUTS_CONDITIONS = L [ " Conditions " ]
BTWLOADOUTS_NEW_SET = L [ " New Set " ]
BTWLOADOUTS_ACTIVATE = L [ " Activate " ]
BTWLOADOUTS_DELETE = L [ " Delete " ]
BTWLOADOUTS_NAME = L [ " Name " ]
BTWLOADOUTS_SPECIALIZATION = L [ " Specialization " ]
BTWLOADOUTS_ENABLED = L [ " Enabled " ]
BTWLOADOUTS_UPDATE = L [ " Update " ]
BTWLOADOUTS_LOG = L [ " Log " ]
BTWLOADOUTS_CHARACTER_RESTRICTIONS = L [ " Character Restrictions " ]
BTWLOADOUTS_RESTRICTIONS = L [ " Restrictions " ]
BTWLOADOUTS_IMPORT = L [ " Import " ]
BTWLOADOUTS_EXPORT = L [ " Export " ]
BTWLOADOUTS_ZONE_NAME = L [ " Zone Name " ]
BTWLOADOUTS_PAGE_1 = L [ " Page 1 " ] ;
BTWLOADOUTS_PAGE_2 = L [ " Page 2 " ] ;
BTWLOADOUTS_ACTION_BAR_2 = L [ " Action Bar 2 " ] ;
BTWLOADOUTS_ACTION_BAR_3 = L [ " Action Bar 3 " ] ;
BTWLOADOUTS_ACTION_BAR_4 = L [ " Action Bar 4 " ] ;
BTWLOADOUTS_ACTION_BAR_5 = L [ " Action Bar 5 " ] ;
BTWLOADOUTS_ACTION_BAR_6 = L [ " Action Bar 6 " ] ;
BTWLOADOUTS_ACTION_BAR_7 = L [ " Action Bar 7 " ] ;
BTWLOADOUTS_ACTION_BAR_8 = L [ " Action Bar 8 " ] ;
BTWLOADOUTS_STANCE_BAR_1 = L [ " Stance Bar 1 " ] ;
BTWLOADOUTS_STANCE_BAR_2 = L [ " Stance Bar 2 " ] ;
BTWLOADOUTS_STANCE_BAR_3 = L [ " Stance Bar 3 " ] ;
BTWLOADOUTS_STANCE_BAR_4 = L [ " Stance Bar 4 " ] ;
BTWLOADOUTS_POSSESS_BAR = L [ " Possess Bar " ] ;
BINDING_HEADER_BTWLOADOUTS = L [ " BtWLoadouts " ]
BINDING_NAME_TOGGLE_BTWLOADOUTS = L [ " Toggle BtWLoadouts " ]
local function SettingsCreate ( options )
local optionsByKey = { } ;
local defaults = { } ;
for _ , option in ipairs ( options ) do
optionsByKey [ option.key ] = option ;
defaults [ option.key ] = option.default ;
end
local result = Mixin ( { } , options ) ;
local mt = { }
function mt . __call ( _ , tbl )
setmetatable ( tbl , { __index = defaults } ) ;
mt.__index = tbl ;
end
function mt . __newindex ( self , key , value )
local option = optionsByKey [ key ] ;
if option then
local func = option.saveValue ;
if func then
value = func ( self , key , value )
if value ~= nil then
mt.__index [ key ] = value
end
else
mt.__index [ key ] = value ;
end
func = option.onChange ;
if func then
func ( self , key , value ) ;
end
else
mt.__index [ key ] = value ;
end
end
function mt . __add ( self , option )
rawset ( self , # self + 1 , option )
optionsByKey [ option.key ] = option ;
defaults [ option.key ] = option.default ;
return self
end
setmetatable ( result , mt ) ;
result ( { } ) ;
return result ;
end
local Settings = SettingsCreate ( {
{
name = L [ " Show minimap icon " ] ,
key = " minimapShown " ,
onChange = function ( _ , id , value )
if value then
Internal.ShowMinimap ( )
else
Internal.HideMinimap ( )
end
end ,
default = true ,
} ,
{
name = L [ " Limit condition suggestions " ] ,
key = " limitConditions " ,
default = false ,
} ,
{
name = L [ " Dont offer conditions of different specialization " ] ,
key = " noSpecSwitch " ,
default = false ,
} ,
{
name = L [ " Filter chat spam while changing loadouts " ] ,
key = " filterChatSpam " ,
default = false ,
} ,
{
name = L [ " Enable Essences " ] ,
key = " essences " ,
onChange = function ( _ , id , value )
BtWLoadoutsFrame.Essences : SetEnabled ( value )
Internal.SetLoadoutSegmentEnabled ( id , value )
BtWLoadoutsFrame : Update ( )
end ,
default = GetExpansionLevel ( ) == 7 ,
} ,
{
name = L [ " Enable Soulbinds " ] ,
key = " soulbinds " ,
onChange = function ( _ , id , value )
BtWLoadoutsFrame.Soulbinds : SetEnabled ( value )
Internal.SetLoadoutSegmentEnabled ( id , value )
BtWLoadoutsFrame : Update ( )
end ,
default = GetExpansionLevel ( ) == 8 ,
} ,
{
name = L [ " Sort classes by name " ] ,
key = " sortClassesByName " ,
onChange = function ( _ , id , value )
if value then
Internal.SortClassesByName ( )
else
Internal.SortClassesByID ( )
end
BtWLoadoutsFrame : Update ( )
end ,
default = true ,
} ,
{
name = L [ " Show Settings in Loadouts menu " ] ,
key = " showSettingsInMenu " ,
default = true ,
}
} ) ;
Internal.Settings = Settings ;
local tomeButton = CreateFrame ( " BUTTON " , " BtWLoadoutsTomeButton " , UIParent , " SecureActionButtonTemplate,SecureHandlerAttributeTemplate " ) ;
tomeButton : SetFrameStrata ( " DIALOG " ) ;
tomeButton : SetAttribute ( " *type1 " , " item " ) ;
tomeButton : SetAttribute ( " unit " , " player " ) ;
tomeButton : SetAttribute ( " item " , " Tome of the Tranquil Mind " ) ;
RegisterStateDriver ( tomeButton , " combat " , " [combat] hide; show " )
tomeButton : SetAttribute ( " _onattributechanged " , [ [ -- (self, name, value)
if name == " active " and value == false then
self : Hide ( ) ;
elseif name == " state-combat " and value == " hide " then
self : Hide ( ) ;
elseif name ~= " statehidden " and self : GetAttribute ( " active " ) and self : GetAttribute ( " state-combat " ) == " show " then
self : Show ( ) ;
end
] ] ) ;
tomeButton : SetAttribute ( " active " , false ) ;
tomeButton : HookScript ( " OnEnter " , function ( self , ... )
self.button : LockHighlight ( )
local handler = self.button : GetScript ( " OnEnter " )
if handler then
handler ( self.button , ... )
end
end ) ;
tomeButton : HookScript ( " OnLeave " , function ( self , ... )
self.button : UnlockHighlight ( )
local handler = self.button : GetScript ( " OnLeave " )
if handler then
handler ( self.button , ... )
end
end ) ;
tomeButton : HookScript ( " OnMouseDown " , function ( self , ... )
self.button : SetButtonState ( " PUSHED " )
end ) ;
tomeButton : HookScript ( " OnMouseUp " , function ( self , ... )
self.button : SetButtonState ( " NORMAL " )
end ) ;
tomeButton : HookScript ( " OnClick " , function ( self , ... )
self.button : GetScript ( " OnClick " ) ( self.button , ... ) ;
end ) ;
StaticPopupDialogs [ " BTWLOADOUTS_REQUESTACTIVATE " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " Activate loadout %s? " ] ,
button1 = YES ,
button2 = NO ,
OnAccept = function ( self , data )
data.func ( data.set ) ;
end ,
timeout = 0 ,
hideOnEscape = 1
} ;
StaticPopupDialogs [ " BTWLOADOUTS_REQUESTMULTIACTIVATE " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " Activate the following loadout? \n " ] ,
button1 = YES ,
button2 = NO ,
OnAccept = function ( self , data )
data.func ( Internal.GetAciveConditionSelection ( ) . profile ) ;
end ,
OnShow = function ( self )
-- Something is changing the frame strata causing issues with the dropdown
-- box so we will change it to defgault
if self : GetFrameStrata ( ) ~= " DIALOG " then
self : SetFrameStrata ( " DIALOG " )
end
end ,
timeout = 0 ,
hideOnEscape = 1
} ;
StaticPopupDialogs [ " BTWLOADOUTS_PARTIAL " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " %s, do you wish to partially continue instead? " ] ,
button1 = YES ,
button2 = NO ,
OnAccept = function ( self , ... )
Internal.ContinuePartialActivateProfile ( ) ;
end ,
OnCancel = function ( self , data , reason , ... )
if reason == " clicked " then
Internal.CancelActivateProfile ( ) ;
end
end ,
timeout = 0 ,
hideOnEscape = 1
} ;
StaticPopupDialogs [ " BTWLOADOUTS_NEEDITEM " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " %s, do you wish to use a %s? " ] ,
button1 = YES ,
button2 = NO ,
selectCallbackByIndex = true ,
OnButton1 = function ( self , ... )
end ,
OnCancel = function ( self , data , reason , ... )
if reason == " clicked " then
Internal.CancelActivateProfile ( ) ;
end
end ,
OnShow = function ( self , data )
tomeButton : SetParent ( self ) ;
tomeButton : ClearAllPoints ( ) ;
tomeButton : SetPoint ( " TOPLEFT " , self.button1 , " TOPLEFT " , 0 , 0 ) ;
tomeButton : SetPoint ( " BOTTOMRIGHT " , self.button1 , " BOTTOMRIGHT " , 0 , 0 ) ;
tomeButton.button = self.button1 ;
tomeButton : SetFrameLevel ( self.button1 : GetFrameLevel ( ) + 1 ) ;
tomeButton : SetAttribute ( " item " , data.name ) ;
tomeButton : SetAttribute ( " active " , true ) ;
end ,
OnHide = function ( self , ... )
tomeButton : SetParent ( UIParent ) ;
tomeButton : ClearAllPoints ( ) ;
tomeButton.button = nil ;
tomeButton : SetAttribute ( " active " , false ) ;
end ,
hasItemFrame = 1 ,
timeout = 0 ,
hideOnEscape = 1 ,
noCancelOnReuse = 1 ,
} ;
StaticPopupDialogs [ " BTWLOADOUTS_NEEDITEMPARTIAL " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " %s, do you wish to use a %s or partially continue without one? " ] ,
button1 = YES ,
button2 = NO ,
button3 = CONTINUE ,
selectCallbackByIndex = true ,
OnButton1 = function ( self , ... )
end ,
OnCancel = function ( self , data , reason , ... )
if reason == " clicked " then
Internal.CancelActivateProfile ( ) ;
end
end ,
OnButton3 = function ( self , data , reason , ... )
if reason == " clicked " then
Internal.ContinueIgnoreItemActivateProfile ( ) ;
end
end ,
OnShow = function ( self , data )
tomeButton : SetParent ( self ) ;
tomeButton : ClearAllPoints ( ) ;
tomeButton : SetPoint ( " TOPLEFT " , self.button1 , " TOPLEFT " , 0 , 0 ) ;
tomeButton : SetPoint ( " BOTTOMRIGHT " , self.button1 , " BOTTOMRIGHT " , 0 , 0 ) ;
tomeButton.button = self.button1 ;
tomeButton : SetFrameLevel ( self.button1 : GetFrameLevel ( ) + 1 ) ;
tomeButton : SetAttribute ( " item " , data.name ) ;
tomeButton : SetAttribute ( " active " , true ) ;
end ,
OnHide = function ( self , ... )
tomeButton : SetParent ( UIParent ) ;
tomeButton : ClearAllPoints ( ) ;
tomeButton.button = nil ;
tomeButton : SetAttribute ( " active " , false ) ;
end ,
hasItemFrame = 1 ,
timeout = 0 ,
hideOnEscape = 1 ,
noCancelOnReuse = 1 ,
} ;
StaticPopupDialogs [ " BTWLOADOUTS_DELETESET " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " Are you sure you wish to delete the set \" %s \" . This cannot be reversed. " ] ,
button1 = YES ,
button2 = NO ,
OnAccept = function ( self , data )
data.func ( data.set ) ;
end ,
timeout = 0 ,
whileDead = 1 ,
showAlert = 1
} ;
StaticPopupDialogs [ " BTWLOADOUTS_DELETEINUSESET " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " Are you sure you wish to delete the set \" %s \" , this set is in use by one or more loadouts. This cannot be reversed. " ] ,
button1 = YES ,
button2 = NO ,
OnAccept = function ( self , data )
data.func ( data.set ) ;
end ,
timeout = 0 ,
whileDead = 1 ,
showAlert = 1
} ;
StaticPopupDialogs [ " BTWLOADOUTS_DELETECHARACTER " ] = {
preferredIndex = STATICPOPUP_NUMDIALOGS ,
text = L [ " Are you sure you wish to delete the character data for \" %s \" , this will also irreversibly delete any equipment sets for the character. " ] ,
button1 = YES ,
button2 = NO ,
OnAccept = function ( self , slug )
Internal.DeleteCharacter ( slug )
end ,
timeout = 0 ,
whileDead = 1 ,
showAlert = 1
} ;
function Internal . HelpTipBox_Anchor ( self , anchorPoint , frame , offset )
local offset = offset or 0 ;
self.Arrow : ClearAllPoints ( ) ;
self : ClearAllPoints ( ) ;
self.Arrow . Glow : ClearAllPoints ( ) ;
self : ClearAllPoints ( ) ;
self.CloseButton : SetPoint ( " TOPRIGHT " , self , " TOPRIGHT " , 4 , 6 ) ;
if anchorPoint == " RIGHT " then
self : SetPoint ( " LEFT " , frame , " RIGHT " , 30 , 0 ) ;
self.Arrow . Arrow : SetRotation ( - math.pi / 2 ) ;
self.Arrow . Glow : SetRotation ( - math.pi / 2 ) ;
self.Arrow : SetPoint ( " RIGHT " , self , " LEFT " , 17 , 0 ) ;
self.Arrow . Glow : SetPoint ( " CENTER " , self.Arrow . Arrow , " CENTER " , - 3 , 0 ) ;
self.CloseButton : SetPoint ( " TOPRIGHT " , self , " TOPRIGHT " , 6 , 6 ) ;
elseif anchorPoint == " LEFT " then
self : SetPoint ( " RIGHT " , frame , " LEFT " , - 30 , 0 ) ;
self.Arrow . Arrow : SetRotation ( math.pi / 2 ) ;
self.Arrow . Glow : SetRotation ( math.pi / 2 ) ;
self.Arrow : SetPoint ( " LEFT " , self , " RIGHT " , - 17 , 0 ) ;
self.Arrow . Glow : SetPoint ( " CENTER " , self.Arrow . Arrow , " CENTER " , 4 , 0 ) ;
self.CloseButton : SetPoint ( " TOPRIGHT " , self , " TOPRIGHT " , 4 , 6 ) ;
elseif anchorPoint == " TOP " then
self : SetPoint ( " BOTTOM " , frame , " TOP " , 0 , 20 + offset ) ;
self.Arrow . Arrow : SetRotation ( 0 ) ;
self.Arrow . Glow : SetRotation ( 0 ) ;
self.Arrow : SetPoint ( " TOP " , self , " BOTTOM " , 0 , 4 ) ;
self.Arrow . Glow : SetPoint ( " TOP " , self.Arrow . Arrow , " TOP " , 0 , 0 ) ;
self.CloseButton : SetPoint ( " TOPRIGHT " , self , " TOPRIGHT " , 4 , 6 ) ;
elseif anchorPoint == " BOTTOM " then
self : SetPoint ( " TOP " , frame , " BOTTOM " , 0 , - 20 - offset ) ;
self.Arrow . Arrow : SetRotation ( math.pi ) ;
self.Arrow . Glow : SetRotation ( math.pi ) ;
self.Arrow : SetPoint ( " BOTTOM " , self , " TOP " , 0 , - 3 ) ;
self.Arrow . Glow : SetPoint ( " BOTTOM " , self.Arrow . Arrow , " BOTTOM " , 0 , 0 ) ;
self.CloseButton : SetPoint ( " TOPRIGHT " , self , " TOPRIGHT " , 4 , 6 ) ;
end
end
function Internal . HelpTipBox_SetText ( self , text )
self.Text : SetText ( text ) ;
self : SetHeight ( self.Text : GetHeight ( ) + 34 ) ;
end
local NUM_TABS = 7 ;
local TAB_LOADOUTS = 1 ;
local TAB_TALENTS = 2 ;
local TAB_PVP_TALENTS = 3 ;
local TAB_ESSENCES = 4 ;
local TAB_EQUIPMENT = 5 ;
local TAB_ACTION_BARS = 6 ;
local TAB_CONDITIONS = 7 ;
local function GetTabFrame ( self , tabID )
return self.TabFrames [ tabID ]
end
function Internal . DropDownSetOnChange ( self , func )
self.OnChange = func ;
end
BtWLoadoutsClassDropDownMixin = { }
function BtWLoadoutsClassDropDownMixin : OnShow ( )
if not self.initialized then
UIDropDownMenu_Initialize ( self , self.Init ) ;
self.initialized = true
end
end
function BtWLoadoutsClassDropDownMixin : Init ( level , menuList )
local info = UIDropDownMenu_CreateInfo ( ) ;
local selected = self : GetValue ( ) ;
info.func = function ( button , arg1 , arg2 , checked )
self : SetValue ( button , arg1 , arg2 , checked )
end
if ( level or 1 ) == 1 then
if self.includeNone then
info.text = L [ " None " ] ;
info.checked = selected == nil ;
UIDropDownMenu_AddButton ( info , level ) ;
end
for classIndex = 1 , GetNumClasses ( ) do
if GetNumSpecializationsForClassID ( classIndex ) > 0 then
local className , classFile = GetClassInfo ( classIndex ) ;
local classColor = C_ClassColor.GetClassColor ( classFile ) ;
info.text = classColor and classColor : WrapTextInColorCode ( className ) or className ;
info.arg1 = classIndex ;
info.arg2 = classFile ;
info.checked = selected == classIndex ;
UIDropDownMenu_AddButton ( info , level ) ;
end
end
end
end
function BtWLoadoutsClassDropDownMixin : GetValue ( )
end
function BtWLoadoutsClassDropDownMixin : SetValue ( button , classIndex , classFile , checked )
end
BtWLoadoutsSpecDropDownMixin = { }
function BtWLoadoutsSpecDropDownMixin : OnShow ( )
if not self.initialized then
UIDropDownMenu_Initialize ( self , self.Init ) ;
self.initialized = true
end
end
function BtWLoadoutsSpecDropDownMixin : Init ( level , menuList )
local info = UIDropDownMenu_CreateInfo ( ) ;
local selectedSpecID , selectedClassID = self : GetValue ( ) ;
info.func = function ( button , arg1 , arg2 , checked )
self : SetValue ( button , arg1 , arg2 , checked )
end
if ( level or 1 ) == 1 then
if self.includeNone then
info.text = L [ " None " ] ;
info.checked = ( not self.includeClass or selectedClassID == nil ) and selectedSpecID == nil ;
UIDropDownMenu_AddButton ( info , level ) ;
end
info.func = nil ;
for classIndex = 1 , GetNumClasses ( ) do
if GetNumSpecializationsForClassID ( classIndex ) > 0 then
local className , classFile = GetClassInfo ( classIndex ) ;
local classColor = C_ClassColor.GetClassColor ( classFile ) ;
info.text = classColor and classColor : WrapTextInColorCode ( className ) or className ;
info.hasArrow , info.menuList = true , classIndex ;
info.keepShownOnClick = true ;
info.notCheckable = true ;
UIDropDownMenu_AddButton ( info , level ) ;
end
end
else
local classID = menuList ;
if self.includeClass then
local className , classFile = GetClassInfo ( classID ) ;
local classColor = C_ClassColor.GetClassColor ( classFile ) ;
info.text = classColor and classColor : WrapTextInColorCode ( className ) or className ;
info.arg1 = nil ;
info.arg2 = classID ;
info.checked = selectedClassID == classID and selectedSpecID == nil ;
UIDropDownMenu_AddButton ( info , level ) ;
end
for specIndex = 1 , GetNumSpecializationsForClassID ( classID ) do
local specID , name , _ , icon , role = GetSpecializationInfoForClassID ( classID , specIndex ) ;
info.text = name ;
info.icon = icon ;
info.arg1 = specID ;
info.arg2 = classID ;
info.checked = selectedSpecID == specID ;
UIDropDownMenu_AddButton ( info , level ) ;
end
end
end
-- Override. return specID, classID (classID only needed if includeClass = true).
function BtWLoadoutsSpecDropDownMixin : GetValue ( )
end
-- Override.
function BtWLoadoutsSpecDropDownMixin : SetValue ( button , specID , classID , checked )
end
-- Restrictions Drop Down, used by sets to handle limit activation
do
local function DropDownInit ( self , level , menuList )
local function OnClick ( _ , arg1 , arg2 , checked )
self : ToggleSelected ( arg1 , arg2 )
end
local info = UIDropDownMenu_CreateInfo ( )
if ( level or 1 ) == 1 then
local hasSelected = false
info.func = OnClick
info.checked = true
info.keepShownOnClick = true
info.isNotRadio = true
for _ , type , key , name , restricted in self : EnumerateSelected ( ) do
info.text = restricted and string.format ( " |CFFFF8080%s|r " , name ) or name
info.arg1 = type
info.arg2 = key
info.tooltipOnButton = restricted
if restricted then
info.tooltipTitle = name
info.tooltipText = L [ " Incompatible Restrictions " ]
else
info.tooltipTitle = nil
info.tooltipText = nil
end
UIDropDownMenu_AddButton ( info , level )
hasSelected = true
end
info.tooltipOnButton = false
info.tooltipTitle = nil
info.tooltipText = nil
if hasSelected then
UIDropDownMenu_AddSeparator ( )
end
info.func = nil
info.checked = nil
for _ , type , name in self : EnumerateSupportedTypes ( ) do
info.text = name
info.hasArrow , info.menuList = true , type
info.notCheckable = true
UIDropDownMenu_AddButton ( info , level )
end
else
info.func = OnClick
info.keepShownOnClick = true
info.isNotRadio = true
for _ , key , name in self : EnumerateType ( menuList ) do
info.text = name
info.arg1 = menuList
info.arg2 = key
info.checked = self : IsSelected ( menuList , key )
UIDropDownMenu_AddButton ( info , level )
end
end
end
BtWLoadoutsRestrictionsDropDownMixin = { }
function BtWLoadoutsRestrictionsDropDownMixin : OnLoad ( )
self.selected = { }
self.supportedTypes = { }
self.limitations = { }
end
function BtWLoadoutsRestrictionsDropDownMixin : OnShow ( )
if not self.initialized then
UIDropDownMenu_Initialize ( self , DropDownInit , " MENU " )
self.initialized = true
end
end
function BtWLoadoutsRestrictionsDropDownMixin : EnumerateSelected ( )
local selected = { }
for _ , type , typeName in self : EnumerateSupportedTypes ( ) do
if self.selected [ type ] and next ( self.selected [ type ] ) then
for _ , key , name , restricted in self : EnumerateType ( type , true ) do
if self : IsSelected ( type , key ) then
selected [ # selected + 1 ] = { type , key , string.format ( " %s: %s " , typeName , name ) , restricted }
end
end
end
end
return function ( tbl , index )
index = index + 1
if tbl [ index ] then
return index , unpack ( tbl [ index ] )
end
end , selected , 0
end
local selectionTemp = { }
function BtWLoadoutsRestrictionsDropDownMixin : SetSelections ( tbl )
assert ( type ( tbl ) == " table " , " Expected table " )
-- Clean up tbl based on available types
wipe ( selectionTemp )
for _ , t in ipairs ( self.supportedTypes ) do
selectionTemp [ t ] = tbl [ t ]
end
wipe ( tbl )
for k , v in pairs ( selectionTemp ) do
tbl [ k ] = v
end
self.selected = tbl
end
function BtWLoadoutsRestrictionsDropDownMixin : ClearSelected ( )
wipe ( self.selected )
end
function BtWLoadoutsRestrictionsDropDownMixin : IsSelected ( type , key )
return self.selected [ type ] and self.selected [ type ] [ key ]
end
function BtWLoadoutsRestrictionsDropDownMixin : ToggleSelected ( type , key )
self.selected [ type ] = self.selected [ type ] or { }
if self.selected [ type ] [ key ] then
self.selected [ type ] [ key ] = nil
else
self.selected [ type ] [ key ] = true
end
if self.onchange then
self : onchange ( type , key )
end
end
function BtWLoadoutsRestrictionsDropDownMixin : SetSupportedTypes ( ... )
wipe ( self.supportedTypes )
for i = 1 , select ( ' # ' , ... ) do
local type = strlower ( select ( i , ... ) )
assert ( Internal.Filters [ type ] ~= nil , " Unavailable type " .. type )
self.supportedTypes [ i ] = type
end
end
-- Allow limiting some supported types, like characters to limit spec or role to limit spec.
function BtWLoadoutsRestrictionsDropDownMixin : SetLimitations ( ... )
wipe ( self.limitations )
for i = 1 , select ( ' # ' , ... ) , 2 do
local k , v = select ( i , ... )
self.limitations [ k ] = v
end
end
function BtWLoadoutsRestrictionsDropDownMixin : EnumerateSupportedTypes ( )
return function ( tbl , index )
index = index + 1
local type = tbl [ index ]
if type then
return index , type , Internal.Filters [ type ] . name
end
end , self.supportedTypes , 0
end
function BtWLoadoutsRestrictionsDropDownMixin : EnumerateType ( type , includeLimitations )
return Internal.Filters [ type ] . enumerate ( self.limitations , includeLimitations )
end
function BtWLoadoutsRestrictionsDropDownMixin : SetScript ( scriptType , handler )
if scriptType == " OnChange " then
self.onchange = handler
else
getmetatable ( self ) . SetScript ( self , scriptType , handler )
end
end
function Internal . UpdateRestrictionFilters ( set )
if set.restrictions then
local filters = set.filters or { }
-- Covenant
if set.restrictions . covenant and next ( set.restrictions . covenant ) then
filters.covenant = wipe ( filters.covenant or { } )
local tbl = filters.covenant
for covenant in pairs ( set.restrictions . covenant ) do
tbl [ # tbl + 1 ] = covenant
end
else
filters.covenant = nil
end
-- Specialization
local roles = { }
local classes = { }
if set.restrictions . spec and next ( set.restrictions . spec ) then
if filters.spec == nil or type ( filters.spec ) == " table " then
filters.spec = wipe ( filters.spec or { } )
local tbl = filters.spec
for spec in pairs ( set.restrictions . spec ) do
local role , class = select ( 5 , GetSpecializationInfoByID ( spec ) )
roles [ role ] = true
classes [ class ] = true
tbl [ # tbl + 1 ] = spec
end
end
if filters.role == nil or type ( filters.role ) == " table " then
filters.role = wipe ( filters.role or { } )
local tbl = filters.role
for role in pairs ( roles ) do
tbl [ # tbl + 1 ] = role
end
end
if filters.class == nil or type ( filters.class ) == " table " then
filters.class = wipe ( filters.class or { } )
local tbl = filters.class
for class in pairs ( classes ) do
tbl [ # tbl + 1 ] = class
end
end
else
filters.spec = nil
filters.role = nil
filters.class = nil
end
-- Race
if set.restrictions . race and next ( set.restrictions . race ) then
filters.race = wipe ( filters.race or { } )
local tbl = filters.race
for race in pairs ( set.restrictions . race ) do
tbl [ # tbl + 1 ] = race
end
else
filters.race = nil
end
end
end
function Internal . AreRestrictionsValidFor ( restrictions , specID , covenantID , raceID )
if restrictions then
if restrictions.spec and next ( restrictions.spec ) and specID ~= nil then
if not restrictions.spec [ specID ] then
return false
end
end
if restrictions.covenant and next ( restrictions.covenant ) and covenantID ~= nil then
if not restrictions.covenant [ covenantID ] then
return false
end
end
if restrictions.race and next ( restrictions.race ) and raceID ~= nil then
if not restrictions.race [ raceID ] then
return false
end
end
end
return true
end
-- Used by combine functions to check set restrictions
function Internal . AreRestrictionsValidForPlayer ( restrictions )
local specID = GetSpecializationInfo ( GetSpecialization ( ) ) or false
local covenantID = C_Covenants.GetActiveCovenantID ( ) or false
local raceID = select ( 3 , UnitRace ( " player " ) ) or false
return Internal.AreRestrictionsValidFor ( restrictions , specID , covenantID , raceID )
end
end
--[[
Character selection drop down menu
] ]
do
BtWLoadoutsCharacterDropDownMixin = { }
function BtWLoadoutsCharacterDropDownMixin : OnShow ( )
if not self.initialized then
UIDropDownMenu_Initialize ( self , self.Init ) ;
self.initialized = true
end
end
function BtWLoadoutsCharacterDropDownMixin : Init ( level )
if not self.GetValue then
return
end
local info = UIDropDownMenu_CreateInfo ( ) ;
local selected = self : GetValue ( )
info.keepShownOnClick = true
info.func = function ( button , arg1 , arg2 , checked )
self : SetValue ( button , arg1 , arg2 , checked )
CloseDropDownMenus ( )
ToggleDropDownMenu ( nil , nil , self )
end
if self.includeAny then
info.text = L [ " Any " ] ;
info.arg1 = nil
if self.multiple then
info.checked = next ( selected ) == nil
else
info.checked = selected == nil
end
UIDropDownMenu_AddButton ( info , level ) ;
end
if self.includeInherit then
info.text = L [ " Inherit " ] ;
info.arg1 = " inherit "
if self.multiple then
info.checked = selected [ " inherit " ] ;
else
info.checked = selected == " inherit "
end
UIDropDownMenu_AddButton ( info , level ) ;
end
local character = Internal.GetCharacterSlug ( )
local classFile = select ( 2 , UnitClass ( " player " ) ) ;
if self.classFile == nil or self.classFile == classFile then
local name , realm = UnitFullName ( " player " )
local characterInfo = GetCharacterInfo ( character )
if characterInfo then
local classColor = C_ClassColor.GetClassColor ( characterInfo.class )
name = format ( " %s - %s " , classColor : WrapTextInColorCode ( characterInfo.name ) , characterInfo.realm )
end
info.text = name
info.arg1 = character
if self.multiple then
info.checked = selected [ character ]
else
info.checked = selected == character ;
end
UIDropDownMenu_AddButton ( info , level ) ;
end
local playerCharacter = character
for _ , character in Internal.CharacterIterator ( ) do
if playerCharacter ~= character then
local name
local characterInfo = GetCharacterInfo ( character )
if self.classFile == nil or self.classFile == characterInfo.class then
if characterInfo then
local classColor = C_ClassColor.GetClassColor ( characterInfo.class )
name = format ( " %s - %s " , classColor : WrapTextInColorCode ( characterInfo.name ) , characterInfo.realm )
end
info.text = name
info.arg1 = character
if self.multiple then
info.checked = selected [ character ]
else
info.checked = selected == character ;
end
UIDropDownMenu_AddButton ( info , level ) ;
end
end
end
end
function BtWLoadoutsCharacterDropDownMixin : SetClass ( classFile )
self.classFile = classFile
end
function BtWLoadoutsCharacterDropDownMixin : UpdateName ( )
if not self.GetValue then
return
end
local character = self : GetValue ( )
if self.multiple then
local first = next ( character )
if first == nil then
UIDropDownMenu_SetText ( self , L [ " Any " ] ) ;
elseif first == " inherit " then
UIDropDownMenu_SetText ( self , L [ " Inherit " ] ) ;
elseif next ( character , first ) == nil then
local characterInfo = Internal.GetCharacterInfo ( first ) ;
if characterInfo then
local classColor = C_ClassColor.GetClassColor ( characterInfo.class )
first = format ( " %s - %s " , classColor : WrapTextInColorCode ( characterInfo.name ) , characterInfo.realm )
end
UIDropDownMenu_SetText ( self , first ) ;
else
UIDropDownMenu_SetText ( self , L [ " Multiple " ] ) ;
end
else
if character == nil then
UIDropDownMenu_SetText ( self , L [ " None " ] ) ;
elseif character == " inherit " then
UIDropDownMenu_SetText ( self , L [ " Inherit " ] ) ;
else
local characterInfo = Internal.GetCharacterInfo ( character ) ;
if characterInfo then
local classColor = C_ClassColor.GetClassColor ( characterInfo.class )
character = format ( " %s - %s " , classColor : WrapTextInColorCode ( characterInfo.name ) , characterInfo.realm )
end
UIDropDownMenu_SetText ( self , character ) ;
end
end
end
end
-- Sets Drop Down menu
do
-- local filtered
local function DropDownInit ( self , level , menuList )
local function OnClick ( _ , arg1 , arg2 , checked )
self : callback ( arg1 )
end
local info = UIDropDownMenu_CreateInfo ( )
local selected = self : GetSelected ( )
if ( level or 1 ) == 1 and self : IncludeNone ( ) then
info.text = NONE ;
info.func = OnClick ;
info.arg1 = " none " ;
info.checked = selected == nil ;
UIDropDownMenu_AddButton ( info , level ) ;
end
if not menuList then
menuList = Internal.FilterSets ( { } , self.filters , self : GetSets ( ) )
menuList = Internal.CategoriesSets ( menuList , self : GetCategories ( ) )
end
local filter = self.categories [ level or 1 ]
if filter then
info.func = nil ;
info.hasArrow = true ;
info.keepShownOnClick = true ;
info.notCheckable = true ;
for _ , key , name , restricted in Internal.Filters [ filter ] . enumerate ( nil , false , true ) do
if menuList [ key ] then
info.text = name
info.menuList = menuList [ key ] --(menuList and (menuList .. ".") or "") .. key
UIDropDownMenu_AddButton ( info , level ) ;
end
end
else
info.func = OnClick ;
Internal.SortSets ( menuList )
local hasPreItems = false
for k , set in pairs ( menuList ) do
if hasPreItems and ( set.order or 0 ) >= 0 then
UIDropDownMenu_AddSeparator ( level )
hasPreItems = false
elseif not hasPreItems and set.order and set.order < 0 then
hasPreItems = true
end
info.text = set.name ~= " " and set.name or L [ " Unnamed " ] ;
info.arg1 = set.setID ;
info.func = OnClick ;
info.checked = selected == set.setID ;
UIDropDownMenu_AddButton ( info , level ) ;
end
end
if ( level or 1 ) == 1 and self : IncludeNewSet ( ) then
info.text = L [ " New Set " ] ;
info.func = OnClick ;
info.arg1 = " new " ;
info.hasArrow , info.menuList = false , nil ;
info.keepShownOnClick = false ;
info.notCheckable = true ;
info.checked = false ;
UIDropDownMenu_AddButton ( info , level ) ;
end
end
BtWLoadoutsSetDropDownMixin = { }
function BtWLoadoutsSetDropDownMixin : OnLoad ( )
self.categories = { }
self.sets = { }
end
function BtWLoadoutsSetDropDownMixin : Init ( )
UIDropDownMenu_Initialize ( self , DropDownInit , " MENU " ) ;
end
function BtWLoadoutsSetDropDownMixin : OnShow ( )
if not self.initialized then
self.initialized = true
self : Init ( )
end
end
function BtWLoadoutsSetDropDownMixin : SetSelected ( value )
self.selected = value
end
function BtWLoadoutsSetDropDownMixin : SetSets ( value )
self.sets = value
end
function BtWLoadoutsSetDropDownMixin : SetCategories ( value )
self.categories = value
end
function BtWLoadoutsSetDropDownMixin : GetCategories ( )
return unpack ( self.categories )
end
function BtWLoadoutsSetDropDownMixin : SetFilters ( value )
self.filters = value
end
function BtWLoadoutsSetDropDownMixin : GetFilters ( )
local temp = { }
for k in pairs ( self.filters ) do
temp [ # temp + 1 ] = k
end
return unpack ( temp )
end
function BtWLoadoutsSetDropDownMixin : GetSets ( )
return self.sets
end
function BtWLoadoutsSetDropDownMixin : GetSelected ( )
return self.selected
end
function BtWLoadoutsSetDropDownMixin : IncludeNewSet ( )
return true
end
function BtWLoadoutsSetDropDownMixin : IncludeNone ( )
return self.includeNone
end
function BtWLoadoutsSetDropDownMixin : SetIncludeNone ( value )
self.includeNone = not not value
end
function BtWLoadoutsSetDropDownMixin : OnItemClick ( callback )
self.callback = callback
end
end
--[[
BtWLoadoutsSidebarMixin , sidebar display with filtering
] ]
do
local FilterSetsBySearch = Internal.FilterSetsBySearch
local FilterSets = Internal.FilterSets
local CategoriesSets = Internal.CategoriesSets
local SortSets = Internal.SortSets
local function BuildList ( items , depth , selected , filtered , collapsed , ... )
if select ( ' # ' , ... ) == 0 then
SortSets ( filtered )
for _ , set in ipairs ( filtered ) do
selected = selected or set
items [ # items + 1 ] = {
id = set.setID ,
name = ( set.name == nil or set.name == " " ) and L [ " Unnamed " ] or set.name ,
disabled = set.disabled ,
selected = set == selected ,
builtin = ( set.managerID ~= nil ) or ( set.configID ~= nil ) ,
depth = depth ,
} ;
end
else
local filter = ...
collapsed.children = collapsed.children or { }
for _ , key , name , restricted in Internal.Filters [ filter ] . enumerate ( nil , nil , true ) do
if filtered [ key ] then
local isCollapsed = collapsed [ key ] and true or false
items [ # items + 1 ] = {
id = key ,
type = filter ,
isHeader = true ,
isCollapsed = isCollapsed ,
collapsed = collapsed ,
name = name ,
depth = depth ,
} ;
if not isCollapsed then
selected = BuildList ( items , depth + 1 , selected , filtered [ key ] , collapsed.children , select ( 2 , ... ) )
end
end
end
end
return selected
end
local function Scroll_Update ( self )
local buttons = self.buttons ;
local items = self.items ;
if not buttons then
return
end
local totalHeight , displayedHeight = # items * ( buttons [ 1 ] : GetHeight ( ) + 1 ) , self : GetHeight ( )
-- local hasScrollBar = totalHeight > displayedHeight
local offset = HybridScrollFrame_GetOffset ( self ) ;
for i , button in ipairs ( buttons ) do
-- button:SetWidth(223)
-- button:SetWidth(hasScrollBar and 200 or 223)
local item = items [ i + offset ]
if item then
button.isAdd = item.isAdd ;
if item.isAdd then
button.SelectedBar : Hide ( ) ;
button.BuiltinIcon : Hide ( ) ;
end
button.isHeader = item.isHeader ;
if item.isHeader then
button.id = item.id ;
button.collapsed = item.collapsed ;
button.SelectedBar : Hide ( ) ;
if item.isCollapsed then
button.ExpandedIcon : Hide ( ) ;
button.CollapsedIcon : Show ( ) ;
else
button.ExpandedIcon : Show ( ) ;
button.CollapsedIcon : Hide ( ) ;
end
button.BuiltinIcon : Hide ( ) ;
button.ExpandedIcon : SetPoint ( " LEFT " , ( item.depth * 15 ) + 4 , 0 )
button.CollapsedIcon : SetPoint ( " LEFT " , ( item.depth * 15 ) + 4 , 0 )
button.Name : SetPoint ( " LEFT " , ( item.depth * 15 ) + 15 , 0 )
else
if not item.isAdd then
button.id = item.id ;
button.SelectedBar : SetShown ( item.selected ) ;
button.BuiltinIcon : SetShown ( item.builtin ) ;
end
button.ExpandedIcon : Hide ( ) ;
button.CollapsedIcon : Hide ( ) ;
button.Name : SetPoint ( " LEFT " , ( item.depth * 15 ) + 4 , 0 )
end
local name ;
-- if item.character then
-- local characterInfo = GetCharacterInfo(item.character);
-- if characterInfo then
-- name = format("%s |cFFD5D5D5(%s - %s)|r", item.name, characterInfo.name, characterInfo.realm);
-- else
-- name = format("%s |cFFD5D5D5(%s)|r", item.name, item.character);
-- end
-- else
name = item.name ;
-- end
if item.disabled then
name = format ( " |cFF999999%s|r " , name )
end
button.Name : SetText ( name or L [ " Unnamed " ] ) ;
button : Show ( ) ;
else
button : Hide ( ) ;
end
end
HybridScrollFrame_Update ( self , totalHeight , displayedHeight ) ;
end
local function DropDown_Initialize ( self , level )
local sidebar = self : GetParent ( )
local info = UIDropDownMenu_CreateInfo ( )
info.keepShownOnClick = true
info.isNotRadio = true
if level == 1 then
-- Own only?
local active = { }
self.MovePool : ReleaseAll ( )
info.isTitle = false
info.disabled = false
info.func = function ( self , arg1 , arg2 )
sidebar : SetFilter ( arg1 , sidebar : GetFilter ( arg1 ) ~= arg2 and arg2 or nil )
CloseDropDownMenus ( )
ToggleDropDownMenu ( 1 , nil , sidebar.FilterDropDown , sidebar.FilterButton , 74 , 15 )
end
if sidebar : SupportsFilters ( " character " ) then
local character = GetCharacterSlug ( )
info.checked = sidebar : GetFilter ( " character " ) == character
info.arg1 = " character "
info.arg2 = character
info.text = L [ " Current Character Only " ]
UIDropDownMenu_AddButton ( info , level )
end
if sidebar : SupportsFilters ( " disabled " ) then
info.checked = sidebar : GetFilter ( " disabled " ) == 0
info.arg1 = " disabled "
info.arg2 = 0
info.text = L [ " Enabled Sets Only " ]
UIDropDownMenu_AddButton ( info , level )
end
if sidebar : GetSupportedFilters ( ) then
info.isTitle = true
info.notCheckable = true
info.checked = false
info.text = L [ " Categories " ]
UIDropDownMenu_AddButton ( info , level )
info.isTitle = false
info.disabled = false
info.notCheckable = false
info.checked = true
info.func = function ( self , arg1 )
sidebar : RemoveCategory ( arg1 )
CloseDropDownMenus ( )
ToggleDropDownMenu ( 1 , nil , sidebar.FilterDropDown , sidebar.FilterButton , 74 , 15 )
end
for index , value in ipairs ( { sidebar : GetCategories ( ) } ) do
info.text = sidebar : GetFilterName ( value )
info.arg1 = value
info.arg2 = index
-- info.customFrame = self.MovePool:Acquire()
active [ value ] = true
UIDropDownMenu_AddButton ( info , level ) ;
end
info.checked = false
info.customFrame = nil
info.func = function ( self , arg1 )
sidebar : AddCategory ( arg1 )
CloseDropDownMenus ( )
ToggleDropDownMenu ( 1 , nil , sidebar.FilterDropDown , sidebar.FilterButton , 74 , 15 )
end
for _ , value in ipairs ( { sidebar : GetSupportedFilters ( ) } ) do
if not active [ value ] then
info.text = sidebar : GetFilterName ( value )
info.arg1 = value
active [ value ] = true
UIDropDownMenu_AddButton ( info , level ) ;
end
end
end
end
end
BtWLoadoutsSidebarMixin = { }
function BtWLoadoutsSidebarMixin : OnLoad ( )
self.supportedFilters = { }
end
function BtWLoadoutsSidebarMixin : CreateButtons ( )
local buttonTemplate , initialOffsetX , initialOffsetY , initialPoint , initialRelative , offsetX , offsetY , point , relativePoint = " BtWLoadoutsSidebarScrollItemTemplate " , 0 , 0 , " TOPLEFT " , " TOPLEFT " , 0 , - 1 , " TOP " , " BOTTOM " ;
-- Custom version of HybridScrollFrame_CreateButtons with 1 main difference, it doesnt reset the scroll when creating buttons so
-- we can use this to create extra buttons on resize without reseting the scroll position
local scrollChild = self.Scroll . scrollChild ;
local button , buttonHeight , buttons , numButtons ;
local parentName = self.Scroll : GetName ( ) ;
local buttonName = parentName and ( parentName .. " Button " ) or nil ;
initialPoint = initialPoint or " TOPLEFT " ;
initialRelative = initialRelative or " TOPLEFT " ;
point = point or " TOPLEFT " ;
relativePoint = relativePoint or " BOTTOMLEFT " ;
offsetX = offsetX or 0 ;
offsetY = offsetY or 0 ;
if ( self.Scroll . buttons ) then
buttons = self.Scroll . buttons ;
buttonHeight = buttons [ 1 ] : GetHeight ( ) ;
else
button = CreateFrame ( " BUTTON " , buttonName and ( buttonName .. 1 ) or nil , scrollChild , buttonTemplate ) ;
buttonHeight = button : GetHeight ( ) ;
button : SetPoint ( initialPoint , scrollChild , initialRelative , initialOffsetX , initialOffsetY ) ;
buttons = { }
tinsert ( buttons , button ) ;
end
self.Scroll . buttonHeight = math.floor ( buttonHeight + .5 ) - offsetY ;
local numButtons = math.ceil ( self.Scroll : GetHeight ( ) / buttonHeight ) + 1 ;
for i = # buttons + 1 , numButtons do
button = CreateFrame ( " BUTTON " , buttonName and ( buttonName .. i ) or nil , scrollChild , buttonTemplate ) ;
button : SetPoint ( point , buttons [ i - 1 ] , relativePoint , offsetX , offsetY ) ;
tinsert ( buttons , button ) ;
end
scrollChild : SetWidth ( self.Scroll : GetWidth ( ) )
scrollChild : SetHeight ( numButtons * buttonHeight ) ;
self.Scroll : SetVerticalScroll ( 0 ) ;
self.Scroll : UpdateScrollChildRect ( ) ;
self.Scroll . buttons = buttons ;
local scrollBar = self.Scroll . scrollBar ;
scrollBar : SetMinMaxValues ( 0 , numButtons * buttonHeight )
scrollBar.buttonHeight = buttonHeight ;
scrollBar : SetValueStep ( buttonHeight ) ;
scrollBar : SetStepsPerPage ( numButtons - 2 ) ; -- one additional button was added above. Need to remove that, and one more to make the current bottom the new top (and vice versa)
end
function BtWLoadoutsSidebarMixin : Init ( )
self.Scroll . items = { }
self.Scroll . ScrollBar.doNotHide = true ;
self : CreateButtons ( ) ;
self.Scroll . scrollBar : SetValue ( 0 ) ;
self.Scroll . update = Scroll_Update
UIDropDownMenu_Initialize ( self.FilterDropDown , DropDown_Initialize , " MENU " ) ;
self.FilterDropDown . MovePool = CreateFramePool ( " FRAME " , self , " BtWLoadoutsSidebarFilterEntryTemplate " , FramePool_HideAndClearAnchors ) ;
end
function BtWLoadoutsSidebarMixin : OnShow ( )
if not self.initialized then
self.initialized = true
self : Init ( )
end
end
function BtWLoadoutsSidebarMixin : SetSupportedFilters ( ... )
wipe ( self.supportedFilters )
for i = 1 , select ( ' # ' , ... ) do
self.supportedFilters [ i ] = select ( i , ... )
end
end
function BtWLoadoutsSidebarMixin : SupportsFilters ( value )
for _ , filter in ipairs ( self.supportedFilters ) do
if filter == value then
return true
end
end
return false
end
function BtWLoadoutsSidebarMixin : GetSupportedFilters ( ... )
return unpack ( self.supportedFilters )
end
function BtWLoadoutsSidebarMixin : GetFilterName ( key )
return Internal.Filters [ key ] . name or key
end
function BtWLoadoutsSidebarMixin : SetSets ( value )
self.sets = value
end
function BtWLoadoutsSidebarMixin : SetCollapsed ( value )
self.collapsed = value
end
function BtWLoadoutsSidebarMixin : SetCategories ( value )
self.categories = value
end
function BtWLoadoutsSidebarMixin : SetFilters ( value )
for k in pairs ( value ) do
if not self : SupportsFilters ( k ) then
value [ k ] = nil
end
end
self.filters = value
end
function BtWLoadoutsSidebarMixin : SetSelected ( selected )
self.selected = selected
end
function BtWLoadoutsSidebarMixin : GetSelected ( )
return self.selected
end
function BtWLoadoutsSidebarMixin : GetCategories ( )
return unpack ( self.categories )
end
function BtWLoadoutsSidebarMixin : GetFilters ( )
local temp = { }
for k in pairs ( self.filters ) do
temp [ # temp + 1 ] = k
end
return unpack ( temp )
end
function BtWLoadoutsSidebarMixin : GetFilter ( name )
return self.filters [ name ]
end
function BtWLoadoutsSidebarMixin : SetFilter ( name , value )
self.filters [ name ] = value
self : Update ( )
end
function BtWLoadoutsSidebarMixin : AddCategory ( filter )
self.categories [ # self.categories + 1 ] = filter
self : Update ( )
end
function BtWLoadoutsSidebarMixin : RemoveCategory ( filter )
for i = 1 , # self.categories do
if self.categories [ i ] == filter then
table.remove ( self.categories , i )
break
end
end
self : Update ( )
end
function BtWLoadoutsSidebarMixin : OnSearchChanged ( )
self.query = self.SearchBox : GetText ( ) : lower ( )
self : Update ( )
end
function BtWLoadoutsSidebarMixin : Update ( )
if not self.initialized then return end
self.FilterButton : SetEnabled ( # self.supportedFilters > 0 )
local filtered = FilterSetsBySearch ( { } , self.query , self.sets )
filtered = FilterSets ( { } , self.filters , filtered )
filtered = CategoriesSets ( filtered , unpack ( self.categories ) )
wipe ( self.Scroll . items )
self.selected = BuildList ( self.Scroll . items , 0 , self.selected , filtered , self.collapsed , unpack ( self.categories ) )
if not self.selected then -- Fallback in case everything is hidden
for _ , set in pairs ( self.sets ) do
if type ( set ) == " table " then
self.selected = set
break
end
end
end
self.Scroll : update ( ) ;
self : Show ( )
end
end
do
function BtWLoadoutsTabFrame_OnLoad ( self )
local frame = self : GetParent ( )
local Tabs = frame.Tabs
local index = # Tabs
local previous = Tabs [ index ]
while previous and not previous : IsShown ( ) do
index = index - 1
previous = Tabs [ index ]
end
local tab = frame.TabPool : Acquire ( )
local id = # Tabs
self : SetID ( id )
tab : SetID ( id )
tab : SetText ( self.name )
if previous then
if select ( 4 , GetBuildInfo ( ) ) >= 100000 then
tab : SetPoint ( " TOPLEFT " , previous , " TOPRIGHT " , 1 , 0 ) ;
else
tab : SetPoint ( " LEFT " , previous , " RIGHT " , - 16 , 0 ) ;
end
else
tab : SetPoint ( " BOTTOMLEFT " , 7 , - 30 )
end
if self.segment then
frame.TabSegments [ self.segment ] = self
if self.enabled == nil then
self.enabled = Internal.GetLoadoutSegmentEnabled ( self.segment )
end
end
tab : SetShown ( self.enabled ~= false )
frame.numTabs = id ;
if id == 1 then
PanelTemplates_SetTab ( frame , id ) ;
end
PanelTemplates_UpdateTabs ( frame ) ;
end
function BtWLoadoutsTabFrame_SetEnabled ( self , value )
self.enabled = value and true or false
BtWLoadoutsTabFrame_ReanchorTabs ( self )
end
function BtWLoadoutsTabFrame_ReanchorTabs ( self )
local frame = self : GetParent ( )
local Tabs = frame.Tabs
local TabFrames = frame.TabFrames
local index = self : GetID ( ) - 1
local previous = Tabs [ index ]
while previous and not previous : IsShown ( ) do
index = index - 1
previous = Tabs [ index ]
end
for i = self : GetID ( ) , # Tabs do
local tab = Tabs [ i ]
local tabFrame = TabFrames [ i ]
tab : SetShown ( tabFrame.enabled ~= false )
if tabFrame.enabled ~= false then
if previous then
if select ( 4 , GetBuildInfo ( ) ) >= 100000 then
tab : SetPoint ( " TOPLEFT " , previous , " TOPRIGHT " , 1 , 0 ) ;
else
tab : SetPoint ( " LEFT " , previous , " RIGHT " , - 16 , 0 ) ;
end
else
tab : SetPoint ( " BOTTOMLEFT " , 7 , - 30 )
end
previous = tab
end
end
end
BtWLoadoutsFrameMixin = { } ;
function BtWLoadoutsFrameMixin : OnLoad ( )
tinsert ( UISpecialFrames , self : GetName ( ) ) ;
self : RegisterForDrag ( " LeftButton " ) ;
self.Tabs = { }
self.TabSegments = { }
if select ( 4 , GetBuildInfo ( ) ) >= 100000 then
self.TabPool = CreateFramePool ( " Button " , self , " BtWLoadoutsTabTemplateDragonflight " )
else
self.TabPool = CreateFramePool ( " Button " , self , " BtWLoadoutsTabTemplate " )
end
if self.TitleContainer then
self.TitleContainer . TitleText : SetText ( BTWLOADOUTS_LOADOUTS )
else
self.TitleText : SetText ( BTWLOADOUTS_LOADOUTS )
self.TitleText : SetHeight ( 24 )
end
self.Bg : SetPoint ( " TOPLEFT " , 0 , - 21 ) -- Fixed gap between border
end
function BtWLoadoutsFrameMixin : SetTitle ( text )
if self.TitleContainer then
self.TitleContainer . TitleText : SetText ( text )
else
self.TitleText : SetText ( text )
end
end
function BtWLoadoutsFrameMixin : OnDragStart ( )
self : StartMoving ( ) ;
end
function BtWLoadoutsFrameMixin : OnDragStop ( )
self : StopMovingOrSizing ( ) ;
end
function BtWLoadoutsFrameMixin : OnMouseUp ( )
if self.Essences . pending ~= nil then
self.Essences . pending = nil
SetCursor ( nil ) ;
self : Update ( ) ;
end
end
function BtWLoadoutsFrameMixin : OnEnter ( )
if self.Essences . pending ~= nil then
SetCursor ( " interface/cursor/cast.blp " ) ;
end
end
function BtWLoadoutsFrameMixin : OnLeave ( )
SetCursor ( nil ) ;
end
function BtWLoadoutsFrameMixin : OnResizeStop ( )
BtWLoadoutsFrameSettings = BtWLoadoutsFrameSettings or { } ;
local frame = self : GetCurrentTab ( ) ;
local w , h = self : GetSize ( ) ;
BtWLoadoutsFrameSettings [ frame.segment or frame : GetParentKey ( ) ] = {
w = w ,
h = h ,
} ;
self.Sidebar : CreateButtons ( )
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : OnTabChanged ( )
local frame = self : GetCurrentTab ( ) ;
local minW , minH , maxW , maxH = self : GetResizeBounds ( )
if frame.GetMaxWidth then
maxW = math.max ( minW , frame : GetMaxWidth ( ) ) ;
else
maxW = minW ;
end
local w , h = minW , minH
if BtWLoadoutsFrameSettings then
local settings = BtWLoadoutsFrameSettings [ frame.segment or frame : GetParentKey ( ) ] ;
if settings then
w , h = settings.w , settings.h ;
end
end
self : SetResizeBounds ( minW , minH , maxW , maxH )
self : SetWidth ( math.max ( minW , math.min ( w , maxW ) ) ) ;
end
function BtWLoadoutsFrameMixin : SetLoadout ( set )
self.Loadouts . set = set ;
wipe ( self.Loadouts . temp ) ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetTalentSet ( set )
self.Talents . set = set ;
wipe ( self.Talents . temp ) ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetPvPTalentSet ( set )
self.PvPTalents . set = set ;
wipe ( self.PvPTalents . temp ) ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetEssenceSet ( set )
self.Essences . set = set ;
wipe ( self.Essences . temp ) ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetEquipmentSet ( set )
self.Equipment . set = set ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetActionBarSet ( set )
self.ActionBars . set = set ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetConditionSet ( set )
self.Conditions . set = set ;
wipe ( self.Conditions . temp ) ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : SetSetByID ( setType , setID )
local frame = setType == " loadout " and self.TabFrames [ 1 ] or self.TabSegments [ setType ]
if frame then
PanelTemplates_SetTab ( self , frame : GetID ( ) )
frame : SetSetByID ( setID )
self : Update ( )
end
end
function BtWLoadoutsFrameMixin : GetCurrentTab ( )
local selectedTab = PanelTemplates_GetSelectedTab ( self ) or 1
return self.TabFrames [ selectedTab ]
end
function BtWLoadoutsFrameMixin : Update ( )
local selectedTab = PanelTemplates_GetSelectedTab ( self ) or 1
if self.TabFrames [ selectedTab ] . enabled == false then
selectedTab = 1
PanelTemplates_SetTab ( self , selectedTab )
end
self.Export : Hide ( )
for id , frame in ipairs ( self.TabFrames ) do
frame : SetShown ( id == selectedTab )
end
self.TabFrames [ selectedTab ] : Update ( self )
end
function BtWLoadoutsFrameMixin : OnButtonClick ( button )
self : GetCurrentTab ( ) : OnButtonClick ( button )
end
function BtWLoadoutsFrameMixin : OnSidebarItemClick ( button )
self : GetCurrentTab ( ) : OnSidebarItemClick ( button )
end
function BtWLoadoutsFrameMixin : OnSidebarItemDoubleClick ( button )
self : GetCurrentTab ( ) : OnSidebarItemDoubleClick ( button )
end
function BtWLoadoutsFrameMixin : OnSidebarItemDragStart ( button )
self : GetCurrentTab ( ) : OnSidebarItemDragStart ( button )
end
function BtWLoadoutsFrameMixin : OnHelpTipManuallyClosed ( closeFlag )
BtWLoadoutsHelpTipFlags [ closeFlag ] = true ;
self : Update ( ) ;
end
local function OptionsMenu_Init ( self , level , menuList )
if level == 1 then
local info = UIDropDownMenu_CreateInfo ( ) ;
info.isTitle , info.disabled , info.notCheckable = false , false , false ;
info.func = function ( self , key )
Settings [ key ] = not Settings [ key ] ;
end
for i , entry in ipairs ( Settings ) do
info.text = entry.name ;
info.arg1 = entry.key ;
info.checked = Settings [ entry.key ] ;
UIDropDownMenu_AddButton ( info , level ) ;
end
UIDropDownMenu_AddSeparator ( )
info.func = nil
info.text = L [ " Delete Character Data " ]
info.notCheckable = true
info.keepShownOnClick = true
info.hasArrow , info.menuList = true , " delete "
UIDropDownMenu_AddButton ( info , level ) ;
elseif level == 2 and menuList == " delete " then
local info = UIDropDownMenu_CreateInfo ( )
info.notCheckable = true
info.keepShownOnClick = true
for _ , realm in Internal.EnumerateRealms ( ) do
info.text = realm
info.hasArrow , info.menuList = true , realm
UIDropDownMenu_AddButton ( info , level )
end
elseif level == 3 then
local info = UIDropDownMenu_CreateInfo ( )
info.notCheckable = true
info.func = function ( self , slug )
StaticPopup_Show ( " BTWLOADOUTS_DELETECHARACTER " , Internal.GetFormattedCharacterName ( slug , true ) , nil , slug )
end
local playerSlug = Internal.GetCharacterSlug ( )
for _ , character in Internal.EnumerateCharactersForRealm ( menuList ) do
if character ~= playerSlug then
local name = character
local characterInfo = Internal.GetCharacterInfo ( character )
if characterInfo then
local classColor = C_ClassColor.GetClassColor ( characterInfo.class )
name = classColor : WrapTextInColorCode ( characterInfo.name )
end
info.text = name
info.arg1 = character
UIDropDownMenu_AddButton ( info , level )
end
end
end
end
function BtWLoadoutsFrameMixin : OnOptionsClick ( button )
if not self.OptionsMenu then
self.OptionsMenu = CreateFrame ( " Frame " , self : GetName ( ) .. " OptionsMenu " , self , " UIDropDownMenuTemplate " ) ;
UIDropDownMenu_Initialize ( self.OptionsMenu , OptionsMenu_Init , " MENU " ) ;
end
ToggleDropDownMenu ( 1 , nil , self.OptionsMenu , button , 0 , 0 ) ;
end
function BtWLoadoutsFrameMixin : SetExport ( value )
PanelTemplates_SetTab ( self , 0 ) ;
self : SetTitle ( L [ " Export " ] ) ;
self.Sidebar : Hide ( )
for id , frame in ipairs ( self.TabFrames ) do
frame : SetShown ( false ) ;
end
self.Export : Show ( )
self.AddButton : Hide ( ) ;
self.ActivateButton : Hide ( ) ;
self.RefreshButton : Hide ( ) ;
self.ExportButton : Hide ( ) ;
self.DeleteButton : Hide ( ) ;
self.Export . Scroll.EditBox . text = value : gsub ( " | " , " || " )
self.Export . Scroll.EditBox : SetText ( value : gsub ( " | " , " || " ) )
self.Export . Scroll.EditBox : HighlightText ( )
self.Export . Scroll.EditBox : SetFocus ( )
end
function BtWLoadoutsFrameMixin : OnShow ( )
if not self.initialized then
-- self.Equipment.flyoutSettings = {
-- onClickFunc = PaperDollFrameItemFlyoutButton_OnClick,
-- getItemsFunc = PaperDollFrameItemFlyout_GetItems,
-- -- postGetItemsFunc = PaperDollFrameItemFlyout_PostGetItems,
-- hasPopouts = true,
-- parent = self.Equipment,
-- anchorX = 0,
-- anchorY = -3,
-- verticalAnchorX = 0,
-- verticalAnchorY = 0,
-- };
self : OnTabChanged ( )
self.initialized = true ;
end
BtWLoadoutsHelpTipFlags [ " MINIMAP_ICON " ] = true ;
StaticPopup_Hide ( " BTWLOADOUTS_REQUESTACTIVATE " ) ;
StaticPopup_Hide ( " BTWLOADOUTS_REQUESTMULTIACTIVATE " ) ;
self : Update ( ) ;
end
function BtWLoadoutsFrameMixin : OnHide ( )
-- When hiding the main window we are going to assume that something has dramatically changed and completely redo everything
Internal.ClearConditions ( )
Internal.UpdateConditionsForInstance ( ) ;
local bossID = Internal.UpdateConditionsForBoss ( ) ;
Internal.UpdateConditionsForAffixes ( ) ;
-- Boss is unavailable so dont trigger conditions
if bossID and not Internal.BossAvailable ( bossID ) then
return
end
Internal.TriggerConditions ( ) ;
end
function BtWLoadoutsFrameMixin : SetNPEShown ( show , title , message )
show = not not show
self.AddButton : SetShown ( not show )
self.RefreshButton : SetShown ( not show )
self.ExportButton : SetShown ( not show )
self.ActivateButton : SetShown ( not show )
self.DeleteButton : SetShown ( not show )
self.NPE : SetShown ( show )
if show then
self.NPE . Title : SetText ( title )
self.NPE . Message : SetText ( message )
self.NPE . AddButton.FlashAnim : Play ( )
end
return show
end
end
BtWLoadoutsTalentButtonMixin = { } ;
function BtWLoadoutsTalentButtonMixin : OnLoad ( )
self : RegisterForClicks ( " LeftButtonUp " ) ;
end
function BtWLoadoutsTalentButtonMixin : SetTalent ( id , isPvP )
self.id , self.isPvP = id , isPvP
end
function BtWLoadoutsTalentButtonMixin : Update ( )
local id , isPvP = self.id , self.isPvP
self : SetShown ( id ~= nil )
if not id then
return
end
local grid = self : GetParent ( ) ;
local frame = grid : GetParent ( ) ;
local set = frame.set
local func = isPvP and GetPvpTalentInfoByID or GetTalentInfoByID
local _ , name , texture = func ( id )
self.Name : SetText ( name ) ;
self.Icon : SetTexture ( texture ) ;
if set and set.talents [ id ] then
self.KnownSelection : Show ( ) ;
self.Icon : SetDesaturated ( false ) ;
self.Cover : Hide ( )
self : SetEnabled ( true )
else
self.KnownSelection : Hide ( ) ;
self.Icon : SetDesaturated ( true ) ;
if grid : GetMaxSelections ( ) == 1 then
self.Cover : Hide ( )
self : SetEnabled ( true )
else
self.Cover : SetShown ( grid : IsMaxSelections ( ) )
self : SetEnabled ( not grid : IsMaxSelections ( ) )
end
end
end
function BtWLoadoutsTalentButtonMixin : OnClick ( )
local grid = self : GetParent ( ) ;
local frame = grid : GetParent ( ) ;
local selected = frame.set and frame.set . talents
local talentID = self.id ;
if not selected then
return
end
if selected [ talentID ] then
selected [ talentID ] = nil ;
else
if grid : GetMaxSelections ( ) == 1 then
for _ , talentID in ipairs ( grid.talents ) do
selected [ talentID ] = nil ;
end
end
selected [ talentID ] = true ;
end
grid : Update ( )
end
function BtWLoadoutsTalentButtonMixin : OnEnter ( )
GameTooltip : SetOwner ( self , " ANCHOR_RIGHT " ) ;
if self.isPvP then
GameTooltip : SetPvpTalent ( self.id , true ) ;
else
GameTooltip : SetTalent ( self.id , true ) ;
end
end
function BtWLoadoutsTalentButtonMixin : OnLeave ( )
GameTooltip_Hide ( ) ;
end
local TALENT_ROW_HEIGHT = 51
BtWLoadoutsTalentSelectionMixin = { }
function BtWLoadoutsTalentSelectionMixin : OnLoad ( )
self.talents = { }
self.maxSelection = 1
self.Buttons = { }
self.BackgroundPool = CreateTexturePool ( self , " BACKGROUND " , 0 , " BtWLoadoutsTalentRowBackgroundTemplate " )
self.SeparatorPool = CreateTexturePool ( self , " BORDER " , 0 , " BtWLoadoutsTalentRowSeparatorTemplate " )
self.ButtonPool = CreateFramePool ( " BUTTON " , self , " BtWLoadoutsTalentButtonTemplate " )
end
function BtWLoadoutsTalentSelectionMixin : OnShow ( )
self : Update ( )
end
function BtWLoadoutsTalentSelectionMixin : Update ( )
local rows = math.ceil ( # self.talents / 3 )
if self.BackgroundPool : GetNumActive ( ) ~= rows then
self.BackgroundPool : ReleaseAll ( )
self.SeparatorPool : ReleaseAll ( )
self.ButtonPool : ReleaseAll ( )
table.wipe ( self.Buttons )
local index = 1
local previous = nil
for i = 1 , rows do
local background = self.BackgroundPool : Acquire ( )
background : SetPoint ( " TOPLEFT " , 0 , - 51 * ( i - 1 ) )
background : SetPoint ( " TOPRIGHT " , 0 , - 51 * ( i - 1 ) )
background : Show ( )
do
local separator = self.SeparatorPool : Acquire ( )
separator : SetSize ( 34 , 50 )
separator : SetTexCoord ( 0.5 , 1 , 0 , 1 )
separator : SetPoint ( " LEFT " , background , " LEFT " , 0 , 0 )
separator : Show ( )
end
do
local separator = self.SeparatorPool : Acquire ( )
separator : SetSize ( 34 , 50 )
separator : SetTexCoord ( 0 , 0.5 , 0 , 1 )
separator : SetPoint ( " RIGHT " , background , " RIGHT " , 0 , 0 )
separator : Show ( )
end
do
local separator = self.SeparatorPool : Acquire ( )
separator : SetPoint ( " CENTER " , background , " LEFT " , 190 , 0 )
separator : Show ( )
end
do
local separator = self.SeparatorPool : Acquire ( )
separator : SetPoint ( " CENTER " , background , " RIGHT " , - 190 , 0 )
separator : Show ( )
end
do
local button = self.ButtonPool : Acquire ( )
button : SetPoint ( " LEFT " , background , " LEFT " , 0 , 0 )
button : SetID ( index )
self.Buttons [ index ] = button
index = index + 1
end
do
local button = self.ButtonPool : Acquire ( )
button : SetPoint ( " LEFT " , background , " LEFT " , 190 , 0 )
button : SetID ( index )
self.Buttons [ index ] = button
index = index + 1
end
do
local button = self.ButtonPool : Acquire ( )
button : SetPoint ( " LEFT " , background , " LEFT " , 190 * 2 , 0 )
button : SetID ( index )
self.Buttons [ index ] = button
index = index + 1
end
end
self : SetHeight ( rows * TALENT_ROW_HEIGHT )
end
for index , button in ipairs ( self.Buttons ) do
button : SetTalent ( self.talents [ index ] , self.isPvP )
button : Update ( )
end
end
function BtWLoadoutsTalentSelectionMixin : SetMaxSelections ( value )
self.maxSelection = value
self : Update ( )
end
function BtWLoadoutsTalentSelectionMixin : GetMaxSelections ( )
return self.maxSelection
end
function BtWLoadoutsTalentSelectionMixin : IsMaxSelections ( )
local frame = self : GetParent ( )
local selected = frame.set and frame.set . talents
if not selected then
return false
end
local count = 0
for _ , talentID in ipairs ( self.talents ) do
if selected [ talentID ] then
count = count + 1
if count == self.maxSelection then
return true
end
end
end
return false
end
function BtWLoadoutsTalentSelectionMixin : SetTalents ( tbl , isPvP )
self.talents , self.isPvP = tbl , ( isPvP and true or false )
self : Update ( )
end
-- [[ LOG ]]
BtWLoadoutsLogFrameMixin = { }
function BtWLoadoutsLogFrameMixin : OnLoad ( )
tinsert ( UISpecialFrames , self : GetName ( ) ) ;
self : RegisterForDrag ( " LeftButton " ) ;
if self.TitleContainer then
self.TitleContainer . TitleText : SetText ( BTWLOADOUTS_LOG )
else
self.TitleText : SetText ( BTWLOADOUTS_LOG )
self.TitleText : SetHeight ( 24 )
end
end
function BtWLoadoutsLogFrameMixin : OnDragStart ( )
self : StartMoving ( ) ;
end
function BtWLoadoutsLogFrameMixin : OnDragStop ( )
self : StopMovingOrSizing ( ) ;
end
function Internal . ClearLog ( )
BtWLoadoutsLogFrame.Scroll . EditBox : SetText ( " " )
end
local lastPass = false
function Internal . LogNewPass ( )
if not lastPass then
BtWLoadoutsLogFrame.Scroll . EditBox : Insert ( string.format ( " [%.03f] %s \n " , GetTime ( ) , " --- NEW PASS --- " ) )
lastPass = true
end
end
function Internal . LogMessage ( ... )
BtWLoadoutsLogFrame.Scroll . EditBox : Insert ( string.format ( " [%.03f] %s \n " , GetTime ( ) , string.format ( ... ) : gsub ( " | " , " || " ) ) )
lastPass = false
end
-- [[ CUSTOM EVENT HANDLING ]]
local eventHandlers = { }
function Internal . OnEvent ( event , callback )
if not eventHandlers [ event ] then
eventHandlers [ event ] = { }
end
eventHandlers [ event ] [ callback ] = true
end
function Internal . Call ( event , ... )
local callbacks = eventHandlers [ event ]
local result = true
if callbacks then
for callback in pairs ( callbacks ) do
if callback ( event , ... ) == false then
result = false
end
end
end
return result
end
-- [[ Slash Command ]]
-- /btwloadouts activate loadout Raid
-- /btwloadouts activate talents Outlaw: Mythic Plus
SLASH_BTWLOADOUTS1 = " /btwloadouts "
SLASH_BTWLOADOUTS2 = " /btwl "
SlashCmdList [ " BTWLOADOUTS " ] = function ( msg )
local command , rest = msg : match ( " ^[%s]*([^%s]+)(.*) " ) ;
if command == " activate " or command == " a " then
local aType , rest = rest : match ( " ^[%s]*([^%s]+)(.*) " ) ;
local set ;
if aType == " action-bars " then
aType = " actionbars "
end
if aType == " profile " or aType == " loadout " then
local num = tonumber ( rest )
if num then
set = Internal.GetProfile ( num ) ;
else
set = Internal.GetProfileByName ( rest ) ;
end
else
local segment = Internal.GetLoadoutSegment ( aType )
if segment then
local num = tonumber ( rest )
local subset
if num then
subset = segment.get ( num )
else
subset = segment.getByName ( rest )
end
if subset then
set = {
[ segment.id ] = { subset.setID }
}
end
else
-- Assume profile
rest = aType .. rest ;
if tonumber ( rest ) then
set = Internal.GetProfile ( tonumber ( rest ) ) ;
else
set = Internal.GetProfileByName ( rest ) ;
end
end
end
if set and Internal.IsLoadoutActivatable ( set ) then
Internal.ActivateProfile ( set ) ;
else
print ( L [ " Could not find a valid set " ] ) ;
end
elseif command == " minimap " or command == " m " then
Settings.minimapShown = not Settings.minimapShown ;
elseif command == " log " or command == " l " then
if BtWLoadoutsLogFrame : IsShown ( ) then
BtWLoadoutsLogFrame : Hide ( )
else
BtWLoadoutsLogFrame : Show ( )
end
elseif command == nil then
if BtWLoadoutsFrame : IsShown ( ) then
BtWLoadoutsFrame : Hide ( )
else
BtWLoadoutsFrame : Show ( )
end
else
-- Usage
end
end
if OneRingLib then
local AB = assert ( OneRingLib.ext . ActionBook : compatible ( 2 , 14 ) , " A compatible version of ActionBook is required " )
AB : AugmentCategory ( " BtWLoadouts " , function ( category , add )
local items = { }
do
for id , set in pairs ( BtWLoadoutsSets.profiles ) do
if type ( set ) == " table " then
if Internal.IsLoadoutActivatable ( set ) then
items [ # items + 1 ] = set
end
end
end
table.sort ( items , function ( a , b )
if a.specID ~= b.specID then
return ( a.specID or 1000 ) < ( b.specID or 1000 )
end
return a.name < b.name
end )
for _ , set in ipairs ( items ) do
add ( " btwloadoutprofile " , set.setID )
end
end
do
wipe ( items )
for id , set in pairs ( BtWLoadoutsSets.talents ) do
if type ( set ) == " table " then
if Internal.IsLoadoutActivatable ( {
talents = { set.setID }
} ) then
items [ # items + 1 ] = set
end
end
end
table.sort ( items , function ( a , b )
if a.specID ~= b.specID then
return a.specID < b.specID
end
return a.name < b.name
end )
for _ , set in ipairs ( items ) do
add ( " btwloadouttalent " , set.setID )
end
end
do
wipe ( items )
for id , set in pairs ( BtWLoadoutsSets.pvptalents ) do
if type ( set ) == " table " then
if Internal.IsLoadoutActivatable ( {
pvptalents = { set.setID }
} ) then
items [ # items + 1 ] = set
end
end
end
table.sort ( items , function ( a , b )
if a.specID ~= b.specID then
return a.specID < b.specID
end
return a.name < b.name
end )
for _ , set in ipairs ( items ) do
add ( " btwloadoutpvptalent " , set.setID )
end
end
do
wipe ( items )
for id , set in pairs ( BtWLoadoutsSets.essences ) do
if type ( set ) == " table " then
if Internal.IsLoadoutActivatable ( {
essences = { set.setID }
} ) then
items [ # items + 1 ] = set
end
end
end
table.sort ( items , function ( a , b )
if a.role ~= b.role then
return a.role < b.role
end
return a.name < b.name
end )
for _ , set in ipairs ( items ) do
add ( " btwloadoutessences " , set.setID )
end
end
do
wipe ( items )
for id , set in pairs ( BtWLoadoutsSets.equipment ) do
if type ( set ) == " table " then
if Internal.IsLoadoutActivatable ( {
equipment = { set.setID }
} ) then
items [ # items + 1 ] = set
end
end
end
table.sort ( items , function ( a , b )
return a.name < b.name
end )
for _ , set in ipairs ( items ) do
add ( " btwloadoutequipment " , set.setID )
end
end
end )
do
local function hint ( id )
local set = BtWLoadoutsSets.profiles [ id ]
local usable = Internal.IsLoadoutActivatable ( set )
return usable , false , nil , set.name
end
local function activate ( id )
local set = BtWLoadoutsSets.profiles [ id ]
if set then
Internal.ActivateProfile ( set )
end
end
local map = { }
AB : RegisterActionType ( " btwloadoutprofile " , function ( id )
if not map [ id ] then
map [ id ] = AB : CreateActionSlot ( hint , id , " func " , activate , id )
end
return map [ id ]
end , function ( id )
local set = BtWLoadoutsSets.profiles [ id ]
local category
if set.specID then
local _ , specName , _ , _ , _ , classFile = GetSpecializationInfoByID ( set.specID )
local classColor = C_ClassColor.GetClassColor ( classFile ) ;
category = format ( " %s - %s " , L [ " Loadout " ] , classColor : WrapTextInColorCode ( specName ) )
else
category = L [ " Loadout " ]
end
return category , set.name , nil
end )
end
do
local function hint ( id )
local set = BtWLoadoutsSets.talents [ id ]
local usable = Internal.IsLoadoutActivatable ( {
talents = { set.setID }
} )
return usable , false , nil , set.name
end
local function activate ( id )
local set = BtWLoadoutsSets.talents [ id ]
if set then
Internal.ActivateProfile ( {
talents = { set.setID }
} ) ;
end
end
local map = { }
AB : RegisterActionType ( " btwloadouttalent " , function ( id )
if not map [ id ] then
map [ id ] = AB : CreateActionSlot ( hint , id , " func " , activate , id )
end
return map [ id ]
end , function ( id )
local set = BtWLoadoutsSets.talents [ id ]
local category
if set.specID then
local _ , specName , _ , _ , _ , classFile = GetSpecializationInfoByID ( set.specID )
local classColor = C_ClassColor.GetClassColor ( classFile ) ;
category = format ( " %s - %s " , L [ " Talents " ] , classColor : WrapTextInColorCode ( specName ) )
else
category = L [ " Talents " ]
end
return category , set.name , nil
end )
end
do
local function hint ( id )
local set = BtWLoadoutsSets.pvptalents [ id ]
local usable = Internal.IsLoadoutActivatable ( {
pvptalents = { set.setID }
} )
return usable , false , nil , set.name
end
local function activate ( id )
local set = BtWLoadoutsSets.pvptalents [ id ]
if set then
Internal.ActivateProfile ( {
pvptalents = { set.setID }
} ) ;
end
end
local map = { }
AB : RegisterActionType ( " btwloadoutpvptalent " , function ( id )
if not map [ id ] then
map [ id ] = AB : CreateActionSlot ( hint , id , " func " , activate , id )
end
return map [ id ]
end , function ( id )
local set = BtWLoadoutsSets.pvptalents [ id ]
local category
if set.specID then
local _ , specName , _ , _ , _ , classFile = GetSpecializationInfoByID ( set.specID )
local classColor = C_ClassColor.GetClassColor ( classFile ) ;
category = format ( " %s - %s " , L [ " PvP Talents " ] , classColor : WrapTextInColorCode ( specName ) )
else
category = L [ " PvP Talents " ]
end
return category , set.name , nil
end )
end
do
local function hint ( id )
local set = BtWLoadoutsSets.essences [ id ]
local usable = Internal.IsLoadoutActivatable ( {
essences = { set.setID }
} )
return usable , false , nil , set.name
end
local function activate ( id )
local set = BtWLoadoutsSets.essences [ id ]
if set then
Internal.ActivateProfile ( {
essences = { set.setID }
} ) ;
end
end
local map = { }
AB : RegisterActionType ( " btwloadoutessences " , function ( id )
if not map [ id ] then
map [ id ] = AB : CreateActionSlot ( hint , id , " func " , activate , id )
end
return map [ id ]
end , function ( id )
local set = BtWLoadoutsSets.essences [ id ]
local category
if set.role then
category = format ( " %s - %s " , L [ " Essences " ] , _G [ set.role ] )
else
category = L [ " Essences " ]
end
return category , set.name , nil
end )
end
do
local function hint ( id )
local set = BtWLoadoutsSets.equipment [ id ]
local usable = Internal.IsLoadoutActivatable ( {
equipment = { set.setID }
} )
return usable , false , nil , set.name
end
local function activate ( id )
local set = BtWLoadoutsSets.equipment [ id ]
if set then
Internal.ActivateProfile ( {
equipment = { set.setID }
} ) ;
end
end
local map = { }
AB : RegisterActionType ( " btwloadoutequipment " , function ( id )
if not map [ id ] then
map [ id ] = AB : CreateActionSlot ( hint , id , " func " , activate , id )
end
return map [ id ]
end , function ( id )
local set = BtWLoadoutsSets.equipment [ id ]
local category = L [ " Equipment " ]
return category , set.name , nil
end )
end
end