lotrointerface.com
Search Downloads

LoTROInterface SVN SortPack

[/] [trunk/] [JackdawPlugins/] [SortPack/] [Bag.lua] - Rev 165

Compare with Previous | Blame | View Log

--[[Idea;

        Streamline the sort by using the new sorting function attached to listboxes.
        1) Tag each backpack slot with the items weight when added (set to zero when removed)
        2) When an item is added/moved to the pack, or the pack is opened, sort the group that contains it.
        
        This is a huge change, as it would no longer be nessecary (or desireable) to clear the bag when it is opened.
        Indeed, this method could be so secure that it may be worth just resorting each group when the bag is opened/closed or changed (but only if visible!)
        
        ]]




--Needs a tidy!
--Check the bag datais valid.
if SB==nil then SB={} end
if SB.x==nil then                               SB.x=100                                                end     --}
if      SB.y==nil then                          SB.y=100                                                end     --}Position
if      SB.icx==nil then                        SB.icx=4                                                end     --]
if      SB.icy==nil then                        SB.icy=3                                                end     --]Size, in icons
if      SB.override==nil then   SB.override=false                       end     --Override default bags?
if      SB.labelwidth==nil then         SB.labelwidth=80                        end     --Width of the text label for the group.
if      SB.font==nil then                       SB.font="TrajanPro14"   end     --Label font
if      SB.ShowItem==nil then   SB.ShowItem=true                        end     --un-hide a group when an item is looted in it?


--font size
SB.fontsize=string.sub(SB.font,-2)
if SB.fontsize=="ed" then SB.fontsize=13-1 else SB.fontsize=tonumber(SB.fontsize)-1 end

--Frame padding
pad={top=30,side=15,bottom=10}

--Calculate width and maximum height for the bag.
SB.width=SB.labelwidth+36*SB.icx+2*pad.side
SB.maxheight=Turbine.UI.Display.GetHeight()

--Functions
        --Set the sizes of all the areas of the bag.
        function SortBagSetSize()
                SortBag.ListBox:SetSize( SB.labelwidth+SB.icx*36, SortBag:GetHeight()-(pad.top+pad.bottom)+1)
                SortBag.ScrollBar:SetPosition(SB.labelwidth+SB.icx*36+10,pad.top+5)
                SortBag.ScrollBar:SetHeight(SortBag:GetHeight()-(pad.top+pad.bottom)-10)
                SortBag.Resize:SetPosition(SB.width-10,pad.top+10)
                SortBag.Resize:SetSize(10,SortBag:GetHeight()-2*pad.top-10)
                SortBag.ResizeBack:SetSize(10,SortBag:GetHeight()-pad.top-pad.bottom)
                Search.label:SetSize(SB.labelwidth,SB.fontsize)
        end
        
        --Adjust the sizes of the GroupBoxes.
        function SetGroupBoxSize()
                
                if GroupBox==nil then return end
                local height=0
                
                for j=0,#Groups do
                        --Adjust GroupBox Widths
                        GroupBox[j]:SetMaxItemsPerLine(SB.icx)
                        GroupBox[j]:SetWidth(SB.icx*36)
                        
                        --Hide the slot, or adjust its height
                        if Groups[j].hide then 
                                GroupBox[j]:SetHeight(0) 
                                GroupBox[j].label:SetBackColor(Turbine.UI.Color( 1,0.4,0,0 )) 
                        else 
                                GroupBox[j]:SetHeight( math.ceil(GroupBox[j]:GetItemCount()/SB.icx)*36) 
                                GroupBox[j].label:SetBackColor(Turbine.UI.Color( 1,0,0,0.4 ))
                        end
                        
                        --Adjust Label Width,Height
                        GroupBox[j].label:SetWidth(SB.labelwidth)
                        if GroupBox[j]:GetItemCount()>0 then 
                                GroupBox[j].label:SetHeight(SB.fontsize) 
                        else 
                                GroupBox[j].label:SetHeight(0) 
                        end
                        
                        --Add to the height variable
                        height=height+math.max(GroupBox[j]:GetHeight(),GroupBox[j].label:GetHeight())

                end
                if height>SB.maxheight-(pad.top+pad.bottom) then height=SB.maxheight-(pad.top+pad.bottom) end

                --Resize the window to fit the new height NOTE: The SB.fontsize is to accomodate the "search" box
                        SortBag:SetHeight(height+pad.top+pad.bottom+SB.fontsize)
                        
                        --Change the title to show how many empty slots are left
                        SortBag:SetText(GroupBox[0]:GetItemCount().." empty slots left")
        end
        
--Search function now added to the bag!
        Search={}

        Search.label=Turbine.UI.Label()
                Search.label:SetBackColor( Turbine.UI.Color( 1,0.1,0.1,0.1 ) )
                Search.label:SetMultiline(true)
                Search.label:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter )
                Search.label:SetMouseVisible (true)
                Search.label:SetSize(SB.labelwidth,SB.fontsize)
                Search.label.MouseDown=function()
                        Search.Textbox:SetText("")
                        SearchBag("")
                end
                
        Search.Textbox=Turbine.UI.TextBox()
                Search.Textbox:SetSize(200,SB.fontsize)
                
        --Scan the text entered.
        Search.Textbox.TextChanged=function() 
                SearchBag(Search.Textbox:GetText())
        end
        
        function SearchBag(SearchString)
                local txt1=string.lower(SearchString)
                for i=1,size do
                        local item = backpack:GetItem(i)
                        if item~=nil then
                                local itemInfo=item:GetItemInfo();
                                local txt2=string.lower(itemInfo:GetName())
                                if string.find(txt2,txt1) then 
                                        BackpackSlots[i]:SetVisible(true)
                                else
                                        BackpackSlots[i]:SetVisible(false)
                                end
                        end
                end
        end
        
        --populate the bag.
        function populatebag()
                SortBag.ListBox:ClearItems()
                
                --Add the search section. Fonts applied here too.
                SortBag.ListBox:AddItem(Search.label)
                SortBag.ListBox:AddItem(Search.Textbox)
                
                Search.Textbox:SetFont(Turbine.UI.Lotro.Font[SB.font])
                Search.label:SetFont(Turbine.UI.Lotro.Font[SB.font])
                Search.label:SetText( "Search" )
                        
                
                GroupBox={}
                BackpackSlots=nil
                BackpackSlots={}
                
                --Check for font size errors
                if SB.labelwidth<SB.fontsize then SB.labelwidth=SB.fontsize end
                
                --Build VirtPack 
                
                VirtPack=analysepack()
                
                ---Build a box for this group of items. Box 0 is for empty slots.
                for i=0,#Groups do
                        GroupBox[i] = Turbine.UI.ListBox()
                        GroupBox[i]:SetOrientation( Turbine.UI.Orientation.Horizontal )
                        
                        GroupBox[i]:SetAllowDrop( true )
                        GroupBox[i].DragDrop = function( sender, args )
                                --Empty slots allow drag-drop. Hopefully!
                                local shortcut = args.DragDropInfo:GetShortcut();

                                if ( shortcut ~= nil ) then
                                        local item = GroupBox[i]:GetItemAt( args.X, args.Y );
                                        local index 
                                        if item==nil then index=1 else index= item.id end
                                        
                                        backpack:PerformShortcutDrop( shortcut, index, Turbine.UI.Control.IsShiftKeyDown() )
                                end
                        end
                end
                
                --Build the backpack Slots.
                for i=1,size do
                        item = backpack:GetItem(i)
                        if item~=nil then AddCallback(item, "QuantityChanged",  BagQuantityChanged) end
                        BackpackSlots[i]=Turbine.UI.Lotro.ItemControl( item )   
                        BackpackSlots[i].id=i --so it can be passed for item swopping.
                        BackpackSlots[i]:SetBackground( "JackdawPlugins/SortPack/Back.tga" )
                        BackpackSlots[i]:SetBlendMode( Turbine.UI.BlendMode.Overlay )
                end
                
                --Move the items into the boxes
                for i=1,#VirtPack do
                        --if i<10 then Turbine.Shell.WriteLine(VirtPack[i].id) end --Re-enable if the "not sorting correctly" bug rears its head again.
                        BackpackSlots[VirtPack[i].id].Group=VirtPack[i].Group
                        GroupBox[VirtPack[i].Group]:AddItem(BackpackSlots[VirtPack[i].id])
                end
                
                --Add the groups to the backpack
                for j=0,#Groups do
                        --Build a label
                        GroupBox[j].label=Turbine.UI.Label()
                                GroupBox[j].label:SetBackColor( Turbine.UI.Color( 1,0,0,0.4 ) )
                                GroupBox[j].label:SetFont(Turbine.UI.Lotro.Font[SB.font])
                                GroupBox[j].label:SetMultiline(true)
                                GroupBox[j].label:SetTextAlignment( Turbine.UI.ContentAlignment.MiddleCenter )
                                GroupBox[j].label:SetText( Groups[j].Name )
                                GroupBox[j].label:SetMouseVisible (true)
                                GroupBox[j].label:SetSize(SB.labelwidth,0)--Initially of height 0
                                GroupBox[j].label.label=true            
                        
                        if j~=0 then 
                                --Add the label and GroupBox, but not for empty slots
                                SortBag.ListBox:AddItem(GroupBox[j].label)                      
                                SortBag.ListBox:AddItem(GroupBox[j])
                        end
                        
                        --Click events for the labels.
                        GroupBox[j].label.MouseClick=function(sender,args)
                                if ( args.Button == Turbine.UI.MouseButton.Left ) then
                                        --Left Clicking the label collapses this group
                                        Groups[j].hide=not(Groups[j].hide)
                                else
                                        --Right clicking either collapses all groups, if this one is shown, or opens all groups if not.
                                                Groups[j].hide=not(Groups[j].hide)
                                        for i=0,#Groups do
                                                Groups[i].hide=Groups[j].hide
                                        end
                                end
                                SetGroupBoxSize()
                        end
                end
                        --Empty Slots group added last.
                        SortBag.ListBox:AddItem(GroupBox[0].label) 
                        SortBag.ListBox:AddItem(GroupBox[0])
                
                --Function refresh the heights of the group boxes               
                SetGroupBoxSize()
        end
        
        --Show the backpack
        function openbag()
                --Clear out any previous search
                Search.Textbox:SetText("")
                SearchBag("")
                --Show the bag!
                SortBag:SetVisible(true)
        end
        
        --Events here replace the default bags with this one.
        function SBOverride()
                        
                if SB.override then SortBag:SetWantsKeyEvents( true );

                        SortBag.KeyDown = function( sender, args )
                                if ( args.Action == Turbine.UI.Lotro.Action.Escape ) then
                                        SortBag:Close()
                                end

                                if ( args.Action == Turbine.UI.Lotro.Action.ToggleBags or
                                         args.Action == Turbine.UI.Lotro.Action.ToggleBag1 or
                                         args.Action == Turbine.UI.Lotro.Action.ToggleBag2 or
                                         args.Action == Turbine.UI.Lotro.Action.ToggleBag3 or
                                         args.Action == Turbine.UI.Lotro.Action.ToggleBag4 or
                                         args.Action == Turbine.UI.Lotro.Action.ToggleBag5 or
                                         args.Action == Turbine.UI.Lotro.Action.ToggleBag6) 
                                then
                                        if SortBag:IsVisible() then
                                                SortBag:Close()
                                        else
                                                openbag()
                                        end
                                end
                        end
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack1, false )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack2, false )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack3, false )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack4, false )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack5, false )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack6, false )
                else
                        SortBag:SetWantsKeyEvents( false )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack1, true )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack2, true )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack3, true )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack4, true )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack5, true )
                        Turbine.UI.Lotro.LotroUI.SetEnabled( Turbine.UI.Lotro.LotroUIElement.Backpack6, true )
                end
        end
        
        --Next three items update the bag if items are added or removed.


                BagAdd=function( sender, args )
                        
                        --args.Index    = Bag slot
                        --args.Item             = Item object

                        --Remove the slot from the group it is in.
                        
                        for i=0,#Groups do
                                if GroupBox[i]:ContainsItem(BackpackSlots[args.Index]) then GroupBox[i]:RemoveItem(BackpackSlots[args.Index]) end
                        end
                        
                        --Determine which group it belongs to
                        local destination=ItemGroup[ItemCategory[GetCat(args.Item)]]
                        
                        if destination==nil then destination=0 end

                        --Insert the item in that group
                        BackpackSlots[args.Index]:SetItem(args.Item)
                        BackpackSlots[args.Index].Group=destination

                        GroupBox[destination]:InsertItem(position,BackpackSlots[args.Index])
                        
                        if destination~=0 then
                                --Remove every item from that groupbox one at a time and resort them.
                                local temp={}
                                --cycle through the elements checking for weights
                                for i=GroupBox[destination]:GetItemCount(),1,-1 do
                                        temp[i]=GroupBox[destination]:GetItem(i)
                                        temp[i].Weight=weight(temp[i].id)
                                        temp[i].Name=GroupBox[destination]:GetItem(i):GetItem():GetName()
                                end
                                
                                --Remove all the items
                                GroupBox[destination]:ClearItems()
                                
                                --Sort the items according to weight (ignoring alpha. I am happy with this compromise)
                                table.sort(temp, function (a,b) 
                                        if a.Weight == b.Weight then 
                                                --return a.Name < b.Name
                                                --return strip(a.Name)< strip(b.Name)
                                                if revorder then return strip(a.Name)> strip(b.Name) else return strip(a.Name)< strip(b.Name) end
                                        else  
                                                if revorder then return (a.Weight > b.Weight) else return (a.Weight < b.Weight) end
                                        end
                                 end) 
                                
                                --Put the items in the group
                                for i=1,#temp do
                                        GroupBox[destination]:AddItem(temp[i])
                                end             
                        end
                        
                        --Refresh heights
                        SetGroupBoxSize()
                        
                        --Add the quantity changed event
                        AddCallback(args.Item, "QuantityChanged",       BagQuantityChanged)
                        unhide(args.Item)
                end
                
                BagRemove=function( sender, args )
                        
                        --Turbine.Shell.WriteLine("BagRemove "..args.Index)
                        --Note: this is sometimes called when looting *and no item is removed* causing the "empty slot" bug. Annoying, and not my fault!
                        
                        --Also called if a stack is merged.
                        --args.Index    = Bag slot
                        
                        --Remove the quantity changed callback
                        item = backpack:GetItem(args.Index)
                        RemoveCallback(item, "QuantityChanged",         BagQuantityChanged)

                        --Remove item from group
                        GroupBox[BackpackSlots[args.Index].Group]:RemoveItem(BackpackSlots[args.Index])
                        --Make the item for that slot nil
                        BackpackSlots[args.Index]:SetItem(nil)
                        BackpackSlots[args.Index].Group=0
                        --Add it to empty slots.
                        GroupBox[0]:AddItem(BackpackSlots[args.Index])
                        
                        --Refesh Heights
                        SetGroupBoxSize()
                end
                
                BagMove=function( sender, args )
                        --15/12/11 This has changed completely! The notes below are now false.

                        --Turbine.Shell.WriteLine("BagMove Old Index"..args.OldIndex.." New Index "..args.NewIndex)
                        --[[
                        1) If an item has just been moved to an empty slot then just this fires.
                        2) If an item has been swopped with another; Say A in slot n1 with B in slot n2
                                        ItemRemoved fires on slot n1
                                        ItemMoved fires with B from n2 to n1
                                        ItemAdded fires on slot n2 with item A
                        
                        Essentially, item A (the moved item) gets held "in hand" making the target slot empty.
                        
                        Recently I have come to the belief that it is this that causes the bug, and not ItemRemoved.
                        ]]
                                        
                        --args.Item             =Item object of the item that has been moved.
                        --args.NewIndex =Target Slot
                        --args.OldIndex =Destination Slot
                        
                        BackpackSlots[args.NewIndex],BackpackSlots[args.OldIndex]=BackpackSlots[args.OldIndex],BackpackSlots[args.NewIndex]
                        
                        --Refresh heights
                        SetGroupBoxSize()
                        
                end
                
                BagQuantityChanged=function(sender,args)
                        unhide(sender)
                end
                
        function unhide(item)
                if not(SB.ShowItem) then return end
                local destination=ItemGroup[ItemCategory[GetCat(item)]]
                
                if destination==nil then destination=0 end

                --Un-Hide this group
                if Groups[destination].hide then
                        Groups[destination].hide=false
                        SetGroupBoxSize()
                end
        end
                
        AddCallback(backpack, "ItemAdded",                      BagAdd)
        AddCallback(backpack, "ItemRemoved",            BagRemove)
        AddCallback(backpack, "ItemMoved",                      BagMove)
        
--Main Structure; Create the window to hold the backpack slots and populate it.

SortBag = Turbine.UI.Lotro.Window()
        SortBag:SetPosition( SB.x,SB.y )
        SortBag:SetText("SortBag")

SortBag.ListBox = Turbine.UI.ListBox()
        SortBag.ListBox:SetParent( SortBag )
        SortBag.ListBox:SetPosition( pad.side, pad.top )
        SortBag.ListBox:SetMaxItemsPerLine(2)
        SortBag.ListBox:SetOrientation( Turbine.UI.Orientation.Horizontal )
        
        SortBag.ScrollBar=Turbine.UI.Lotro.ScrollBar()
                SortBag.ScrollBar:SetOrientation( Turbine.UI.Orientation.Vertical )
                SortBag.ListBox:SetVerticalScrollBar( SortBag.ScrollBar )
                SortBag.ScrollBar:SetParent(SortBag)
                SortBag.ScrollBar:SetPosition(SB.labelwidth+SB.icx*36+10,pad.top+5)
                SortBag.ScrollBar:SetWidth(10)
        
        --Remove this control when Turbine fix the backpack bug. again.
        SortBag.Control=Turbine.UI.Control()
                SortBag.Control:SetParent(SortBag)
                SortBag.Control:SetMouseVisible(true)
                SortBag.Control:SetBackground(0x41007e26)
                SortBag.Control:SetSize(16,16)
                SortBag.Control:SetPosition(pad.side-15,pad.top-15)
                
        SortBag.Control.MouseClick=function()
                --This was, originally, in Button.lua. And is better there imho.
                local contextMenu = Turbine.UI.ContextMenu()
                contextMenu.items = contextMenu:GetItems()
                
                local option2=Turbine.UI.MenuItem("Re-stack the items - WARNING! EXPERIMENTAL!",true)
                        option2.Click = function () import "JackdawPlugins.SortPack.Stack"      Turbine.Shell.WriteLine("<rgb=#888888>Starting stack")  Stack() end

                local option3=Turbine.UI.MenuItem("Override default bags",true,SB.override)
                        option3.Click = function () SB.override=not(SB.override) SBOverride() end
                
                local option4=Turbine.UI.MenuItem("Open the sort order panel",true)
                        option4.Click = function () import"JackdawPlugins.SortPack.ListOption" ShowListOption() end
                
                local option6=Turbine.UI.MenuItem("Create/Edit custom Categories",true)
                        option6.Click = function () import"JackdawPlugins.SortPack.CustomOption" ShowCustomOption() end
                        
                local option7=Turbine.UI.MenuItem("Show a group on item gain.",true,SB.ShowItem)
                        option7.Click = function () SB.ShowItem=not(SB.ShowItem) end
                
                local option8=Turbine.UI.MenuItem("Open the Debug Window",true)
                        option8.Click = function () import"JackdawPlugins.SortPack.Debug" Debug() end           
                        
                local option5 = Turbine.UI.MenuItem("Select SortBag label font;")
                        contextMenu.SubMenuItems = option5:GetItems()
                        local suboption5={}
                        local font={}
                        j=1
                        for i in pairs(Turbine.UI.Lotro.Font) do 
                                font[j]=i
                                j=j+1
                        end
                        table.sort(font, function (a,b) 
                                        return (a < b) 
                         end)
                         for i=1,#font do
                                suboption5[i] = Turbine.UI.MenuItem(font[i],true,font[i]==SB.font)
                                suboption5[i].Click = function () 
                                        SB.font=font[i]
                                        SB.fontsize=string.sub(SB.font,-2)
                                        if SB.fontsize=="ed" then SB.fontsize=13-1 else SB.fontsize=tonumber(SB.fontsize)-1 end
                                        populatebag()
                                end

                                contextMenu.SubMenuItems:Add(suboption5[i])
                        end

                contextMenu.items:Add(option2)
                contextMenu.items:Add(option5)  
                contextMenu.items:Add(option3)
                contextMenu.items:Add(option7)
                contextMenu.items:Add(option4)
                contextMenu.items:Add(option6)
                contextMenu.items:Add(option8)
                
                contextMenu:ShowMenu()
        end
        
        SortBag.Resize=Turbine.UI.Control()
                SortBag.Resize:SetParent(SortBag)
                SortBag.Resize:SetZOrder(99)
                
                SortBag.ResizeBack=Turbine.UI.Control()
                SortBag.ResizeBack:SetParent(SortBag.Resize)
                SortBag.ResizeBack:SetBackColor(Turbine.UI.Color(0.7,0.3,0.3,1))
                SortBag.ResizeBack:SetVisible(false)
                SortBag.ResizeBack:SetMouseVisible(false)
                
                SortBag.Resize.MouseEnter=function() SortBag.ResizeBack:SetVisible(true) end
                SortBag.Resize.MouseLeave=function() SortBag.ResizeBack:SetVisible(false)  end
                
                SortBag.Resize.MouseDown=function ()
                        draggingr=true
                end
                SortBag.Resize.MouseUp=function ()
                        draggingr=false
                end
                SortBag.Resize.MouseMove=function(sender,args)
                        if draggingr then
                                local oldwidth=SB.width
                                SB.width,dummy=SortBag:GetMousePosition() 
                                
                                if SortBag:IsAltKeyDown() then
                                        SB.labelwidth=SB.width-oldwidth+SB.labelwidth
                                        if SB.labelwidth<SB.fontsize then SB.labelwidth=SB.fontsize end
                                else
                                        SB.icx=math.floor((SB.width-2*pad.side-SB.labelwidth)/36)
                                        SB.icy=math.floor((SB.maxheight-(pad.top+pad.bottom))/36)
                                        if SB.icx<3 then SB.icx=3 end
                                        if SB.icy<1 then SB.icy=1 end
                                end
                                        SB.width=36*SB.icx+2*pad.side+SB.labelwidth
                                        SortBag:SetSize(SB.width,SB.maxheight)
                        end
                end     
                
SortBag.SizeChanged=function()
        SortBagSetSize()
        SetGroupBoxSize()
        
        --Now, if the size of the bag would take the bottom of the bag off the screen, then re-position it.
        local x,y=SortBag:GetPosition()
        if y+SortBag:GetHeight()>SB.maxheight then y=SB.maxheight-SortBag:GetHeight() end
        SortBag:SetPosition(x,y)
end

SortBag:SetSize(SB.width,SB.maxheight)

SortBag.PositionChanged=function()
        local x,y=SortBag:GetPosition()
                if x<0 then x=0 end
                if y<0 then y=0 end
                SortBag:SetPosition(x,y)
                SB.x,SB.y=x,y   
end

populatebag()

SBOverride()

Compare with Previous | Blame


All times are GMT -5. The time now is 06:40 PM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui