-- ------------------------------------------------------------------------------ --
-- TradeSkillMaster_Destroying --
-- http://www.curse.com/addons/wow/tradeskillmaster_destroying --
-- --
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
-- All Rights Reserved* - Detailed license information included with addon. --
-- ------------------------------------------------------------------------------ --
-- load the parent file (TSM) into a local variable and register this file as a module
local TSM = select ( 2 , ... )
local GUI = TSM : NewModule ( " GUI " , " AceEvent-3.0 " )
-- loads the localization table --
local L = LibStub ( " AceLocale-3.0 " ) : GetLocale ( " TradeSkillMaster_Destroying " )
local private = { data = { } , ignore = { } }
TSMAPI : RegisterForTracing ( private , " TSM_Destroying.GUI_private " )
function GUI : OnEnable ( )
private.frame = private : CreateDestroyingFrame ( )
TSMAPI : CreateEventBucket ( " BAG_UPDATE " , function ( ) private : UpdateST ( ) end , 0.2 )
GUI : RegisterEvent ( " LOOT_SLOT_CLEARED " , private.LootChanged )
GUI : RegisterEvent ( " LOOT_OPENED " , private.LootOpened )
GUI : RegisterEvent ( " LOOT_CLOSED " , private.LootChanged )
GUI : RegisterEvent ( " UNIT_SPELLCAST_INTERRUPTED " )
GUI : RegisterEvent ( " UI_ERROR_MESSAGE " , function ( _ , msg ) if msg == ERR_INVALID_ITEM_TARGET or msg == SPELL_FAILED_ERROR then private.LootChanged ( ) end end )
TSMAPI : CreateTimeDelay ( " destroyingSTUpdate " , 1 , function ( ) private : UpdateST ( ) end )
end
function GUI : ShowFrame ( )
private.hidden = nil
private : UpdateST ( true )
end
function private : CreateDestroyingFrame ( )
local frameDefaults = {
x = 850 ,
y = 450 ,
width = 200 ,
height = 220 ,
scale = 1 ,
}
local frame = TSMAPI : CreateMovableFrame ( " TSMDestroyingFrame " , frameDefaults )
frame : SetFrameStrata ( " HIGH " )
TSMAPI.Design : SetFrameBackdropColor ( frame )
local title = TSMAPI.GUI : CreateLabel ( frame )
title : SetText ( " TSM_Destroying " )
title : SetPoint ( " TOPLEFT " )
title : SetPoint ( " TOPRIGHT " )
title : SetHeight ( 20 )
local line = TSMAPI.GUI : CreateVerticalLine ( frame , 0 )
line : ClearAllPoints ( )
line : SetPoint ( " TOPRIGHT " , - 25 , - 1 )
line : SetWidth ( 2 )
line : SetHeight ( 22 )
local closeBtn = TSMAPI.GUI : CreateButton ( frame , 18 )
closeBtn : SetPoint ( " TOPRIGHT " , - 3 , - 3 )
closeBtn : SetWidth ( 19 )
closeBtn : SetHeight ( 19 )
closeBtn : SetText ( " X " )
closeBtn : SetScript ( " OnClick " , function ( )
if InCombatLockdown ( ) then return end
TSM : Print ( L [ " Hiding frame for the remainder of this session. Typing '/tsm destroy' will open the frame again. " ] )
private.hidden = true
frame : Hide ( )
end )
TSMAPI.GUI : CreateHorizontalLine ( frame , - 23 )
local stContainer = CreateFrame ( " Frame " , nil , frame )
stContainer : SetPoint ( " TOPLEFT " , 0 , - 25 )
stContainer : SetPoint ( " BOTTOMRIGHT " , 0 , 30 )
TSMAPI.Design : SetFrameColor ( stContainer )
local stCols = {
{
name = L [ " Item " ] ,
width = 0.6 ,
} ,
{
name = L [ " Stack Size " ] ,
width = 0.4 ,
align = " CENTER " ,
} ,
}
local handlers = {
OnClick = function ( _ , data , self , button )
if not data then return end
if button == " RightButton " then
if IsShiftKeyDown ( ) then
TSM.db . global.ignore [ data.itemString ] = true
TSM : Printf ( L [ " Ignoring all %s permanently. You can undo this in the Destroying options. " ] , data.link )
TSM.Options : UpdateIgnoreST ( )
else
private.ignore [ data.itemString ] = true
TSM : Printf ( L [ " Ignoring all %s this session (until your UI is reloaded). " ] , data.link )
end
private : UpdateST ( )
end
end ,
OnEnter = function ( _ , data , self )
if not data then return end
local color = TSMAPI.Design : GetInlineColor ( " link " )
GameTooltip : SetOwner ( self , " ANCHOR_RIGHT " )
TSMAPI : SafeTooltipLink ( data.itemString )
-- GameTooltip:AddLine(data.link)
GameTooltip : AddLine ( " - - - " )
GameTooltip : AddLine ( format ( L [ " %sRight-Click|r to ignore this item for this session. Hold %sshift|r to ignore permanently. You can remove items from permanent ignore in the Destroying options. " ] , color , color ) , 1 , 1 , 1 , 1 , true )
GameTooltip : Show ( )
end ,
OnLeave = function ( )
GameTooltip : ClearLines ( )
GameTooltip : Hide ( )
end
}
local st = TSMAPI : CreateScrollingTable ( stContainer , stCols , handlers , 12 )
st : SetData ( { } )
st : DisableSelection ( true )
frame.st = st
local destroyBtn = TSMAPI.GUI : CreateButton ( frame , 14 , " TSMDestroyButton " , true )
destroyBtn : SetPoint ( " BOTTOMLEFT " , 3 , 3 )
destroyBtn : SetPoint ( " BOTTOMRIGHT " , - 3 , 3 )
destroyBtn : SetHeight ( 20 )
destroyBtn : SetText ( L [ " Destroy Next " ] )
destroyBtn : SetAttribute ( " type1 " , " macro " )
destroyBtn : SetAttribute ( " macrotext1 " , " " )
destroyBtn : SetScript ( " PreClick " , function ( )
if not destroyBtn : IsVisible ( ) or # private.data == 0 then
destroyBtn : SetAttribute ( " macrotext1 " , " " )
else
local data = private.data [ 1 ]
private.tempData = data
destroyBtn : SetAttribute ( " macrotext1 " , format ( " /cast %s; \n /use %d %d " , data.spell , data.bag , data.slot ) )
destroyBtn : Disable ( )
TSMAPI : CancelFrame ( " destroyEnableDelay " )
TSMAPI : CreateTimeDelay ( " destroyEnableDelay " , 3 , function ( ) if not UnitCastingInfo ( " player " ) and not LootFrame : IsVisible ( ) then destroyBtn : Enable ( ) end end )
private.highStack = data.numDestroys > 1
private.currentSpell = data.spell
end
end )
frame.destroyBtn = destroyBtn
return frame
end
-- combine partial stacks
function private : Stack ( )
local partialStacks = { }
for bag , slot , itemString , quantity in TSMAPI : GetBagIterator ( nil , TSM.db . global.includeSoulbound ) do
local spell , perDestroy = TSM : IsDestroyable ( bag , slot , itemString )
if spell and quantity % perDestroy ~= 0 and not private.ignore [ itemString ] and not TSM.db . global.ignore [ itemString ] then
partialStacks [ itemString ] = partialStacks [ itemString ] or { }
tinsert ( partialStacks [ itemString ] , { bag , slot } )
end
end
for itemString , locations in pairs ( partialStacks ) do
for i =# locations , 2 , - 1 do
local quantity = select ( 2 , GetContainerItemInfo ( unpack ( locations [ i ] ) ) )
local maxStack = select ( 8 , GetItemInfo ( itemString ) )
if quantity == 0 or quantity == maxStack then break end
for j = 1 , i - 1 do
local targetQuantity = select ( 2 , GetContainerItemInfo ( unpack ( locations [ j ] ) ) )
if targetQuantity ~= maxStack then
PickupContainerItem ( unpack ( locations [ i ] ) )
PickupContainerItem ( unpack ( locations [ j ] ) )
end
end
end
end
end
local isDelayed
function private : UpdateST ( forceShow )
if private.hidden then return end
if ( not private.frame or not private.frame : IsVisible ( ) ) and not forceShow and not isDelayed then
TSMAPI : CreateTimeDelay ( " destroyBagUpdateDelay2 " , 1 , function ( ) isDelayed = true private : UpdateST ( ) isDelayed = nil end )
return
end
if InCombatLockdown ( ) then return end
if TSM.db . global.autoStack then
private : Stack ( )
end
local stData = { }
for bag , slot , itemString , quantity in TSMAPI : GetBagIterator ( nil , TSM.db . global.includeSoulbound ) do
if not private.ignore [ itemString ] and not TSM.db . global.ignore [ itemString ] then
local spell , perDestroy = TSM : IsDestroyable ( bag , slot , itemString )
local link = GetContainerItemLink ( bag , slot )
if spell and quantity >= perDestroy then
local row = {
cols = {
{
value = link ,
} ,
{
value = quantity
} ,
} ,
itemString = itemString ,
link = link ,
quantity = quantity ,
bag = bag ,
slot = slot ,
spell = spell ,
perDestroy = perDestroy ,
numDestroys = floor ( quantity / perDestroy ) ,
}
tinsert ( stData , row )
end
end
end
if # stData == 0 then
if forceShow then
TSM : Print ( L [ " Nothing to destroy in your bags. " ] )
end
private.frame . destroyBtn : Disable ( )
private.frame : Hide ( )
elseif ( TSM.db . global.autoShow or forceShow ) and not private.frame : IsVisible ( ) then
TSMAPI : CancelFrame ( " destroyEnableDelay " )
private.frame . destroyBtn : Enable ( )
private.frame : Show ( )
end
private.data = CopyTable ( stData )
private.frame . st : SetData ( stData )
end
function GUI : UNIT_SPELLCAST_INTERRUPTED ( _ , unit )
if unit == " player " and private.frame and private.frame : IsVisible ( ) then
TSMAPI : CancelFrame ( " destroyEnableDelay " )
if InCombatLockdown ( ) then
TSMAPI : CreateTimeDelay ( " destroyEnableDelay " , 1 ,
function ( )
if not UnitCastingInfo ( " player " )
and not LootFrame : IsVisible ( )
and not InCombatLockdown ( ) then
private.frame . destroyBtn : Enable ( )
end
end )
else
private.frame . destroyBtn : Enable ( )
end
end
end
function private : LootOpened ( )
if not private.currentSpell then return end
local temp = { result = { } , time = time ( ) }
for bag , slot , itemString , quantity , locked in TSMAPI : GetBagIterator ( nil , TSM.db . global.includeSoulbound ) do
if locked and TSM : IsDestroyable ( bag , slot , itemString ) then
temp.item = itemString
break
end
end
if temp.item and GetNumLootItems ( ) > 0 then
for i = 1 , GetNumLootItems ( ) do
local itemString = TSMAPI : GetItemString ( GetLootSlotLink ( i ) )
local quantity = select ( 3 , GetLootSlotInfo ( i ) ) or 0
if itemString and quantity > 0 then
temp.result [ itemString ] = quantity
end
end
TSM.db . global.history [ private.currentSpell ] = TSM.db . global.history [ private.currentSpell ] or { }
tinsert ( TSM.db . global.history [ private.currentSpell ] , temp )
TSM.Options : UpdateLogST ( )
end
private.currentSpell = nil
end
function private : LootChanged ( )
if not private.tempData then return end
if not LootFrame : IsVisible ( ) then
if private.frame and private.frame : IsVisible ( ) then
local quantity = select ( 2 , GetContainerItemInfo ( private.tempData . bag , private.tempData . slot ) )
if quantity == private.tempData . quantity or quantity == private.tempData . perDestroy then
TSMAPI : CancelFrame ( " destroyEnableDelay " )
if InCombatLockdown ( ) then
TSMAPI : CreateTimeDelay ( " destroyEnableDelay " , 1 ,
function ( )
if not UnitCastingInfo ( " player " )
and not LootFrame : IsVisible ( )
and not InCombatLockdown ( ) then
private.frame . destroyBtn : Enable ( )
end
end )
else
private.frame . destroyBtn : Enable ( )
end
end
end
elseif private.highStack and GetNumLootItems ( ) <= 1 then
if private.frame and private.frame : IsVisible ( ) then
TSMAPI : CancelFrame ( " destroyEnableDelay " )
if InCombatLockdown ( ) then
TSMAPI : CreateTimeDelay ( " destroyEnableDelay " , 1 ,
function ( )
if not UnitCastingInfo ( " player " )
and not LootFrame : IsVisible ( )
and not InCombatLockdown ( ) then
private.frame . destroyBtn : Enable ( )
end
end )
else
private.frame . destroyBtn : Enable ( )
end
end
end
end