z_mirror/flib
git clone https://git.raiguard.me/z_mirror/flib
a9f2be7
trunk
1--- Utilities for building GUIs and handling GUI events. 2--- ```lua 3--- local flib_gui = require("__flib__.gui") 4--- ``` 5--- @class flib_gui : event_handler 6local flib_gui ={} 7 8local handler_tag_key ="__" .. script . mod_name .. "_handler" 9 10--- @type table<flib.GuiElemHandler, string> 11local handlers ={} 12--- @type table<string, flib.GuiElemHandler> 13local handlers_lookup ={} 14 15--- Add a new child or children to the given GUI element. 16--- @param parent LuaGuiElement The parent GUI element. 17--- @param def flib.GuiElemDef|flib.GuiElemDef[] The element definition, or an array of element definitions. 18--- @param elems table<string, LuaGuiElement>? Optional initial `elems` table. 19--- @return table<string, LuaGuiElement> elems Elements with names will be collected into this table. 20--- @return LuaGuiElement first The element that was created first; the "top level" element. 21function flib_gui . add ( parent , def , elems ) 22if not parent or not parent . valid then 23error ( "Parent element is missing or invalid" ) 24end 25if not elems then 26elems ={} 27end 28-- If a single def was passed, wrap it in an array 29if def . type or ( def . tab and def . content ) then 30def ={ def } 31end 32local first 33for i =1 , # def do 34local def =def [ i ] 35if def . type then 36-- Remove custom attributes from the def so the game doesn't serialize them 37local children =def . children 38local elem_mods =def . elem_mods 39local handler =def . handler 40local style_mods =def . style_mods 41local drag_target =def . drag_target 42-- If children were defined in the array portion, remove and collect them 43local has_array_children =false 44if def [ 1 ] then 45if children then 46error ( "Cannot define children in array portion and subtable simultaneously" ) 47end 48has_array_children =true 49children ={} 50for i =1 , # def do 51children [ i ] =def [ i ] 52def [ i ] =nil 53end 54end 55def . children =nil 56def . elem_mods =nil 57def . handler =nil 58def . style_mods =nil 59def . drag_target =nil 60 61local elem =parent . add ( def ) 62 63if not first then 64first =elem 65end 66if def . name then 67elems [ def . name ] =elem 68end 69if style_mods then 70for key , value in pairs ( style_mods ) do 71elem . style [ key ] =value 72end 73end 74if elem_mods then 75for key , value in pairs ( elem_mods ) do 76elem [ key ] =value 77end 78end 79if drag_target then 80local target =elems [ drag_target ] 81if not target then 82error ( "Drag target '" .. drag_target .. "' not found." ) 83end 84elem . drag_target =target 85end 86if handler then 87local out 88if type ( handler ) == "table" then 89out ={} 90for name , handler in pairs ( handler ) do 91out [ tostring ( name )] =handlers [ handler ] 92end 93else 94out =handlers [ handler ] 95end 96local tags =elem . tags 97tags [ handler_tag_key ] =out 98elem . tags =tags 99end 100if children then 101flib_gui . add ( elem , children , elems ) 102end 103 104-- Re-add custom attributes 105if children and has_array_children then 106for i =1 , # children do 107def [ i ] =children [ i ] 108end 109else 110def . children =children 111end 112def . elem_mods =elem_mods 113def . handler =handler 114def . style_mods =style_mods 115def . drag_target =drag_target 116elseif def . tab and def . content then 117local _ , tab =flib_gui . add ( parent , def . tab , elems ) 118local _ , content =flib_gui . add ( parent , def . content , elems ) 119parent . add_tab ( tab , content ) 120end 121end 122return elems , first 123end 124 125--- Add the given handler functions to the registry for use with `flib_gui.add`. Each handler must have a unique name. If a 126--- `wrapper` function is provided, it will be called instead, and will receive the event data and handler. The wrapper 127--- can be used to execute logic or gather data common to all handler functions for this GUI. 128--- @param new_handlers table<string, fun(e: flib.GuiEventData)> 129--- @param wrapper fun(e: flib.GuiEventData, handler: function)? 130--- @param prefix string? 131function flib_gui . add_handlers ( new_handlers , wrapper , prefix ) 132for name , handler in pairs ( new_handlers ) do 133if prefix then 134name =prefix .. "/" .. name 135end 136if type ( handler ) == "function" then 137if handlers_lookup [ name ] then 138error ( "Attempted to register two GUI event handlers with the same name: " .. name ) 139end 140handlers [ handler ] =name 141if wrapper then 142handlers_lookup [ name ] =function ( e ) 143wrapper ( e , handler ) 144end 145else 146handlers_lookup [ name ] =handler 147end 148end 149end 150end 151 152--- Dispatch the handler associated with this event and GUI element. The handler must have been added using 153--- `flib_gui.add_handlers`. 154--- @param e flib.GuiEventData 155--- @return boolean handled True if an event handler was called. 156function flib_gui . dispatch ( e ) 157local elem =e . element 158if not elem then 159return false 160end 161local tags =elem . tags --[[@as Tags]] 162local handler_def =tags [ handler_tag_key ] 163if not handler_def then 164return false 165end 166local handler_type =type ( handler_def ) 167if handler_type == "table" then 168handler_def =handler_def [ tostring ( e . name )] 169end 170if handler_def then 171local handler =handlers_lookup [ handler_def ] 172if handler then 173handler ( e ) 174return true 175end 176end 177return false 178end 179 180--- For use with `__core__/lualib/event_handler`. Pass `flib_gui` into `handler.add_lib` to handle 181--- all GUI events automatically. 182flib_gui . events ={} 183for name , id in pairs ( defines . events ) do 184if string . find ( name , "on_gui_" ) then 185flib_gui . events [ id ] =flib_gui . dispatch 186end 187end 188 189--- Handle all GUI events with `flib_gui.dispatch`. Will not overwrite any existing event handlers. 190function flib_gui . handle_events () 191for id in pairs ( flib_gui . events ) do 192if not script . get_event_handler ( id ) then 193script . on_event ( id , flib_gui . dispatch ) 194end 195end 196end 197 198--- Format the given handlers for use in a GUI element's tags. An alternative to using `flib_gui.add` if event handling 199--- is the only desired feature. 200--- 201--- ### Example 202--- 203--- ```lua 204--- --- @param e EventData.on_gui_click 205--- local function on_button_clicked(e) 206--- game.print("You clicked it!") 207--- end 208--- 209--- player.gui.screen.add({ 210--- type = "button", 211--- caption = "Click me!", 212--- tags = flib_gui.format_handlers({ [defines.events.on_gui_click] = on_button_clicked }), 213--- }) 214--- 215--- flib_gui.handle_events({ on_button_clicked = on_button_clicked }) 216--- ``` 217--- @param input flib.GuiElemHandler|table<defines.events, flib.GuiElemHandler?> 218--- @param existing Tags? 219--- @return Tags 220function flib_gui . format_handlers ( input , existing ) 221local out 222if type ( input ) == "table" then 223out ={} 224for name , handler in pairs ( input ) do 225out [ tostring ( name )] =handlers [ handler ] 226end 227else 228out =handlers [ input ] 229end 230if existing then 231existing [ handler_tag_key ] =out 232return existing 233end 234return { [ handler_tag_key ] =out } 235end 236 237--- A GUI element definition. This extends `LuaGuiElement.add_param` with several new attributes. 238--- Children may be defined in the array portion as an alternative to the `children` subtable. 239--- @class flib.GuiElemDef: LuaGuiElement.add_param.button|LuaGuiElement.add_param.camera|LuaGuiElement.add_param.checkbox|LuaGuiElement.add_param.choose_elem_button|LuaGuiElement.add_param.drop_down|LuaGuiElement.add_param.flow|LuaGuiElement.add_param.frame|LuaGuiElement.add_param.line|LuaGuiElement.add_param.list_box|LuaGuiElement.add_param.minimap|LuaGuiElement.add_param.progressbar|LuaGuiElement.add_param.radiobutton|LuaGuiElement.add_param.scroll_pane|LuaGuiElement.add_param.slider|LuaGuiElement.add_param.sprite|LuaGuiElement.add_param.sprite_button|LuaGuiElement.add_param.switch|LuaGuiElement.add_param.tab|LuaGuiElement.add_param.table|LuaGuiElement.add_param.text_box|LuaGuiElement.add_param.textfield 240--- @field style_mods LuaStyle? Modifications to make to the element's style. 241--- @field elem_mods LuaGuiElement? Modifications to make to the element itself. 242--- @field drag_target string? Set the element's drag target to the element whose name matches this string. The drag target must be present in the `elems` table. 243--- @field handler (flib.GuiElemHandler|table<defines.events, flib.GuiElemHandler>)? Handler(s) to assign to this element. If assigned to a function, that function will be called for any GUI event on this element. 244--- @field children flib.GuiElemDef[]? Children to add to this element. 245--- @field tab flib.GuiElemDef? To add a tab, specify `tab` and `content` and leave all other fields unset. 246--- @field content flib.GuiElemDef? To add a tab, specify `tab` and `content` and leave all other fields unset. 247 248--- A handler function to invoke when receiving GUI events for this element. 249--- @alias flib.GuiElemHandler fun(e: flib.GuiEventData) 250 251--- Aggregate type of all possible GUI events. 252--- @alias flib.GuiEventData EventData.on_gui_checked_state_changed|EventData.on_gui_click|EventData.on_gui_closed|EventData.on_gui_confirmed|EventData.on_gui_elem_changed|EventData.on_gui_location_changed|EventData.on_gui_opened|EventData.on_gui_selected_tab_changed|EventData.on_gui_selection_state_changed|EventData.on_gui_switch_state_changed|EventData.on_gui_text_changed|EventData.on_gui_value_changed 253 254return flib_gui