airstruck / luigi

Lovely User Interfaces for Game Inventors
MIT License
114 stars 21 forks source link

Adding buttons to a scroll list #32

Closed rm-code closed 8 years ago

rm-code commented 8 years ago

Quick question. I am working on a UI which has a scrollable list of buttons:

screenshot 2016-01-28 23 16 33

Basically new items should be added to the list when the user drags a folder onto the love window. What's the best way to do this (is it possible at all)?

airstruck commented 8 years ago

Give the widget that holds the buttons an id attribute, something like id = 'buttonList'. Then you can add a new button like this: myLayout.buttonList:addChild { type = 'button', }.

Widget:addChild should probably call reshape on itself but I don't think it does yet, so you might have to call that afterwards or add it to Widget:addChild.

rm-code commented 8 years ago

Works like a charm :+1:

rm-code commented 8 years ago

Follow up:

        for name, path in pairs( config.repositories ) do
            layout.leftScrollPanel:addChild { type = 'button', id = name, text = name };
        end

How do I add a function for that button? I tried this:

layout.leftScrollPanel[name]:onPress( function()
                print( 'Power Rangers are cool' )
            end)

based on a code snippet from your example

    layout.license:onPress(function()
            license:show()
            about:hide()
        end);

I understand there is something different going on, but I couldn't figure it out myself :frowning:

airstruck commented 8 years ago

It would just be layout[name]:onPress(...). The layout is like a flat index for anything with an id attribute.

But, I wouldn't use id for dynamically created widgets. You can do this instead:

    for name, path in pairs( config.repositories ) do
        local button = { type = 'button', text = name }
        layout.leftScrollPanel:addChild(button)
        button:onPress(function() ... end)
    end

This works because the table you use to describe a widget is identical to the widget itself. Or:

    for name, path in pairs( config.repositories ) do
        layout.leftScrollPanel:addChild { type = 'button', text = name }
            :onPress(function() ... end)
    end

This works because Widget:addChild returns the added widget.

local a = { id = 'foo' }
local b = layout.someWidget:addChild(a)
local c = layout.foo
-- a == b == c

There's also another approach you can use, and I think this is really the best way. Most events "bubble," meaning the event fires on the originating widget and each ancestor, all the way up to the layout. You can delegate event handling to an ancestor widget and only write one event handler for all of the buttons. The originating widget is available in event.target. Look at the directional control buttons here for an example.

rm-code commented 8 years ago

Thanks, the code I use now:

        for name, _ in pairs( config.repositories ) do
            local button = { type = 'button', text = name, log = name };
            layout.leftScrollPanel:addChild( button );
        end

        -- Handle directional controls.
        layout:onPress( function ( event )
            layout:hide();
            ScreenManager.switch( 'main', { log = event.target.log, config = config } );
        end)

I like how short it all is :)

airstruck commented 8 years ago

Just keep in mind that your Layout:onPress handler will fire no matter what widget you press, so if you only care about widgets with a log property, you might want something like:

layout:onPress( function ( event )
    local log = event.target.log
    if not log then return end
    layout:hide();
    ScreenManager.switch( 'main', { log = log, config = config } );
end)
rm-code commented 8 years ago

I see. I'll change it.