view Gui.lua @ 105:c6c748a5823b tip

Collaborative list trimming 80% functional Updates for the zone-in problem
author John@Yosemite-PC
date Sun, 06 May 2012 08:33:34 -0400
parents f844309a0e35
children
line wrap: on
line source
local AceGUI = LibStub("AceGUI-3.0")
local bsk=bsk
local _G=_G
local table=table 
local pairs=pairs
local setmetatable=setmetatable
local ipairs=ipairs
local string=string
local sformat=string.format
local tostring=tostring
local type=type
local getn=getn
setfenv(1,bsk)

local copy = function(t)
    local c = {}
    if not t then return c end
    for i,v in pairs(t) do c[i] = v end
    return c
end
local colorize = function(str,color)
    if str==nil or str=="" then return "" end
    if type(color) == "table" then
        color = string.format("%02x%02x%02x",255*color.r,255*color.g,255*color.b)
    end
    if color == nil then return str end
    return "|cff"..tostring(color or "ffffff")..str.."|r"
end

local CreateListSelector = function(SListPopulator)
    PersonList:RefreshRaidList()
    local pulldown = AceGUI:Create("Dropdown")
    local pull = {}
    local lids = LootLists:GetAllIds()
    for _,v in pairs(lids) do
        local l = LootLists:Select(v)
        pull[l:GetId()] = l:GetName()
        if l:GetLength() > 0 then
            pulldown:SetItemDisabled(i,true)
        end
    end
    pulldown:SetWidth(175)
    pulldown:SetList(pull)
    SListPopulator:SetSwidget(pulldown)
    pulldown:SetCallback("OnValueChanged", function(_,_,value) SListPopulator:PulldownEvent(value) end)
    if stateactivelist > 0 then SListPopulator:PulldownEvent(stateactivelist) end -- default value
    return pulldown
end

local f, right -- important gui elements
local escapeButton = 
{
    shown = false,
    ["IsShown"] = function(self) return self.shown end,
    ["Hide"] = function(self) if f then AceGUI:Release(f); self.shown=false; f=nil end end
}

SelectorListEventDispatcher =
{
    listeners = nil,
    target = nil,
    line = nil,
    ["SetTarget"] = function(self,other)
        self.target = other 
        self.target:SetCallback("OnSelectionCleared",function(...) self:OnSelectionCleared(...) end)
        self.target:SetCallback("OnSelection",function(...) self:OnSelection(...) end)
    end,
    ["RegisterListener"] = function(self,other) table.insert(self.listeners,other) end,
    ["OnSelectionCleared"] = function(self,_)
        self.line = nil
        self:Event("OnSelectionCleared")
    end,
    ["OnSelection"] = function(self,_,_,line)
        self.line = line
        self:Event("OnSelection",line)
    end,
    ["Event"] = function(self,event,arg)
        if not self.target then error("Event called with no listener...") end
        if not self.listeners then return end
        for i,v in pairs(self.listeners) do
            --bsk.print("listener")
            if type(v) == "table" then
                if v[event] then
                    v[event](v,arg)
                end
            elseif type(v) == "function" then
                v(event,arg)
            elseif type(v) ~= "nil" then -- allow nils to pass quietly
                _G.error("Bad listener - "..type(v))
            end
        end
    end,
    ["Release"] = function(self) self.listeners = {}; self.target=nil; self.line=nil end,
    ["LatestValue"] = function(self) return self.line end
}
function SelectorListEventDispatcher:new()
    local t = {}
    setmetatable(t,SelectorListEventDispatcher)
    self.__index = self
    t.listeners = {}
    return t
end

SListEventDispatch = SelectorListEventDispatcher:new()
LListEventDispatch = SelectorListEventDispatcher:new()
RListEventDispatch = SelectorListEventDispatcher:new()

function ConvertLe2Line(le)
    local line = {value=le:GetId(),text=le:GetName(),icon=[[Interface\Glues\CharacterCreate\UI-CharacterCreate-Classes]]}
    line.iconCoords=_G.CLASS_ICON_TCOORDS[le:GetClass()]
    line.textPlain = line.text
    line.text=colorize(line.text,_G.RAID_CLASS_COLORS[le:GetClass()])
    return line
end

local SListPopulator =
{
    filtered = false,
    widget = nil,
    swidget = nil,
    data = nil,
    lref = nil,

    ["Release"] = function(self) self.filtered, self.widget, self.swidget, self.data, self.lref = false, nil, nil, nil, nil end,
    ["Redraw"] = function(self)
        if self.lref == nil or self.widget == nil then return end -- don't do work if not fully initialized
        self.data = {}
        for le in self.lref:OrderedListEntryIter() do
            local disabled = not PersonList:IsActive(le:GetId()) 
            if not self.filtered or not disabled then
                local line = ConvertLe2Line(le)
                line.disabled = disabled
                table.insert(self.data,line)
            end
        end
        self.widget:SetList(self.data)
        SListEventDispatch:Event("Redraw")
    end,
    ["SetSwidget"] = function(self,w) 
        if type(w) ~= "table" or type(w.SetList) ~= "function" then
            _G.error("Bad SetWidget")
        end
        self.swidget = w
    end,
    ["SetWidget"] = function(self,w) 
        if type(w) ~= "table" or type(w.SetList) ~= "function" then
            _G.error("Bad SetWidget")
        end
        self.widget = w
    end,
    ["SetFiltered"] = function(self,value) 
        self.filtered = value
        self:Redraw()
    end,
    ["SelectList"] = function(self,value,nocomm) 
        self.swidget:SetValue(value)
        local l = LootLists:Select(value)
        if l ~= self.lref then
            self.lref = l
            self:Redraw() 
        end
        if nocomm then InitiateActiveList(value) end
    end,


    ["PulldownEvent"] = function(self,value)
        self:SelectList(value)
        if admin and state == "looting" then
            InitiateActivateList(value)
        end
    end,
    ["DataEvent"] = function(self)
        self:Redraw()
    end,
    ["StateEvent"] = function(self)
        -- todo: events still happen even if the gui is closed. protect the api.

        print("State event in SL: ", state, admin)
        if state == "bidding" or (state == "looting" and not admin) then
            self.swidget:SetDisabled(true)
            self:SelectList(stateactivelist)
        else
            self.swidget:SetDisabled(false)
        end
        -- if bidding then disable pulldown
        -- if looting and not admin then disable pulldown
        -- if looting and admin then enable pulldown
        -- otherwise enable pulldown
    end,
    ["ActiveListEvent"] = function(self)
        self:SelectList(stateactivelist)
    end,



    ["GetMe"] = function(self)
        local me = _G.UnitName("player")
        for i,v in pairs(self.data) do
            if v.textPlain == me then
                return v
            end
        end
    end,
}

local LListPopulator =
{
    data = {},
    widget = nil,
    ["Release"] = function(self) self.data = {}; self.widget = nil end,
    ["ItemListEvent"] = function(self) self:Redraw() end,
    ["Redraw"]= function(self)
        self.data = {}
        for i,v in pairs(stateitemlist) do
            local entry = {value=i, text=v.link, link=v.link, mlid=v.mlid, disabled=v.disabled}
            table.insert(self.data,entry)
        end
        if self.widget then
            self.widget:SetList(self.data)
            LListEventDispatch:Event("Redraw")
        end
    end,
    ["SetWidget"] = function(self,w)
        if type(w) ~= "table" or type(w.SetList) ~= "function" then
            _G.error("Bad SetWidget")
        end
        self.widget = w
        --if debug then
        --    self.data = {
        --        {
        --            value=1, 
        --            text = "|cffa335ee|Hitem:77109:4080:4009:0:0:0:0:0:85:0|h[Band of Reconstruction]|h|r",
        --            link = "|cffa335ee|Hitem:77109:4080:4009:0:0:0:0:0:85:0|h[Band of Reconstruction]|h|r",
        --        },
        --        {
        --            value=2,
        --            text = "|cffa335ee|Hitem:19351:0:0:0:0:0:0:0:85:0|h[Maladath, Runed Blade of the Black Flight]|h|r",
        --            link = "|cffa335ee|Hitem:19351:0:0:0:0:0:0:0:85:0|h[Maladath, Runed Blade of the Black Flight]|h|r"
        --        },
        --        {
        --            value=3,
        --            text = "|cffa335ee|Hitem:31986:0:0:0:0:0:0:0:85:0|h[Merciless Gladiator's Crossbow of the Phoenix]|h|r",
        --            link = "|cffa335ee|Hitem:31986:0:0:0:0:0:0:0:85:0|h[Merciless Gladiator's Crossbow of the Phoenix]|h|r"
        --        },
        --        {
        --            value=4,
        --            text = "|cffa335ee|Hitem:65003:0:0:0:0:0:0:0:85:0|h[Reclaimed Ashkandi, Greatsword of the Brotherhood]|h|r",
        --            link = "|cffa335ee|Hitem:65003:0:0:0:0:0:0:0:85:0|h[Reclaimed Ashkandi, Greatsword of the Brotherhood]|h|r"
        --        },
        --        {
        --            value=5,
        --            text = "|cffff8000|Hitem:19019:0:0:0:0:0:0:0:85:0|h[Thunderfury, Blessed Blade of the Windseeker]|h|r",
        --            link = "|cffff8000|Hitem:19019:0:0:0:0:0:0:0:85:0|h[Thunderfury, Blessed Blade of the Windseeker]|h|r"
        --        },
        --    }
        --end
        self:Redraw()
    end,
}

local RListPopulator =
{
    widget = nil,
    ["RollEvent"] = function(self) self:Redraw() end,
    ["Release"] = function(self) self.widget = nil end,
    ["Redraw"] = function(self)
        local list = {}
        for i,v in pairs(statebids) do
            table.insert(list,v)
        end
        for i,v in pairs(staterolls) do
            local roll
            for r,s in pairs(staterollvalues) do
                if s.value == v.value then
                    roll = r
                    break
                end
            end
            print("Inserting a roll ", v.value, roll)

            local c = copy(v)
            c.disabled = false
            c.text = c.text .. " (roll "..roll..")"
            table.insert(list,c)
        end
        self.widget:SetList(list)
        RListEventDispatch:Event("Redraw")
    end,
    ["SetWidget"] = function(self,w)
        if type(w) ~= "table" or type(w.SetList) ~= "function" then
            _G.error("Bad SetWidget")
        end
        self.widget = w
        --if debug then
        --    local dummydata = {}
        --    local tree = SListPopulator.data
        --    for i,v in pairs(tree) do dummydata[i] = copy(v); dummydata[i].disabled = false end
        --    if dummydata[2] then dummydata[2].text = dummydata[2].text .. " (roll 73)" end
        --    self.data = dummydata
        --end
        self:Redraw()
    end,
    ["Convert"] = function(who,roll) -- convert an LE object into one suitable to put in a SelectorList
        local new = copy(who)
        new.disabled = false -- todo: should be unnessary - they can't get on the list like this
        if roll then
            new.text = new.text .. " (roll 73)"
        end
        return new
    end,
}

local BZPopulator =
{
    group = nil,
    ["SetGroup"] = function(self,g)
        if type(g) ~= "table" or type(g.AddChild) ~= "function" then
            _G.error("Bad SetGroup for BZPopulator")
        end
        self.group = g
    end,


    ["Release"] = function(self) self.group = nil; RListEventDispatch:Release(); RListPopulator:Release() end,  

    ["StateEvent"] = function(self)
        if state == "bidding" then

            local spacer = AceGUI:Create("Label")
            spacer:SetText(" ")
            spacer:SetFullWidth(true)
            local spacer2 = AceGUI:Create("Label") -- don't try to combine this with "spacer" - you can't add a child more than once
            spacer2:SetText(" ")
            spacer2:SetFullWidth(true)

            local label = AceGUI:Create("Label")
            label:SetText("Bidding now open for ...")
            local biddingOn = AceGUI:Create("InteractiveLabel")
            biddingOn.userdata = { stateitem.link } 
            biddingOn:SetText(biddingOn.userdata[1])
            biddingOn:SetFullWidth(true)
            biddingOn:SetCallback("OnEnter", function(widget) _G.GameTooltip:SetOwner(widget.frame,"ANCHOR_RIGHT");  _G.GameTooltip:SetHyperlink(widget.userdata[1]); _G.GameTooltip:Show() end )
            biddingOn:SetCallback("OnLeave", function(widget) _G.GameTooltip:Hide() end )
            local b1 = AceGUI:Create("SelectorList")
            b1:SetNumLines(6)
            b1:SetInteractive(admin)
            local bidTitle = AceGUI:Create("Label")
            bidTitle:SetText("Current bids")
            bidTitle:SetFullWidth(true)

            local bidRetractButton = AceGUI:Create("Button")
            bidRetractButton:SetText("Place Bid")
            bidRetractButton:SetWidth(100)
            bidRetractButton:SetCallback("OnClick", function(widget) InitiateBid(SListPopulator:GetMe()) end)

            local rollButton = AceGUI:Create("Button")
            rollButton:SetText("Offset Roll")
            rollButton:SetWidth(100)
            rollButton:SetCallback("OnClick", function(widget) InitiateRollRequest(SListPopulator:GetMe()) end) -- todo: wrong behavior. GetMe will nil if the person isn't on the currently selected loot list. this could easily happen. return a new thingy instead
            local retractButton = AceGUI:Create("Button")
            retractButton:SetText("Retract")
            retractButton:SetWidth(100)
            retractButton:SetCallback("OnClick", function(widget) InitiateRetract(SListPopulator:GetMe()) end)

            RListEventDispatch:SetTarget(b1)
            RListPopulator:SetWidget(b1)

            local g1
            if admin then
                b1.alignoffset = 0.25 -- or else g1 won't align well
                g1 = AceGUI:Create("SimpleGroup")
                g1.alignoffset = 0.25
                g1:SetWidth(120)
                g1:SetLayout("List")

                -- todo: convoluted and repetitive - surely there's a
                -- better way than this ...
                adminForce = AceGUI:Create("Button")
                if SListEventDispatch:LatestValue() then
                    adminForce:SetText(sformat("Force bid (%s)",SListEventDispatch:LatestValue().textPlain))
                    adminForce:SetDisabled(false)
                else
                    adminForce:SetText("Force bid")
                    adminForce:SetDisabled(true)
                end
                adminForce:SetWidth(160)
                adminForce:SetCallback("OnClick",function(widget) InitiateBid(SListEventDispatch:LatestValue()) end)
                adminForce.userdata = 
                {
                    widget = adminForce,
                    ["Redraw"] = function(self,_) self.widget:SetDisabled(true); self.widget:SetText("Force bid") end,
                    ["OnSelection"] = function(self,_) self.widget:SetDisabled(false); self.widget:SetText(sformat("Force bid (%s)",SListEventDispatch:LatestValue().textPlain)) end,
                    ["OnSelectionCleared"] = function(self) self.widget:SetDisabled(true); self.widget:SetText("Force bid") end
                }
                SListEventDispatch:RegisterListener(adminForce.userdata)

                adminRetract = AceGUI:Create("Button")
                if RListEventDispatch:LatestValue() then
                    adminRetract:SetText(sformat("Retract bid (%s)",RListEventDispatch:LatestValue().textPlain))
                    adminRetract:SetDisabled(false)
                else
                    adminRetract:SetText("Retract bid")
                    adminRetract:SetDisabled(true)
                end
                adminRetract:SetWidth(160)
                adminRetract.userdata = 
                {
                    widget = adminRetract,
                    ["Redraw"] = function(self,_) self.widget:SetDisabled(true); self.widget:SetText("Retract bid") end,
                    ["OnSelection"] = function(self,_) self.widget:SetDisabled(false); self.widget:SetText(sformat("Retract bid (%s)",RListEventDispatch:LatestValue().textPlain)) end,
                    ["OnSelectionCleared"] = function(self) self.widget:SetDisabled(true); self.widget:SetText("Retract bid") end
                }
                adminRetract:SetCallback("OnClick",function(widget) InitiateRetract(RListEventDispatch:LatestValue()) end)
                RListEventDispatch:RegisterListener(adminRetract.userdata)
                adminRetract:SetDisabled(true)

                g1:AddChildren(adminForce,adminRetract)
            end

            self.group:AddChildren(spacer,label,biddingOn,bidRetractButton,rollButton,retractButton,spacer2,bidTitle,b1)
            if admin then self.group:AddChildren(g1) end

        else


            self.group:ReleaseChildren()
            RListEventDispatch:Release()
            RListPopulator:Release() 
        end

    end,
    
    
}

DataEventDispatch =
{
    -- todo: batch events
    listeners = {},
    ["DataEvent"] = function(self,_) --todo: pass along the received event
        for i,v in pairs(self.listeners) do
            if v and v["DataEvent"] then
                v:DataEvent()
            end
        end
    end,
    ["RegisterListener"] = function(self,listener)
        if not listener or not listener["DataEvent"] then
            _G.error("Bad listener")
        end
        table.insert(self.listeners,listener)
    end
}

AdminLootButtons =
{
    openButton = nil,
    assignButton = nil,
    suicideButton = nil,
    -- todo - open roll button
    
    eventsFromLL = 
    {
        ["Redraw"] = function(self) AdminLootButtons:Redraw() end,
        ["OnSelection"] = function(self) AdminLootButtons:Redraw() end,
        ["OnSelectionCleared"] = function(self) AdminLootButtons:Redraw() end,
    },
    eventsFromSL = 
    {
        ["Redraw"] = function(self) AdminLootButtons:Redraw() end,
        ["OnSelection"] = function(self) AdminLootButtons:Redraw() end,
        ["OnSelectionCleared"] = function(self) AdminLootButtons:Redraw() end,
    },
    ["StateEvent"] = function(self) self:Redraw() end,
    ["RollEvent"] = function(self) self:Redraw() end,

    ["SetButtons"] = function(self,open,assign,suicide)
        self.openButton = open
        self.assignButton = assign
        self.suicideButton = suicide
        SListEventDispatch:RegisterListener(self.eventsFromSL)
        LListEventDispatch:RegisterListener(self.eventsFromLL)
        self:Redraw()
    end,
    ["Release"] = function(self)
        self.openButton = nil
        self.assignButton = nil
        self.suicideButton = nil
    end,

    ["Redraw"] = function(self)
        if state == "neutral" then -- gray all buttons
            self.openButton:SetText("Open Bids")
            self.openButton:SetDisabled(true)
            self.assignButton:SetText("Assign")
            self.assignButton:SetDisabled(true)
            self.suicideButton:SetText("Suicide")
            self.suicideButton:SetDisabled(true)
        elseif state == "looting" then
            if LListEventDispatch.line then
                self.openButton:SetDisabled(false)
                self.openButton:SetText("Open Bids")
                self.openButton:SetCallback("OnClick", function(widget) InitiateOpenBid(LListEventDispatch:LatestValue()) end)
            else
                self.openButton:SetText("Open Bids")
                self.openButton:SetDisabled(true)
            end
            if LListEventDispatch.line and SListEventDispatch.line then
                self.assignButton:SetText("Assign")
                self.assignButton:SetDisabled(false)
                self.assignButton:SetCallback("OnClick", function(widget) FreeLoot(LListEventDispatch:LatestValue(),SListEventDispatch:LatestValue()) end)
                self.suicideButton:SetText("Suicide")
                self.suicideButton:SetDisabled(false)
                self.suicideButton:SetCallback("OnClick", function(widget) DirectSuicideLoot(LListEventDispatch:LatestValue(),SListEventDispatch:LatestValue(),SListPopulator.lref) end)
            else
                self.assignButton:SetText("Assign")
                self.assignButton:SetDisabled(true)
                self.suicideButton:SetText("Suicide")
                self.suicideButton:SetDisabled(true)
            end
            -- if item selected, light up Open button
            -- if item selected and name selected, light up assign/suicide
            -- buttons
        elseif state == "bidding" then
            self.openButton:SetDisabled(false)
            self.openButton:SetText("Cancel Bidding")
            self.openButton:SetCallback("OnClick", function(widget) InitiateCloseBidding() end)
            self.assignButton:SetText("Finish & Assign")
            self.assignButton:SetDisabled(not (getn(staterolls) > 0 or getn(statebids) > 0))
            self.assignButton:SetCallback("OnClick", function(widget) ExpensiveLoot(LListEventDispatch:LatestValue(),SListPopulator.lref) end) -- todo: problem here - use stateitem instead
            self.suicideButton:SetText(" ")
            self.suicideButton:SetDisabled(true)

            -- change open button to cancel
            -- change assign button to award
            -- disable ... and rename? the third button

        end
    end,
}

function OnInitializeSetStaticData()
    SetChangeListener(DataEventDispatch)
    DataEventDispatch:RegisterListener(SListPopulator)
    RegisterListenerActiveListChanged(SListPopulator)
    RegisterListenerStateChange(SListPopulator)
    RegisterListenerRolls(RListPopulator)
    RegisterItemListListener(LListPopulator)
    RegisterListenerStateChange(BZPopulator)
    if admin then 
        RegisterListenerStateChange(AdminLootButtons)
        RegisterListenerRolls(AdminLootButtons)
    end
end

function CreateGUI()
    -- special registration procedure to be closable with the escape button
    escapeButton.shown = true
    _G["BSK_ESCAPEBUTTON"] = escapeButton
    table.insert(_G.UISpecialFrames, "BSK_ESCAPEBUTTON")

    if f then return end -- no second gui please
    f = AceGUI:Create("Frame")

    f:SetCallback("OnClose",function(widget) escapeButton.shown = false; AceGUI:Release(widget); f=nil; right=nil; SListEventDispatch:Release(); LListEventDispatch:Release(); SListPopulator:Release(); RListEventDispatch:Release(); LListPopulator:Release(); RListPopulator:Release(); BZPopulator:Release(); AdminLootButtons:Release() end)
    f:SetTitle("BSK")
    f:SetLayout("Flow")
    f:SetHeight(680) 
    f:SetWidth(580)

    local left = AceGUI:Create("InlineGroup")
    left:SetLayout("List")
    left:SetWidth(175)
    left:SetFullHeight(true)
    left.alignoffset=0.25 -- hack, as per http://forums.wowace.com/showthread.php?t=17114

    right = AceGUI:Create("InlineGroup")
    right:SetLayout("Flow")
    right:SetWidth(700-175-160)
    right:SetFullHeight(true)
    right.alignoffset=0.25

    local t1 = AceGUI:Create("SelectorList")
    t1:SetNumLines(25)
    t1:SetFullWidth(true)
    t1:SetInteractive(admin)
    SListEventDispatch:SetTarget(t1)
    SListPopulator:SetWidget(t1)

    local p1 = CreateListSelector(SListPopulator)
    p1:SetFullWidth(true)

    left:AddChild(p1)
    left:AddChild(t1)

    local t2 = AceGUI:Create("SelectorList")
    t2:SetNumLines(7)
    t2:SetFullWidth(true)
    t2:EnableButtonTooltips(true)
    LListEventDispatch:SetTarget(t2)
    LListPopulator:SetWidget(t2)

    biddingZone = AceGUI:Create("SimpleGroup")
    biddingZone:SetLayout("Flow")
    biddingZone:SetFullWidth(true)
    BZPopulator:SetGroup(biddingZone)

    local alb1, alb2, alb3
    if admin then 
        alb1 = AceGUI:Create("Button")
        alb1:SetWidth(120)
        --alb1:SetText("Open Bids")
        --alb1.userdata = 
        --{
        --    state = false,
        --    widget = alb1,
        --    ["Redraw"] = function(self,_) self.widget:SetDisabled(true); self.item = nil end,
        --    ["OnSelection"] = function(self,value) self.widget:SetDisabled(false); self.item = value end,
        --    ["OnSelectionCleared"] = function(self) self.widget:SetDisabled(true); self.item = nil end
        --}
        --alb1:SetDisabled(true)
        --LListEventDispatch:RegisterListener(alb1.userdata)
        --alb1:SetCallback("OnClick", 
        --    function(widget) 
        --        if widget.userdata.state then -- we were bidding when the button was pressed
        --            widget:SetText("Open Bids")
        --            InitiateCloseBidding() -- todo: plug in loot award, etc
        --        else
        --            widget:SetText("Close bids")
        --            InitiateOpenBid(LListEventDispatch:LatestValue())
        --        end
        --        widget.userdata.state = not widget.userdata.state
        --    end
        --)

        alb2 = AceGUI:Create("Button")
        alb2:SetWidth(120)
        --alb2:SetText("Assign")
        --alb2.userdata =
        --{
        --    widget = alb2,
        --    ["OnUpdate"] = function(self) self.widget:SetDisabled(not (self.slist.checked and self.llist.checked)) end,
        --}
        --alb2.userdata.slist = 
        --{
        --    parent = alb2.userdata,
        --    checked = false,
        --    ["Redraw"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --    ["OnSelection"] = function(self) self.checked = true; self.parent:OnUpdate() end,
        --    ["OnSelectionCleared"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --}
        --alb2.userdata.llist = 
        --{
        --    parent = alb2.userdata,
        --    checked = false,
        --    ["Redraw"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --    ["OnSelection"] = function(self) self.checked = true; self.parent:OnUpdate() end,
        --    ["OnSelectionCleared"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --}
        --SListEventDispatch:RegisterListener(alb2.userdata.slist)
        --LListEventDispatch:RegisterListener(alb2.userdata.llist)

        alb3 = AceGUI:Create("Button")
        alb3:SetWidth(120)
        --alb3:SetText("Suicide")
        --alb3.userdata = -- TODO: holy hell, come up with a pattern or something for this ....
        --{
        --    widget = alb3,
        --    ["OnUpdate"] = function(self) self.widget:SetDisabled(not (self.slist.checked and self.llist.checked)) end,
        --}
        --alb3.userdata.slist = 
        --{
        --    parent = alb3.userdata,
        --    checked = false,
        --    ["Redraw"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --    ["OnSelection"] = function(self) self.checked = true; self.parent:OnUpdate() end,
        --    ["OnSelectionCleared"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --}
        --alb3.userdata.llist = 
        --{
        --    parent = alb3.userdata,
        --    checked = false,
        --    ["Redraw"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --    ["OnSelection"] = function(self) self.checked = true; self.parent:OnUpdate() end,
        --    ["OnSelectionCleared"] = function(self) self.checked = false; self.parent:OnUpdate() end,
        --}
        --SListEventDispatch:RegisterListener(alb3.userdata.slist)
        --LListEventDispatch:RegisterListener(alb3.userdata.llist)
        AdminLootButtons:SetButtons(alb1,alb2,alb3)
    end

    local suicideSelected, undo
    if admin then

        suicideSelected = AceGUI:Create("Button")
        suicideSelected:SetFullWidth(true)
        suicideSelected:SetText("Suicide")
        suicideSelected:SetCallback("OnClick",
            function(_)
                local p = SListEventDispatch:LatestValue()
                local lref = SListPopulator.lref
                lref:SuicidePerson(p.value)
            end
        )

        -- use userdata + SListEventDispatch to toggle state
        suicideSelected.userdata = 
        {
            widget = suicideSelected,
            ["Redraw"] = function(self,_) self.widget:SetDisabled(true) end,
            ["OnSelection"] = function(self,_) self.widget:SetDisabled(false) end,
            ["OnSelectionCleared"] = function(self) self.widget:SetDisabled(true) end
        }
        SListEventDispatch:RegisterListener(suicideSelected.userdata)

        undo = AceGUI:Create("Button")
        undo:SetText("Undo / out of order")
        undo:SetFullWidth(true)
        undo:SetDisabled(true)
    end

    local filter = AceGUI:Create("CheckBox")
    filter:SetLabel("Only show active")
    filter:SetFullWidth(true)
    filter:SetValue(false)
    SListPopulator:SetFiltered(false)
    filter:SetCallback("OnValueChanged",function(widget,_,value) SListPopulator:SetFiltered(value) end)

    left:AddChildren(filter)
    if admin then left:AddChildren(suicideSelected,undo) end
    right:AddChildren(t2)
    if admin then right:AddChildren(alb1,alb2,alb3) end
    right:AddChildren(biddingZone)
    f:AddChildren(left,right)


end