--lua
local unpack , select , pairs , strjoin , type , wipe , tostring , tonumber , error , setmetatable , tinsert , tsort , tremove , max , min
= unpack , select , pairs , strjoin , type , wipe , tostring , tonumber , error , setmetatable , table.insert , table.sort , table.remove , math.max , math.min
-- WoW API
local GetSpecializationInfoByID , GetItemStatDelta , IsControlKeyDown , IsShiftKeyDown , SetCursor , ResetCursor , DressUpItemLink , GetItemIcon , GetAddOnMetadata , GetSpecializationInfo , PlaySound , GetNumSpecializations , UnitAffectingCombat
= GetSpecializationInfoByID , GetItemStatDelta , IsControlKeyDown , IsShiftKeyDown , SetCursor , ResetCursor , DressUpItemLink , GetItemIcon , GetAddOnMetadata , GetSpecializationInfo , PlaySound , GetNumSpecializations , UnitAffectingCombat
local BestInSlot , L , AceGUI = unpack ( select ( 2 , ... ) )
local frameName = " BestInSlotFrame "
local frame
local menuItems = { }
local menuLabels
local container , menuContainer
local selectedMenuId = 1
local MINIMUMWIDTH , MINIMUMHEIGHT = 250 , 300
local animating = false
local biggestWidth , biggestHeight
local function getWidthForModule ( module )
local type = type ( module.Width )
if type == " number " then return module.Width
elseif type == " function " then return module.Width ( ) end
end
local function getHeightForModule ( module )
local type = type ( module.Height )
if type == " number " then return module.Height
elseif type == " function " then return module.Height ( ) end
end
local function getBiggestWidth ( )
if not biggestWidth then
biggestWidth = getWidthForModule ( menuItems [ 1 ] )
for i = 2 , # menuItems do
local modWidth = getWidthForModule ( menuItems [ i ] )
if modWidth > biggestWidth then
biggestWidth = modWidth
end
end
end
return biggestWidth
end
local function getBiggestHeight ( )
if not biggestHeight then
biggestHeight = getHeightForModule ( menuItems [ 1 ] )
for i = 2 , # menuItems do
local height = getHeightForModule ( menuItems [ i ] )
if height > biggestHeight then
biggestHeight = height
end
end
end
return biggestHeight
end
local function addGuildInfoToTooltip ( tooltip , itemId , difficultyId )
if BestInSlot.db . char.options . guildtooltip then
local players = BestInSlot : GetGuildMembersByItemID ( itemId , difficultyId )
local first = true
local obtainedPlayers = { }
for player , playerSpecs in pairs ( players ) do
local guildRank = BestInSlot : GetGuildRank ( player )
if guildRank and BestInSlot.db . char.options . showGuildRankInTooltip [ guildRank ] then
local specNames = { }
local specNamesObtained = { }
for specId , obtained in pairs ( playerSpecs ) do
local tbl = specNames
if obtained then tbl = specNamesObtained end
local specName = select ( 2 , GetSpecializationInfoByID ( specId ) )
tinsert ( tbl , specName )
end
if # specNames > 0 then
if first then
tooltip : AddLine ( L [ " The following people in your guild also need this item: " ] , nil , nil , nil , true )
first = false
end
tooltip : AddLine ( ( " - %s (%s) " ) : format ( BestInSlot : GetPlayerString ( player ) , strjoin ( " / " , unpack ( specNames ) ) ) )
end
if # specNamesObtained > 0 then
obtainedPlayers [ player ] = specNamesObtained
end
end
end
first = true
for player , specNames in pairs ( obtainedPlayers ) do
if first then
tooltip : AddLine ( " " )
tooltip : AddLine ( L [ " The following people in your guild already obtained this item " ] , nil , nil , nil , true )
first = false
end
tooltip : AddLine ( ( " - %s (%s) " ) : format ( BestInSlot : GetPlayerString ( player ) , strjoin ( " / " , unpack ( specNames ) ) ) )
end
end
end
--- Helper for starting an animation
local function startAnimating ( )
animating = true
end
--- Helper for stopping an animation
local function stopAnimating ( )
animating = false
end
--- Set the size of the frame
-- @param #number targetWidth The new width
-- @param #number targetHeight the new height
-- @param #function func The function to run when the frame is done resizing
function BestInSlot : SetFrameSize ( targetWidth , targetHeight , func , ... )
if not frame then return end
if self.options . windowFixed then
frame : SetWidth ( getBiggestWidth ( ) )
frame : SetHeight ( getBiggestHeight ( ) )
if func and type ( func ) == " function " then
func ( ... )
end
return
end
local currentWidth , currentHeight = frame.frame . width , frame.frame . height
if not targetWidth then targetWidth = currentWidth end
if not targetHeight then targetHeight = currentHeight end
if targetWidth == currentWidth and targetHeight == currentHeight then
if type ( func ) == " function " then
func ( ... )
end
return
end
if self.options . instantAnimation then
frame : SetHeight ( targetHeight )
frame : SetWidth ( targetWidth )
if type ( func ) == " function " then
func ( ... )
end
else
local ANIMATIONTIME = 500 --milliseconds
local timer = 0
local incWidth = ( targetWidth - currentWidth ) / ( ANIMATIONTIME / 80 )
local incHeight = ( targetHeight - currentHeight ) / ( ANIMATIONTIME / 80 )
startAnimating ( )
local resizeTimerId
local funcArgs = { ... }
resizeTimerId = self : ScheduleRepeatingTimer ( function ( )
if not frame then stopAnimating ( ) BestInSlot : CancelTimer ( resizeTimerId ) end
if incHeight < 0 then
frame : SetHeight ( max ( frame.frame . height + incHeight , targetHeight ) )
else
frame : SetHeight ( min ( frame.frame . height + incHeight , targetHeight ) )
end
if incWidth < 0 then
frame : SetWidth ( max ( frame.frame . width + incWidth , targetWidth ) )
else
frame : SetWidth ( min ( frame.frame . width + incWidth , targetWidth ) )
end
if frame.frame . width == targetWidth and frame.frame . height == targetHeight then
BestInSlot : CancelTimer ( resizeTimerId )
if func and type ( func ) == " function " then
stopAnimating ( )
func ( unpack ( funcArgs ) )
end
end
end ,
0.025 )
end
end
--- Sets the content to the supplied menuWidget
-- @param #table menuWidget An AceGUI Widget with the UserData "id" set to the id of the menu to set the content to
local function SetContent ( menuWidget )
local id = menuWidget : GetUserData ( " id " )
if not id then error ( " The menu widget that has been made didn't provide an id " ) end
if animating then return false end
return BestInSlot : SetMenu ( id )
end
function BestInSlot : SetMenu ( id , ... )
local args = { ... }
local item = menuItems [ id ]
if selectedMenuId then
local selectedItem = menuItems [ selectedMenuId ]
selectedItem : Close ( )
BestInSlot : HideItemTooltip ( )
wipe ( container : GetUserDataTable ( ) )
local menuLabel = menuLabels [ selectedMenuId ]
if menuLabel then
menuLabel : SetColor ( 0.8941 , 0.73725 , 0.01961 )
menuLabel : SetHighlight ( " Interface \\ QuestFrame \\ UI-QuestTitleHighlight " )
end
end
local menuLabel = menuLabels [ id ]
if menuLabel then
menuLabel : SetColor ( 1 , 1 , 1 )
menuLabel : SetHighlight ( " Interface \\ QuestFrame \\ UI-QuestLogTitleHighlight " )
end
container : ReleaseChildren ( )
container : SetLayout ( " Flow " )
self : SetFrameSize ( getWidthForModule ( item ) , getHeightForModule ( item ) , function ( ) container : ResumeLayout ( ) item : Draw ( container , unpack ( args ) ) BestInSlot : CheckTutorials ( item.Description ) end )
selectedMenuId = id
return true
end
function BestInSlot : HideItemTooltip ( )
if GameTooltip : IsShown ( ) then
GameTooltip.itemInfo = nil
GameTooltip : Hide ( )
end
if BISComparisonTooltip then
BISComparisonTooltip : Hide ( )
end
end
local playerClass
function BestInSlot : GetItemTooltip ( itemid , difficulty , frame , itemlink )
if frame then
GameTooltip : SetOwner ( frame.frame )
GameTooltip : SetAnchorType ( " ANCHOR_NONE " )
GameTooltip : SetPoint ( " TOPLEFT " , frame.frame , " TOPRIGHT " , 10 , 0 )
else
GameTooltip : SetOwner ( UIParent )
end
if not self : ItemExists ( itemid ) and itemlink then
GameTooltip : SetHyperlink ( itemlink )
end
local item = self : GetItem ( itemid , difficulty )
if not item then return end
playerClass = playerClass or select ( 3 , UnitClass ( " player " ) )
GameTooltip : SetHyperlink ( item.link , playerClass , select ( 2 , self : GetSelected ( self.SPECIALIZATION ) ) )
GameTooltip.itemInfo = item
if self.options . DEBUG then
GameTooltip : AddLine ( " itemid: " .. tostring ( itemid ) )
GameTooltip : AddLine ( " dungeon: " .. tostring ( item.dungeon ) )
GameTooltip : AddLine ( " bossid: " .. tostring ( item.bossid ) )
GameTooltip : AddLine ( " link: " .. tostring ( item.link ) )
GameTooltip : AddLine ( " difficulty: " .. tostring ( item.difficulty ) )
GameTooltip : AddLine ( " equipslot: " .. tostring ( item.equipSlot ) )
if item.misc then
GameTooltip : AddLine ( " Item is misc source: " .. item.misc )
end
if item.tieritem then
GameTooltip : AddLine ( " Item is tier item " )
end
if item.tiertoken then
GameTooltip : AddLine ( " Item is tier token " )
end
end
GameTooltip : Show ( )
return GameTooltip
end
function BestInSlot : GetItemComparisonTooltip ( tooltip , selectedItem , difficulty )
local compareItem = tooltip.itemInfo
local item = self : GetItem ( selectedItem , difficulty )
if not compareItem then return end
if compareItem.itemid == item.itemid and compareItem.difficulty == item.difficulty then return end --don't show then it's comparing itself!
if not BISComparisonTooltip then
CreateFrame ( " GameTooltip " , " BISComparisonTooltip " , tooltip , " GameTooltipTemplate " )
end
if not BISComparisonTooltip : IsShown ( ) then
BISComparisonTooltip : SetOwner ( BestInSlot.frame . frame )
BISComparisonTooltip : SetAnchorType ( " ANCHOR_NONE " )
BISComparisonTooltip : SetPoint ( " TOPLEFT " , GameTooltip , " TOPRIGHT " )
end
BISComparisonTooltip : SetHyperlink ( item.link , playerClass , select ( 2 , self : GetSelected ( self.SPECIALIZATION ) ) )
local statDelta = GetItemStatDelta ( item.link , compareItem.link )
for stat , value in pairs ( statDelta ) do
BISComparisonTooltip : AddLine ( ( " %s%d %s " .. FONT_COLOR_CODE_CLOSE ) : format ( ( value > 0 and GREEN_FONT_COLOR_CODE or RED_FONT_COLOR_CODE ) , value , tostring ( _G [ stat ] ) ) )
end
BISComparisonTooltip : Show ( )
end
function BestInSlot : GameTooltip_OnTooltipSetItem ( tooltip , ... )
if self.db . char.options . showBiSTooltip and ( self.db . char.options . tooltipCombat or not UnitAffectingCombat ( " player " ) ) then
local _ , link = tooltip : GetItem ( )
if link then
local itemId , instanceID = self : GetItemInfoFromLink ( link )
local exists , existType = self : ItemExists ( itemId )
if not exists then return end
if itemId then
instanceID = tonumber ( instanceID )
instanceID = self : GetDifficultyIdForDungeon ( instanceID , nil , true ) or 1
local bisInfo
if existType == " item " then
bisInfo = self : IsItemBestInSlot ( itemId , instanceID )
else
bisInfo = self : IsTokenBestInSlot ( itemId , instanceID )
end
local isBiS = false --catch empty tables
if bisInfo and type ( bisInfo ) == " table " then
local specsText = " "
local first = true
for specId in pairs ( bisInfo ) do
isBiS = true
if not first then
specsText = specsText .. " / "
end
specsText = specsText .. ( type ( specId ) == " string " and specId or select ( 2 , GetSpecializationInfoByID ( specId ) ) ) --custom lists can just show as custom list, otherwise lookup spec name
first = false
end
if isBiS then
local color = self.colorHighlight
if self : HasItem ( itemId , instanceID , true ) then
color = GREEN_FONT_COLOR_CODE
end
tooltip : AddLine ( ( " %1$s (%2$s) " ) : format ( color .. " BestInSlot " .. self.colorNormal , color .. specsText .. " |r " ) )
end
end
local item = self : GetItem ( itemId )
if item and ( self.db . char.options . tooltipSource or self.options . DEBUG ) then
if item.multiplesources then
tooltip : AddLine ( SOURCES .. " : " )
for dungeonname , v in pairs ( item.multiplesources ) do
for bossid in pairs ( v ) do
tooltip : AddLine ( ( " %s%s %s(%s)|r " ) : format ( self.colorHighlight , self : GetDescription ( self.BOSS , dungeonname , bossid ) , self.colorNormal , dungeonname ) )
end
end
elseif item.dungeon and item.bossid then
tooltip : AddLine ( ( " %s %s%s - %s " ) : format ( SOURCE , self.colorHighlight , self : GetDescription ( self.BOSS , item.dungeon , item.bossid ) , self : GetInstanceName ( item.dungeon ) ) )
elseif item.misc then
tooltip : AddLine ( ( " %s %s%s " ) : format ( SOURCE , self.colorHighlight , item.misc ) )
end
end
if self : ItemExists ( itemId ) then
addGuildInfoToTooltip ( tooltip , itemId , instanceID )
end
end
end
end
end
local function helperOnEnter ( widget , ... )
local itemid = widget : GetUserData ( " itemid " )
local itemlink = widget : GetUserData ( " itemlink " )
local callbacks = widget : GetUserData ( " callbacks " )
local difficulty = widget : GetUserData ( " difficulty " )
if not itemid then return end
BestInSlot : GetItemTooltip ( itemid , difficulty , BestInSlot.frame , itemlink )
if IsControlKeyDown ( ) then
SetCursor ( " INSPECT_CURSOR " )
else
ResetCursor ( )
end
if callbacks.OnEnter then
for i = 1 , # callbacks.OnEnter do
callbacks.OnEnter [ i ] ( widget , ... )
end
end
end
local function helperOnLeave ( widget , ... )
ResetCursor ( )
local callbacks = widget : GetUserData ( " callbacks " )
BestInSlot : HideItemTooltip ( )
if callbacks.OnLeave then
for i = 1 , # callbacks.OnLeave do
callbacks.OnLeave [ i ] ( widget , ... )
end
end
end
local function helperOnClick ( widget , ... )
local itemlink = widget : GetUserData ( " itemlink " )
local callbacks = widget : GetUserData ( " callbacks " )
if not itemlink then return end
if IsShiftKeyDown ( ) then
if not ChatEdit_InsertLink ( itemlink ) then
ChatFrame_OpenChat ( itemlink )
end
elseif IsControlKeyDown ( ) then
DressUpItemLink ( itemlink )
end
if callbacks.OnClick then
for i = 1 , # callbacks.OnClick do
callbacks.OnClick [ i ] ( widget , ... )
end
end
end
local function itemLinkCallback ( self , name , func )
if type ( func ) ~= " function " then error ( " 2nd parameter should be function " ) end
local callbacks = self : GetUserData ( " callbacks " )
if name == " OnEnter " or name == " OnLeave " or name == " OnClick " then
if not callbacks [ name ] then
callbacks [ name ] = { }
end
tinsert ( callbacks [ name ] , func )
else
error ( " Invalid callback method " )
end
end
function BestInSlot : GetItemLinkLabel ( itemid , difficulty , withIcon )
if not withIcon and withIcon ~= false then
withIcon = true
end
if not itemid then
error ( " GetItemLinkLabel cannot be called without itemid argument " )
return
end
local label = AceGUI : Create ( " InteractiveLabel " )
label : SetUserData ( " itemid " , itemid )
label : SetUserData ( " difficulty " , difficulty )
label : SetCallback ( " OnEnter " , helperOnEnter )
label : SetCallback ( " OnLeave " , helperOnLeave )
label : SetCallback ( " OnClick " , helperOnClick )
if itemid ~= " PLACEHOLDER " then
local item = self : GetItem ( itemid , difficulty )
if not item then
label : SetText ( " Undefined itemid " )
else
label : SetUserData ( " itemlink " , item.link )
label : SetText ( item.link )
end
if withIcon then
label : SetImage ( GetItemIcon ( itemid ) )
end
else
label : SetText ( " " )
end
label : SetUserData ( " callbacks " , { } )
return label
end
local UISpecialFramesId
local function frameClosed ( widget )
if UISpecialFrames [ UISpecialFramesId ] == frameName then
tremove ( UISpecialFrames , UISpecialFramesId )
end
BestInSlot : HideFrame ( )
end
local function GetFrame ( )
if frame then return end
frame = AceGUI : Create ( " Frame " )
frame.frame : SetFrameStrata ( " HIGH " )
BestInSlot.frame = frame
--make closable with escape
_G [ frameName ] = frame.frame
tinsert ( UISpecialFrames , frameName )
UISpecialFramesId = # UISpecialFrames
frame : SetTitle ( " Best In Slot Redux " .. GetAddOnMetadata ( " BestInSlotRedux " , " Version " ) )
frame : SetStatusText ( ( " By: %s, %s, %s, %s, %s. " ) : format ( BestInSlot.Author0 , BestInSlot.Author4 , BestInSlot.Author1 , BestInSlot.Author2 , BestInSlot.Author3 ) )
local FrameBackdrop = {
bgFile = " Interface \\ DialogFrame \\ UI-DialogBox-Background-Dark " ,
edgeFile = " Interface \\ DialogFrame \\ UI-DialogBox-Border " ,
tile = true , tileSize = 32 , edgeSize = 32 ,
insets = { left = 8 , right = 8 , top = 8 , bottom = 8 }
}
frame.frame : SetBackdrop ( FrameBackdrop )
frame : SetCallback ( " OnClose " , frameClosed )
frame : EnableResize ( nil )
local dimensionsSet = false
local initItem
if selectedMenuId then --GUI has been opened before
local item = menuItems [ selectedMenuId ]
initItem = item
if item.Height then
frame : SetHeight ( getHeightForModule ( item ) )
frame : SetWidth ( getWidthForModule ( item ) )
dimensionsSet = true
end
end
if not dimensionsSet or BestInSlot.db . char.options . windowFixed then
if BestInSlot.db . char.options . windowFixed then
frame : SetHeight ( getBiggestHeight ( ) )
frame : SetWidth ( getBiggestWidth ( ) )
else
frame : SetHeight ( MINIMUMHEIGHT )
frame : SetWidth ( MINIMUMWIDTH )
end
end
frame : PauseLayout ( )
frame : SetPoint ( " TOPLEFT " , UIParent , " TOPLEFT " , 200 , - 250 )
if not BestInSlot.hasModules then
local label = AceGUI : Create ( " Label " )
label : SetText ( L [ " This addon requires atleast 1 expansion module! Please enable one! " ] )
label : SetFullWidth ( true )
label : SetPoint ( " TOPLEFT " , frame.frame , " TOPLEFT " )
frame : AddChild ( label )
return
end
menuContainer = AceGUI : Create ( " SimpleGroup " )
menuContainer : SetPoint ( " TOPLEFT " , frame.frame , " TOPLEFT " , 10 , - 20 )
menuContainer : SetPoint ( " BOTTOMRIGHT " , frame.frame , " BOTTOMLEFT " , 160 , 50 )
menuContainer : PauseLayout ( )
local previousLabel
menuLabels = { }
for i = 1 , # menuItems do
local item = menuItems [ i ]
if item.IsShown ( ) then
local interactiveLabel = AceGUI : Create ( " InteractiveLabel " )
interactiveLabel : SetText ( item.Description )
interactiveLabel : SetWidth ( 140 )
interactiveLabel : SetFont ( GameFontNormalSmall : GetFont ( ) , 14 , nil )
interactiveLabel : SetUserData ( " name " , item.Description )
interactiveLabel : SetUserData ( " id " , i )
if selectedMenuId and selectedMenuId == i then
interactiveLabel : SetHighlight ( " Interface \\ QuestFrame \\ UI-QuestLogTitleHighlight " )
interactiveLabel : SetColor ( 1 , 1 , 1 )
else
interactiveLabel : SetColor ( 0.8941 , 0.73725 , 0.01961 )
interactiveLabel : SetHighlight ( " Interface \\ QuestFrame \\ UI-QuestTitleHighlight " )
end
interactiveLabel : SetCallback ( " OnClick " , SetContent )
if not previousLabel then
interactiveLabel : SetPoint ( " TOPLEFT " , menuContainer.frame , " TOPLEFT " , 10 , - 10 )
interactiveLabel : SetPoint ( " TOPRIGHT " , menuContainer.frame , " TOPRIGHT " , - 10 , - 10 )
else
interactiveLabel : SetPoint ( " TOPLEFT " , previousLabel.frame , " BOTTOMLEFT " , 0 , - 10 )
interactiveLabel : SetPoint ( " TOPRIGHT " , previousLabel.frame , " BOTTOMRIGHT " , 0 , - 10 )
end
previousLabel = interactiveLabel
menuLabels [ i ] = interactiveLabel
menuContainer : AddChild ( interactiveLabel )
end
end
frame : AddChild ( menuContainer )
frame : SetUserData ( " menu " , menuContainer )
container = AceGUI : Create ( " SimpleGroup " )
container : SetPoint ( " TOPRIGHT " , frame.frame , " TOPRIGHT " , - 20 , - 20 )
container : SetPoint ( " BOTTOMLEFT " , menuContainer.frame , " BOTTOMRIGHT " , 5 , 0 )
container : SetLayout ( " Flow " )
frame : AddChild ( container )
frame : SetUserData ( " content " , container )
if initItem then
initItem : Draw ( container )
BestInSlot : CheckTutorials ( )
end
local windowpos = BestInSlot.db . char.windowpos
if windowpos.point then
frame : ClearAllPoints ( )
frame : SetPoint ( windowpos.point , windowpos.relativeTo , windowpos.relativePoint , windowpos.xOffset , windowpos.yOffset )
end
end
function BestInSlot : HideFrame ( )
if frame then
local point , relativeTo , relativePoint , xOffset , yOffset = frame.frame : GetPoint ( 1 )
self.db . char.windowpos = {
point = point ,
relativeTo = type ( relativeTo ) == " table " and relativeTo : GetName ( ) or relativeTo ,
relativePoint = relativePoint ,
xOffset = xOffset ,
yOffset = yOffset
}
if selectedMenuId then
local item = menuItems [ selectedMenuId ]
if item then
item : Close ( )
end
end
frame.frame : SetBackdrop ( { --set backdrop back to the original backdrop for other users
bgFile = " Interface \\ DialogFrame \\ UI-DialogBox-Background " ,
edgeFile = " Interface \\ DialogFrame \\ UI-DialogBox-Border " ,
tile = true , tileSize = 32 , edgeSize = 32 ,
insets = { left = 8 , right = 8 , top = 8 , bottom = 8 }
} )
frame.frame : SetFrameStrata ( " FULLSCREEN_DIALOG " )
frame : Release ( )
frame = nil
container = nil
menuContainer = nil
PlaySound ( SOUNDKIT.IG_CHARACTER_INFO_CLOSE )
if BestInSlotTutorialFrame : IsVisible ( ) then
BestInSlotTutorialFrame : Hide ( )
end
BestInSlot.frame = nil
menuLabels = nil
end
end
function BestInSlot : GetSelectedMenuItem ( )
return menuItems [ selectedMenuId ] . Description
end
local function defaultDraw ( menu , container )
local label = AceGUI : Create ( " Label " )
label : SetText ( " This menu has not been implemented yet " )
container : AddChild ( label )
end
local function defaultClose ( ) end
local function defaultIsShown ( ) return true end
-- {
-- descr = "Description",
-- draw = drawFunction(),
-- [width = 100,]
-- [height = 100,]
-- [close = closeFunction(),]
-- [isShown = isShownFunction(),]
-- }
local menuPrototype = setmetatable ( {
Draw = defaultDraw ,
Width = 500 ,
Height = 600 ,
Close = defaultClose ,
IsShown = defaultIsShown ,
} ,
{ __index = BestInSlot } )
function BestInSlot : GetMenuPrototype ( menuName )
if not menuName or type ( menuName ) ~= " string " then error ( " GetMenuPrototype must always have a name in the form of a string " ) end
local menuIndex = # menuItems + 1
local prototype = setmetatable ( { Description = menuName , menuindex = menuIndex } , { __index = menuPrototype } )
menuItems [ menuIndex ] = prototype
return prototype
end
-------------------------------------------------
-- Functions for add-on wide selection values
--
local selected
function BestInSlot : InitSelectedSettings ( )
if selected == nil then
selected = self.db . char.selected
local verify = { self.EXPANSION , self.RAIDTIER , self.INSTANCE , self.DIFFICULTY , self.SPECIALIZATION }
local verified = true
for _ , type in pairs ( verify ) do
if not selected [ type ] then
verified = false
break
end
end
if not verified or not tContains ( self : GetInstances ( ) , selected [ self.INSTANCE ] ) then
selected = { } --when not verified, reset selected
self : SetSelected ( self.EXPANSION , self : GetLatest ( self.EXPANSION ) )
self : SetSelected ( self.SPECIALIZATION )
else
self : ValidateSelected ( self.INSTANCE )
end
end
end
function BestInSlot : GetSelected ( bisType )
if not selected then
self : InitSelectedSettings ( )
end
if not selected [ self.SPECIALIZATION ] or selected [ self.SPECIALIZATION ] == - 1 then
self : SetSelected ( self.SPECIALIZATION )
end
if bisType then
if selected [ bisType ] then
if bisType == self.SPECIALIZATION then
return selected [ bisType ] , type ( selected [ bisType ] ) == " string " and self : GetSpecForCustomList ( selected [ bisType ] ) or selected [ bisType ]
end
return selected [ bisType ]
else
error ( " You supplied an invalid type! " )
end
else
return { expansion = selected [ self.EXPANSION ] , raidtier = selected [ self.RAIDTIER ] , instance = selected [ self.INSTANCE ] , difficulty = selected [ self.DIFFICULTY ] , specialization = selected [ self.SPECIALIZATION ] }
end
end
function BestInSlot : ValidateSelected ( type )
if type == self.RAIDTIER then
local expansion = self : GetExpansions ( type , selected [ type ] )
if selected [ self.EXPANSION ] ~= expansion then
self : SetSelected ( self.EXPANSION , expansion )
end
local difficulties = self : GetDifficulties ( type , selected [ type ] )
if not difficulties [ selected [ self.DIFFICULTY ] ] then
self : SetSelected ( self.DIFFICULTY , difficulties [ # difficulties ] )
end
elseif type == self.INSTANCE then
local raidTier = self : GetRaidTiers ( type , selected [ type ] )
if selected [ self.RAIDTIER ] ~= raidTier then
self : SetSelected ( self.RAIDTIER , raidTier )
end
elseif type == self.DIFFICULTY then
local difficulties = self : GetDifficulties ( self.RAIDTIER , selected [ self.RAIDTIER ] )
if selected [ type ] > # difficulties then
self : SetSelected ( type , # difficulties )
end
end
self.db . char.selected = selected
end
local eventBuffer = { }
local eventTimer
local function sendEvents ( )
for k , v in pairs ( eventBuffer ) do
BestInSlot : SendEvent ( " SelectedChange " , k , v )
end
wipe ( eventBuffer )
eventTimer = nil
end
function BestInSlot : SetSelected ( type , value )
if not selected then
self : InitSelectedSettings ( )
end
if value and selected [ type ] == value then return end
if value then
selected [ type ] = value
end
if type == self.EXPANSION then
self : SetSelected ( self.RAIDTIER , self : GetLatest ( self.RAIDTIER , self.EXPANSION , value ) )
elseif type == self.RAIDTIER then
self : SetSelected ( self.INSTANCE , self : GetLatest ( self.INSTANCE , self.RAIDTIER , value ) )
elseif type == self.INSTANCE then
if ( not selected [ self.DIFFICULTY ] ) or # ( self : GetDifficulties ( type , selected [ type ] ) ) < selected [ self.DIFFICULTY ] then
self : SetSelected ( self.DIFFICULTY , self : GetLatest ( self.DIFFICULTY , self.INSTANCE , value ) )
end
elseif type == self.SPECIALIZATION then
if not value then
selected [ self.SPECIALIZATION ] = GetSpecializationInfo ( self : GetSpecialization ( ) )
end
end
eventBuffer [ type ] = value
if not eventTimer then
eventTimer = C_Timer.After ( 0.001 , sendEvents )
end
self : ValidateSelected ( type )
self.db . char.selected = selected
end
local function getRaidTierDropdown ( dropdown )
local order = BestInSlot : GetRaidTiers ( )
local list = { }
for i = 1 , # order do
list [ order [ i ] ] = BestInSlot : GetDescription ( BestInSlot.RAIDTIER , order [ i ] )
end
dropdown : SetList ( list )
local value = BestInSlot : GetSelected ( BestInSlot.RAIDTIER )
dropdown : SetValue ( value )
dropdown : SetLabel ( L [ " Raid Tier " ] )
dropdown : SetUserData ( BestInSlot.RAIDTIER , value )
return dropdown
end
local function getDifficultyDropdown ( dropdown )
local raidTierValue = BestInSlot : GetSelected ( BestInSlot.RAIDTIER )
dropdown : SetList ( BestInSlot : GetDifficulties ( BestInSlot.RAIDTIER , raidTierValue ) )
local value = BestInSlot : GetSelected ( BestInSlot.DIFFICULTY )
dropdown : SetValue ( value )
dropdown : SetLabel ( L [ " Difficulty " ] )
dropdown : SetUserData ( BestInSlot.DIFFICULTY , value )
dropdown : SetUserData ( BestInSlot.RAIDTIER , raidTierValue )
return dropdown
end
local function getSpecializationDropdown ( dropdown )
local customLists = BestInSlot.db . char.customlists
local hasCustomLists = # customLists > 0
dropdown : SetList ( { } )
if hasCustomLists then
dropdown : AddItem ( " _header1 " , L [ " Specialization " ] )
dropdown : SetItemDisabled ( " _header1 " , true )
end
for i = 1 , GetNumSpecializations ( ) do
local id , name = GetSpecializationInfo ( i )
dropdown : AddItem ( id , name )
end
dropdown : SetLabel ( L [ " Specialization " ] )
if # customLists > 0 then
dropdown : AddItem ( " _spacer " , " " )
dropdown : SetItemDisabled ( " _spacer " , true )
dropdown : AddItem ( " _header " , L [ " Custom Lists " ] )
dropdown : SetItemDisabled ( " _header " , true )
for i = 1 , # customLists do
dropdown : AddItem ( customLists [ i ] . name , customLists [ i ] . name )
end
end
local value = BestInSlot : GetSelected ( BestInSlot.SPECIALIZATION )
dropdown : SetValue ( value )
dropdown : SetUserData ( BestInSlot.SPECIALIZATION , value )
end
local function getDungeonDropdown ( dropdown )
dropdown : SetList ( { } )
local options = { }
local instances = BestInSlot : GetInstances ( )
tsort ( instances , function ( a , b ) return BestInSlot : GetRaidTiers ( BestInSlot.INSTANCE , a ) < BestInSlot : GetRaidTiers ( BestInSlot.INSTANCE , b ) end )
local selectedDungeon = BestInSlot : GetSelected ( BestInSlot.INSTANCE )
local lastExpansion
for i = 1 , # instances do
local expansion = BestInSlot : GetExpansions ( BestInSlot.INSTANCE , instances [ i ] )
if expansion ~= lastExpansion then
local name = BestInSlot : GetDescription ( BestInSlot.EXPANSION , expansion )
dropdown : AddItem ( name , " " .. name )
dropdown : SetItemDisabled ( name , true )
lastExpansion = expansion
end
dropdown : AddItem ( instances [ i ] , BestInSlot : GetDescription ( BestInSlot.INSTANCE , instances [ i ] ) )
end
dropdown : SetLabel ( L [ " Raid Instance " ] )
dropdown : SetValue ( selectedDungeon )
dropdown : SetUserData ( BestInSlot.INSTANCE , selectedDungeon )
end
local function dropDownCallback ( dropdown , event , value , ... )
local udt = dropdown : GetUserDataTable ( )
BestInSlot : SetSelected ( udt.type , value )
if udt.customcallback then udt.customcallback ( dropdown , event , value , ... ) end
end
local function dropdownReleased ( dropdown )
BestInSlot : UnregisterEvent ( " SelectedChange " , dropdown : GetUserData ( " eventid " ) )
end
local dropdownConstructors = {
[ BestInSlot.RAIDTIER ] = getRaidTierDropdown ,
[ BestInSlot.INSTANCE ] = getDungeonDropdown ,
[ BestInSlot.DIFFICULTY ] = getDifficultyDropdown ,
[ BestInSlot.SPECIALIZATION ] = getSpecializationDropdown
}
local function verifyRequireChange ( widget , typeChanged , value )
local udt = widget : GetUserDataTable ( )
return udt [ typeChanged ] and udt [ typeChanged ] ~= value or false
end
local function defaultOnChange ( event , typeChanged , valueChanged , dropdown , ... )
if verifyRequireChange ( dropdown , typeChanged , valueChanged ) then
dropdown : SetValue ( valueChanged )
dropdown : SetUserData ( typeChanged , valueChanged )
end
end
local function difficultyOnChange ( event , typeChanged , valueChanged , dropdown , ... )
if typeChanged == BestInSlot.RAIDTIER or typeChanged == BestInSlot.INSTANCE then
dropdownConstructors [ BestInSlot.DIFFICULTY ] ( dropdown )
elseif typeChanged == BestInSlot.DIFFICULTY then
dropdown : SetValue ( valueChanged )
dropdown : SetUserData ( typeChanged , valueChanged )
end
end
local dropdownOnChange = {
[ BestInSlot.RAIDTIER ] = defaultOnChange ,
[ BestInSlot.INSTANCE ] = defaultOnChange ,
[ BestInSlot.DIFFICULTY ] = difficultyOnChange ,
[ BestInSlot.SPECIALIZATION ] = defaultOnChange
}
function BestInSlot : GetDropdown ( type , dropdown , callback )
local dropdown = dropdown or AceGUI : Create ( " Dropdown " )
if not dropdownConstructors [ type ] then error ( " Can't make a dropdown of that type! " ) end
dropdownConstructors [ type ] ( dropdown )
dropdown : SetUserData ( " type " , type )
dropdown : SetUserData ( " customcallback " , callback )
dropdown : SetUserData ( " eventid " , self : RegisterEvent ( " SelectedChange " , dropdownOnChange [ type ] , dropdown ) )
dropdown : SetCallback ( " OnValueChanged " , dropDownCallback )
dropdown : SetCallback ( " OnRelease " , dropdownReleased )
return dropdown
end
local function uneditableOnTextChanged ( widget )
widget : SetText ( widget : GetUserData ( " contents " ) )
end
function BestInSlot : CreateUneditableTextbox ( contents , description , type )
local editBox = AceGUI : Create ( type or " EditBox " )
if description then
editBox : SetLabel ( description )
end
editBox : SetText ( contents )
editBox : SetUserData ( " contents " , contents )
editBox : SetFullWidth ( true )
editBox : SetCallback ( " OnTextChanged " , uneditableOnTextChanged )
return editBox
end
function BestInSlot : QuickCreate ( widgtype , options , addTo , point , ... )
local result = AceGUI : Create ( widgtype )
if options then
for k , v in pairs ( options ) do
if type ( v ) == " table " then
result [ k ] ( result , unpack ( v ) )
else
result [ k ] ( result , v )
end
end
end
if addTo then
if point then
result : SetPoint ( point , addTo.frame , ... )
end
addTo : AddChild ( result )
end
return result
end
function BestInSlot : ShowFrame ( )
if not frame then
GetFrame ( )
PlaySound ( SOUNDKIT.IG_CHARACTER_INFO_OPEN )
end
end
function BestInSlot : ToggleFrame ( )
if not frame then
self : ShowFrame ( )
else
self : HideFrame ( )
end
end
BestInSlot : RegisterSlashCmd ( " show " , ( L [ " %s or %s " ] ) : format ( " /bis " , " /bestinslot " ) , function ( ) BestInSlot : ShowFrame ( ) end , 1 )
BestInSlot : RegisterSlashCmd ( " reset " , ( " /bis %s - %s " ) : format ( " reset " , L [ " Resets the window to it's original position " ] ) , function ( ) if frame then BestInSlot : HideFrame ( ) end wipe ( BestInSlot.db . char.windowpos ) end )