[solved] [GUI] Passing parameters to callbacks

Discussion of Lua and LuaWML support, development, and ideas.

Moderator: Forum Moderators

Post Reply
white_haired_uncle
Posts: 1203
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

[solved] [GUI] Passing parameters to callbacks

Post by white_haired_uncle »

So I have this ordered list of units which I present in a tree_view along with buttons which will eventually enable the user to move a unit up or down in the list. Currently, I'm trying to use a button with a callback. My problem is I can't figure out how to pass arguments to a callback. This is what I tried, and I know why it's wrong, I just can't think of an alternative.

(There's actually a number of pieces to the following I'm not sure about yet, but I'm stuck on this one for now. Feel free to blast away at anything else you don't like).

Code: Select all

        local function preshow(dialog)
                local function move_up(index)
                        if index == 1 then return end
                        local new_list = {}
                        for i,unit in ipairs(ar_list) do
                                if i == index - 1 then
                                        table.insert(new_list,ar_list[i+1])
                                elseif i == index then
                                        table.insert(new_list,ar_list[i-1])
                                else
                                        table.insert(new_list,ar_list[i])
                                end
                        end
                        ar_list = new_list
                        wesnoth.wml_actions.redraw {}
                end

                for i,unit in ipairs(ar_list) do
                        dialog.autorecall_tv:add_item_of_type("autorecall_node")
                        local units = wesnoth.units.find{ id = unit.id } -- or what? better error handling here 
                        if #units < 1 then
                                wesnoth.interface.add_chat_message(string.format("Ack! %s not found!",unit.id))
                        else
                                local markup = ""
                                if i > wml.variables.max_autorecall then markup = "font-style='oblique'" end
                                dialog.autorecall_tv[i].ar_position.marked_up_text = string.format("<span font_family='monospace'>%d) </span>",i)
                                dialog.autorecall_tv[i].ar_unit.marked_up_text = string.format("<span %s>%s (%s)</span>",markup,units[1].name,
                                        units[1].__cfg.language_name)
                                dialog.autorecall_tv[i].ar_up.on_button_click = move_up(i)
                        end
                end
        end

Code: Select all

wesnoth: src/scripting/lua_widget.cpp:177: void luaW_callwidgetcallback(lua_State*, gui2::widget*, gui2::window*, std::string_view): Assertion `lua_isfunction(L, -1)' failed.
Abort(coredump)
spartan$ /opt/wesnoth-1.17-git/bin/wesnoth --debug --log-debug=scripting/lua
Battle for Wesnoth v1.17.25+dev (88befc29de9-Clean) x86_64
Last edited by white_haired_uncle on March 3rd, 2024, 8:18 pm, edited 1 time in total.
Speak softly, and carry Doombringer.
white_haired_uncle
Posts: 1203
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

Re: [GUI] Passing parameters to callbacks

Post by white_haired_uncle »

Hmm, this seems to work. It's as if i is substituted in the function at the time the function is defined?

Code: Select all

                                dialog.autorecall_tv[i].ar_up.on_button_click = function()
                                        if i == 1 then return end
                                        local new_list = {}
                                        for j,unit in ipairs(ar_list) do
                                                if j == i - 1 then
                                                        table.insert(new_list,ar_list[j+1])
                                                elseif j == i then
                                                        table.insert(new_list,ar_list[j-1])
                                                else
                                                        table.insert(new_list,ar_list[j])
                                                end
                                        end
                                        ar_list = new_list
                                        gui.show_dialog(dialogDefinition,preshow)
   
Well, sort of. I moved a bunch of stuff around and then had to hit escape several times to close the gui. Each time I hit escape the list changed. It's like I'm seeing guis nested in guis. I think I need to find a better way to redraw, or put the whole thing in a while loop, calling show_dialog from callback may not be such a great idea?
Speak softly, and carry Doombringer.
User avatar
Celtic_Minstrel
Developer
Posts: 2233
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: [GUI] Passing parameters to callbacks

Post by Celtic_Minstrel »

white_haired_uncle wrote: March 1st, 2024, 1:00 am

Code: Select all

                                dialog.autorecall_tv[i].ar_up.on_button_click = move_up(i)
No, what are you doing. That won't work. You can't call the function and assign its result as a callback. Just assign the function directly:

Code: Select all

                                dialog.autorecall_tv[i].ar_up.on_button_click = move_up
If the issue is that your function needs a parameter, wrap it in a tiny forwarding function:

Code: Select all

                                dialog.autorecall_tv[i].ar_up.on_button_click = function() move_up(i) end
Of course, the second way in your latest post (defining the function inline) also works, because in that case the function itself captures i.
Author of The Black Cross of Aleron campaign and Default++ era.
Former maintainer of Steelhive.
white_haired_uncle
Posts: 1203
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

Re: [GUI] Passing parameters to callbacks

Post by white_haired_uncle »

I like your forwarding function idea. It allows me to abstract the actual implementation of the function from the callback assignment, which I find to be MUCH easier to follow. Thank you.
Speak softly, and carry Doombringer.
Post Reply