tldr: on_gui_click event handlers are basically lookup functions written by different people with different degree of quality coding and which sole purpose is to find which ui button from an unknown multitude of those has been pressed. Instead of that: (see the text at the bottom of post)
Initial wallotext Im little ashamed of
Currently, on_gui_click has only field player_index and element, and element contains the following items in it:
[quote]caption, children_names, direction, gui, isluaobject, name, parent, player_index, state, style, text, valid, value[/quote].
NONE of those are unique. (Well, references to objects may be, but to use those to distinguish elements, you'd need to keep table of gui objects for different players and update it on each creation\destruction)
I've seen people simply comparing the caption of the element passed to event handler with the constant (and have seen their handlers react to my buttons from my gui from my mod and vice versa).
Yes, if you name your gui elements with complicated names like 'modname-guiname-childname-childname', you'll have a decent chance of avoiding name clashes. But this is extremely unwieldy and not intuitive.
Semi-resilient to the problem is the comparison with the name of top parent of the gui. People tend to use derivatives of their unique mod names for those. However, a certain effort is needed to obtain those.
What I suggest, either:
1) Add ancestor field to a gui element, which points to the last its parent which is not (left/top/center). Provide generate_gui_name() function for unique naming of such ancestors (like with custom events. Or maybe better: add a reference_point field, which points to nearest parent node with guaranteed unique name obtained. (i.e. if a modder adds a node with a name generated by the function, the children of such node would have a field pointing to it).
or
2) Just force all the element names be generated by program. (I've only been blabbering in previous paragraph because in my imagination that would flood the code with a horde of intermittent variables storing the names.
or
3) Just allow handler for a given element be defined in the definition of the element itself.
Re: Easy gui_element identification
Posted: Sun Aug 16, 2015 9:46 pm
by Rseding91
You can compare elements directly:
if (event.element == game.get_player(event.player_index).gui.top.my_gui)
Also, element.name is unique in the element collection it resides (unique in the element.parent.children_names set).
Also also: element.parent points to the element that owns the element which can easily be used to crawl up the parent chain to the root gui element.
Re: Easy gui_element identification
Posted: Mon Aug 17, 2015 5:11 pm
by Adil
Rseding91 wrote:You can compare elements directly:
if (event.element == game.get_player(event.player_index).gui.top.my_gui)
That would actually require a number of nested ifs:
if ( game.get_player(event.player_index).gui.top.my_gui~=nil) then
if event.element == game.get_player(event.player_index).gui.top.my_gui.button1 then
elseif game.get_player(event.player_index).gui.top.my_gui.subgroup1~=nil then
if event.element == game.get_player(event.player_index).gui.top.my_gui.button2 then
end
end
end
Certainly doable, but not very intuitive or motivating to do it this way. The suggestion is about making doing the right thing easier.
Rseding91 wrote:Also, element.name is unique in the element collection it resides
Yes, but you don't know in which collection it resides. Only the full set of (name, parent_name, parent_parent_name,...,your_gui_name (and maybe top/left/center). And as for
Rseding91 wrote:Also also: element.parent points to the element that owns the element which can easily be used to crawl up the parent chain
you don't know the size of the set or the length of the chain for the element stored in event.element. Yes, a function can be written to determine the structure of the chain and the top parent, but once again, that's something that would get reimplemented by each modder, and would be implemented with various degree of correctness.
Re: Easy gui_element identification
Posted: Mon Aug 17, 2015 5:23 pm
by GopherAtl
Adil wrote:
Rseding91 wrote:You can compare elements directly:
if (event.element == game.get_player(event.player_index).gui.top.my_gui)
That would actually require a number of nested ifs:
if ( game.get_player(event.player_index).gui.top.my_gui~=nil) then
if event.element == game.get_player(event.player_index).gui.top.my_gui.button1 then
elseif game.get_player(event.player_index).gui.top.my_gui.subgroup1~=nil then
if event.element == game.get_player(event.player_index).gui.top.my_gui.button2 then
end
end
end
Certainly doable, but not very intuitive or motivating to do it this way. The suggestion is about making doing the right thing easier.
Rseding91 wrote:Also, element.name is unique in the element collection it resides
Yes, but you don't know in which collection it resides. Only the full set of (name, parent_name, parent_parent_name,...,your_gui_name (and maybe top/left/center). And as for
Rseding91 wrote:Also also: element.parent points to the element that owns the element which can easily be used to crawl up the parent chain
you don't know the size of the set or the length of the chain for the element stored in event.element. Yes, a function can be written to determine the structure of the chain and the top parent, but once again, that's something that would get reimplemented by each modder, and would be implemented with various degree of correctness.
local myHandlers={}
local function myCreateElement(element_def,player_index,side,handler)
game.players[player_index].gui[side].add(element_def)
myHandlers[element_def.name]=handler
end
local myGuiHandler(event)
local handler=myHandlers[event.element]
if handler then
handler(event)
end
end
function onClickHi(event)
game.players[event.player_index).print("Hello to you, too.")
end
game.on_event(on_player_created, function(event)
myAddElement({type="button" caption="Hi!",name="hi"},event.player_index,"left",handler)
end)
(untested code, but should be basically sound)
You can make it as organized as you want. The api is low-level, and there's actually nothing wrong with if...elseif blocks. You're welcome to not like them, and lua actually makes it pretty esay to avoid them if you want. And as for "different people with different degree of quality coding," well, honestly, if doing some "if...elseif" blocks is taxing their coding skills, well, they're kind of screwed.
Re: Easy gui_element identification
Posted: Mon Aug 17, 2015 9:58 pm
by Rseding91
Gui elements are persistent (saved and restored on load) the current Factorio Lua event system is not. Every time the game is exited and loaded every mod re-registers the event handlers it wants to use with the game.
If Gui elements did the same there net effect wouldn't be any different: you'd still need to know which elements are yours so you could register the handlers. I've seen very complex mods and never seen one have issues with naming the elements or handling events for the elements.