Core Module - Gui
-- Making the base button concept
local button =
Gui.new_concept() -- Make a new empty concept
:save_as('button') -- Save it as Gui.concepts.button so it can be used in other files
:new_event('on_click',defines.events.on_gui_click) -- Add an on click event for this concept
:new_property('tooltip') -- Add a property with the default setter method called tooltip
:new_property('caption',function(properties,value) -- Add a property with a custom setter method called caption
properties.caption = value
properties.sprite = nil
properties.type = 'button'
end)
:new_property('sprite',function(properties,value) -- Add a property with a custom setter method called sprite
properties.image = value
properties.caption = nil
properties.type = 'sprite-button'
end)
:define_draw(function(properties,parent,element) -- Add the draw function to create the element from the concept
-- Properties will include all the information that you need to draw the element
-- Parent is the parent element for the element, this may have been altered by previous draw functions
-- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function
if properties.type == 'button' then
element = parent.add{
type = properties.type,
name = properties.name,
caption = properties.caption,
tooltip = properties.tooltip
}
else
element = parent.add{
type = properties.type,
name = properties.name,
sprite = properties.sprite,
tooltip = properties.tooltip
}
end
-- If you return element or parent then their values will be updated for the next draw function in the chain
-- It is best practice to always return the values if you have made any changes to them
return element, parent
end)
-- Making a new button which has a custom style
local custom_button =
Gui.new_concept('button') -- We can use button here since we used save as on the concept
-- button:clone() -- If we had not used save as then this is how we would use it as a base
:set_caption('Custom Button') -- Set the caption of the concept, this is possible as we added caption as a property
:set_tooltip('Only admins can press this button') -- Set the tooltip of the concept, this is possible as we added tooltip as a property
:on_click(function(event) -- Register a handler to the click event we added with new event
if not event.player.admin then
event.player.print('You must be admin to use this button')
end
end)
:new_event('on_admin_clicked',defines.events.on_gui_click,function(event) -- Add a click event which has a filter function
return event.player.admin -- Check if the player is admin
end)
:on_admin_clicked(function(event) -- Register a handler to the admin click event we have just created
-- The admin click event is only an example, because of how sinmple the filter is we could have just used an if else statement
game.print(event.player.name..' pressed my admin button')
end)
-- Drawing a concept
custom_button:draw(game.player.gui.left)
| button | Clickable elements that fire on_gui_click when clicked. |
| checkbox | Clickable elements with a cross in the middle that can be turned off or on. |
| dropdown | A drop down list of other elements. |
| elem_button | A button that lets the player pick one of an: item, entity, tile, or signal similar to the filter-select window. |
| empty | A empty widget that just exists. |
| flow | Invisible containers that lay out children either horizontally or vertically. |
| frame | Grey semi-transparent boxes that contain other elements. |
| label | A piece of text. |
| line | A vertical or horizontal line. |
| progress_bar | Indicate progress by displaying a partially filled bar. |
| scroll | Similar to a flow but includes the ability to show and use scroll bars. |
| slider | A number picker. |
| table | An invisible container that lays out children in a specific number of columns. |
| text_box | A multi-line text box that supports selection and copy-paste. |
| text_field | Boxes of text the user can type in. |
| set_dropdown_value(element, value) | Selects the index of a dropdown with this value |
| get_dropdown_value(element) | Gets the selected item value of a dropdown |
| add_dropdown_items(element[, start_index], new_items) | Adds the given items into the list of items for this dropdown |
| progress_bar:increment(element[, amount=1]) | Will increase the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances |
| progress_bar:decrement(element[, amount=1]) | Will decrease the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances |
| progress_bar:reset(element) | Resets the progress back to 0% for this element, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances |
| increment_progress_bar(element[, amount=0.01]) | Increment any progress bar by the given percentage |
| decrement_progress_bar(element[, amount=0.01]) | Decrement any progress bar by the given percentage |
| require_concept(concept_name) | Loads a concept from the concepts file |
| require_style(style_name) | Loads a set of concepts from the styles file |
| get_concept(name) | Gets a gui concept from name, id, or its self |
| Prototype:save_as(save_name) | Used to save the concept to the main gui module to allow access from other files |
| new_concept([base_concept]) | Returns a new gui concept, option to provide a base concept to copy properties and draw functions from |
| draw_concept(concept, parent) | Used to draw a concept to a parent element |
| get_player_from_element(element) | Gets the player who owns this element |
| valid(element) | Simple check for if an element is valid |
| destroy(element) | Destroies and element if it is valid |
| find(element, ...) | Finds and returns a gui element if it is valid from a long chain of element names or concepts |
| exists | Checks if a gui element exists or not, returns it if found else the path where it failed |
| toggle_enabled(element) | Toggles the enabled state of an element |
| toggle_visible(element) | Toggles the visible state of an element |
| set_padding(element[, up=0][, down=0][, left=0][, right=0]) | Sets the padding for a gui element |
| categorize_by_player(element) | A categorize function to be used with add_store, each player has their own category |
| categorize_by_force(element) | A categorize function to be used with add_store, each force has its own category |
| categorize_by_surface(element) | A categorize function to be used with add_store, each surface has its own category |
| Prototype:clone(concept_name) | Used to copy all the settings from one concept to another and removing links to the orginal |
| Prototype:define_clone(clone_callback) | Use to add your own callbacks to the clone function, for example adding to a local table |
| Prototype:save_as(save_name) | Used to save the concept to the main gui module to allow access from other files |
| Prototype:debug(name) | Sets a debug name that can be used with error handlers |
| Prototype:new_event(event_name[, factorio_event][, event_condition]) | Adds a new event trigger to the concept which can be linked to a factorio event |
| Prototype:on_custom_event(handler) | Adds a custom event handler, replace with the name of the event |
| Prototype:raise_event(event_name[, event={}][, from_factorio=false]) | Raises a custom event, folowing keys included automaticlly: concept, event name, game tick, player from player_index, element if valid |
| Prototype:new_property(property_name[, setter_callback][, default]) | Adds a new property to the concept, such as caption, tooltip, or some custom property you want to control |
| Prototype:set_custom_property(value) | Sets a new value for a property, triggers setter method if provided, replace with property name |
| Prototype:define_draw(draw_callback) | Used to define how the concept is turned into an ingame element or "instance" as we may refer to them |
| Prototype:draw(parent_element[, override_name]) | Calls all the draw functions in order to create this concept in game; will also store and sync the instance if stores are used |
| Prototype:define_instance_store([category_callback]) | Adds an instance store to the concept; when a new instance is made it is stored so you can access it later |
| Prototype.get_instances([category]) | Gets all insatnces in a category, category may be nil to return all |
| Prototype.add_instance(element[, category]) | Adds an instance to this concept, used automatically during concept:draw |
| Prototype.update_instances([category], update_callback) | Applies an update function to all instances, simialr use to what table.forEach would be |
| Prototype:define_data_store([category_callback]) | Adds a data store to this concept which allows you to store synced/percistent data between instances |
| Prototype.get_data([category]) | Gets the data that is stored for this category |
| Prototype.set_data([category], value) | Sets the data that is stored for this category |
| Prototype.clear_data([category]) | Clears the data that is stored for this category |
| Prototype.update_data([category], update_callback) | Updates the data that is stored for this category |
| Prototype:define_combined_store([category_callback], sync_callback) | Used to add a both instance and data store which are linked together, new instances are synced to the current value, changing the stored value will change all instances |
| Prototype.sync_instance(element) | Will sync an instance to match the stored value based on the given sync callback |
| run_tests(player[, category]) | Runs a set of gui tests to ensure that the system is working |
Clickable elements that fire on_gui_click when clicked.
Properties / Events:-- Making a basic button
local basic_button =
Gui.new_concept('button')
:set_caption('Basic Button')
:set_tooltip('Basic button')
:on_click(function(event)
event.player.print('You pressed basic button!')
end)
-- Making a sprite button
local sprite_button =
Gui.new_concept('button')
:set_sprite('utility/warning_icon')
:set_tooltip('Sprite button')
:on_click(function(event)
event.player.print('You pressed sprite button!')
end)
Clickable elements with a cross in the middle that can be turned off or on.
Properties / Events:-- Making a basic checkbox
local basic_checkbox =
Gui.new_concept('checkbox')
:set_caption('Basic Checkbox')
:set_tooltip('Basic checkbox')
:on_state_changed(function(event)
event.player.print('Basic checkbox is now: '..tostring(event.element.state))
end)
A drop down list of other elements.
Properties / Events:-- Making a basic dropdown
local static_dropdown =
Gui.new_concept('dropdown')
:set_static_items{'Option 1','Option 2','Option 3'}
:on_selection_changed(function(event)
local value = Gui.get_dropdown_value(event.element)
event.player.print('Static dropdown is now: '..value)
end)
-- Making a dropdown with dynamic items, example is name of online players
local dynamic_dropdown =
Gui.new_concept('dropdown')
:set_dynamic_items(function(element)
local items = {}
for _,player in pairs(game.connected_players) do
items[#items+1] = player.name
end
return items
end)
:on_selection_changed(function(event)
local value = Gui.get_dropdown_value(event.element)
event.player.print('Dynamic dropdown is now: '..value)
end)
A button that lets the player pick one of an: item, entity, tile, or signal similar to the filter-select window.
Properties / Events:-- Making a basic elem button
local basic_elem_button =
Gui.new_concept('elem_button')
:on_selection_changed(function(event)
event.player.print('Basic elem button is now: '..event.element.elem_value)
end)
A empty widget that just exists.
The root GUI element screen is an empty-widget.
Properties / Events:-- Making a draggable space styled widget
local draggable_space =
Gui.new_concept('empty')
:set_style('draggable_space')
Invisible containers that lay out children either horizontally or vertically.
The root GUI elements (top, left and center; see LuaGui) are flows.
Properties / Events:-- Making a basic flow, contains a label with hello world
local basic_flow =
Gui.new_concept('flow')
:define_draw(function(properties,parent,element)
element.add{
type = 'label',
caption = 'Hello, World!'
}
end)
Grey semi-transparent boxes that contain other elements.
They have a caption, and, just like flows, they lay out children either horizontally or vertically.
Properties / Events:-- Making a basic frame, contains a label with hello world
local basic_frame =
Gui.new_concept('frame')
:set_title('Basic Frame')
:define_draw(function(properties,parent,element)
element.add{
type = 'label',
caption = 'Hello, World!'
}
end)
A piece of text.
Properties / Events:-- Making a basic label
local basic_label =
Gui.new_concept('label')
:set_caption('Hello, World!')
A vertical or horizontal line.
Properties / Events:-- Making a basic frame, contains a label with hello world
local basic_line =
Gui.new_concept('line')
Indicate progress by displaying a partially filled bar.
Properties / Events:-- Making a basic progress bar, will increase when pressed then will reset when full
local basic_progress_bar =
Gui.new_concept('progress_bar')
:set_tooltip('Basic progress bar')
:set_maximum(5)
:new_event('on_click',defines.events.on_gui_click)
:on_click(function(event)
event.concept:increment(event.element)
end)
:set_delay_completion(true)
:on_completion(function(event)
event.concept:reset(event.element)
end)
Similar to a flow but includes the ability to show and use scroll bars.
Properties / Events:-- Making a basic flow, contains a label with hello world
local basic_scroll =
Gui.new_concept('scroll')
:define_draw(function(properties,parent,element)
element.style.hieght = 50
for i = 1,10 do
element.add{
type = 'label',
caption = i
}
end
end)
A number picker.
Properties / Events:-- Making a basic slider
local basic_slider =
Gui.new_concept('slider')
:set_range(1,10)
:on_value_changed(function(event)
event.player.print('Basic slider is now: '..event.element.slider_value)
end)
-- Making a discrete_slider
local discrete_slider =
Gui.new_concept('slider')
:set_range(1,10)
:set_value_step(1)
:set_discrete_slider(true)
:on_value_changed(function(event)
event.player.print('Interval slider is now: '..event.element.slider_value)
end)
An invisible container that lays out children in a specific number of columns.
Column width is given by the largest element contained in that row.
Properties / Events:-- Making a basic table, contains 25 labels
local basic_table =
Gui.new_concept('table')
:set_column_count(5)
:define_draw(function(properties,parent,element)
for i = 1,25 do
element.add{
type = 'lable',
caption = i
}
end
end)
A multi-line text box that supports selection and copy-paste.
Properties / Events:-- Making a text box
local basic_text_box =
Gui.new_concept('text_box')
:set_default('I am the text that will show in the text box')
-- Making a text box which can be edited
local editible_text_box =
Gui.new_concept('text_box')
:set_is_read_only(false)
:set_default('I am the text that will show in the text box')
:on_confirmation(function(event)
event.player.print('Editible text box is now: '..event.element.text)
end)
Boxes of text the user can type in.
Properties / Events:-- Making a text field
local basic_text_field =
Gui.new_concept('text_field')
:on_confirmation(function(event)
event.player.print('Basic text field is now: '..event.element.text)
end)
-- Making a text field which will clear on right click and un forcus on confirmation
local better_text_field =
Gui.new_concept('text_field')
:set_clear_on_rmb(true)
:set_lose_forcus(true)
:on_confirmation(function(event)
event.player.print('Better text field is now: '..event.element.text)
end)
-- Making a decimal input
local decimal_text_field =
Gui.new_concept('text_field')
:set_is_decimal(true)
:on_confirmation(function(event)
event.player.print('Decimal text field is now: '..event.element.text)
end)
Selects the index of a dropdown with this value
Parameters:-- Selecting the item with the value 'foo'
Gui.set_dropdown_value(element,'foo')
Gets the selected item value of a dropdown
Parameters:-- Getting the selected value
local selected_value = Gui.get_dropdown_value(element)
Adds the given items into the list of items for this dropdown
Parameters:-- Add the items 'foo' and 'bar' to the end
Gui.add_dropdown_items(element,{'foo','bar'})
-- Add the items 'foo' and 'bar' to the start
Gui.add_dropdown_items(element,1,{'foo','bar'})
Will increase the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances
Parameters:-- Incrementing progress bar with no instance store
local new_value = progress_bar:increment(element)
-- Incrementing progress bar with an instance store
progress_bar:increment(category)
Will decrease the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances
Parameters:-- Decrementing progress bar with no instance store
local new_value = progress_bar:decrement(element)
-- Decrementing progress bar with an instance store
progress_bar:decrement(category)
Resets the progress back to 0% for this element, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances
Parameters:-- Reseting a progress bar with no instance store
local new_value = progress_bar:reset(element)
-- Reseting a progress bar with an instance store
progress_bar:reset(category)
Increment any progress bar by the given percentage
Parameters:-- Increment any progress bar by 10%
Gui.increment_progress_bar(element,0.1)
Decrement any progress bar by the given percentage
Parameters:-- Decrement any progress bar by 10%
Gui.decrement_progress_bar(element,0.1)
Loads a concept from the concepts file
Parameters:-- Load a base concept
Gui.require_concept('frame') --- @dep Gui.concept.frame
Loads a set of concepts from the styles file
Parameters:-- Load a base style
Gui.require_concept('expgaming') --- @dep Gui.style.frame
Gets a gui concept from name, id, or its self
Parameters: Usage:-- Getting a gui concept
local button = Gui.get_concept('Button')
Used to save the concept to the main gui module to allow access from other files
Parameters:-- Save a concept to allow access in another file
button:save_as('button')
-- Access concept after being saved
Gui.concepts.button
Gui.get_concept('button')
Returns a new gui concept, option to provide a base concept to copy properties and draw functions from
Parameters:-- Making a new button, see module usage
local button = Gui.new_concept('Button')
Used to draw a concept to a parent element
Parameters:-- Drawing a new element
Gui.draw_concept('Button',element)
Gets the player who owns this element
Parameters:-- Getting the player of an element
local player = Gui.get_player_from_element(element)
Simple check for if an element is valid
Parameters:-- Return if not valid
if not Gui.valid(element) then return end
Destroies and element if it is valid
Parameters:-- Destoring an element
Gui.destroy(element)
Finds and returns a gui element if it is valid from a long chain of element names or concepts
Parameters:-- Getting the center gui
local exists, center = Gui.find(player,'gui','center')
Checks if a gui element exists or not, returns it if found else the path where it failed
-- Getting the center gui
local exists, center = Gui.exists(player,'gui','center')
Toggles the enabled state of an element
Parameters:-- Toggle the enabled state of an element
Gui.toggle_enabled(element)
Toggles the visible state of an element
Parameters:-- Toggle the visible state of an element
Gui.toggle_visible(element)
Sets the padding for a gui element
Parameters:-- Remove all padding of an element
Gui.set_padding(element)
-- Remove side padding but keep vertical padding
Gui.set_padding(element,true,true)
-- Remove all padding but set right to 2
Gui.set_padding(element,false,false,false,2)
A categorize function to be used with add_store, each player has their own category
Parameters:-- Storing data on a per player basis, can be used with instances
Gui.get_concept('CustomButton')
:define_data_store(Gui.categorize_by_player)
A categorize function to be used with add_store, each force has its own category
Parameters:-- Storing data on a per force basis, can be used with instances
Gui.get_concept('CustomButton')
:define_data_store(Gui.categorize_by_force)
A categorize function to be used with add_store, each surface has its own category
Parameters:-- Storing data on a per surface basis, can be used with instances
Gui.get_concept('CustomButton')
:define_data_store(Gui.categorize_by_surface)
Used to copy all the settings from one concept to another and removing links to the orginal
Parameters:-- Clones the base Button concept to make a alternative button
local custom_button =
Gui.get_concept(Gui.concepts.button):clone()
Use to add your own callbacks to the clone function, for example adding to a local table
Parameters:-- Adding concept to a local table
local buttons = {}
local button =
Gui.get_concept('Button')
:define_clone(function(concept)
buttons[concept.name] = concept
end)
Used to save the concept to the main gui module to allow access from other files
Parameters:-- Save a concept to allow access in another file
button:save_as('button')
-- Access concept after being saved
Gui.concepts.button
Gui.get_concept('button')
Sets a debug name that can be used with error handlers
Parameters:-- Set the debug name
unsaved_concept:debug('Example button')
Adds a new event trigger to the concept which can be linked to a factorio event
Parameters:-- Adds an on_admin_clicked event to fire when ever an admin clicks the button
local custom_button =
Gui.get_concept('Button'):clone('CustomButton')
:new_event('on_admin_clicked',defines.events.on_gui_click,function(event)
return event.player.admin -- only raise custom event when an admin clicks the button
end)
Adds a custom event handler, replace with the name of the event
Parameters:-- When an admin clicks the button a message is printed
local custom_button =
Gui.get_concept('CustomButton')
:on_admin_clicked(function(event)
game.print(event.player.name..' pressed my admin button')
end)
Raises a custom event, folowing keys included automaticlly: concept, event name, game tick, player from player_index, element if valid
Parameters:-- Raising the custom event on_admin_clicked
local custom_button =
Gui.get_concept('CustomButton')
-- Note that this is an example and would not work due it expecting a valid element for event.element
-- this will however work fine if you can provide all expected keys, or its not linked to any factorio event
custom_button:raise_event('on_admin_clicked',{
player_index = game.player.index
})
Adds a new property to the concept, such as caption, tooltip, or some custom property you want to control
Parameters:-- Adding caption, sprite, and tooltip to the base button concept
local button =
Gui.get_concept('Button')
:new_property('tooltip')
:new_property('caption',nil,function(properties,value)
properties.caption = value
properties.sprite = nil
properties.type = 'button'
end)
:new_property('sprite',nil,function(properties,value)
properties.image = value
properties.caption = nil
properties.type = 'sprite-button'
end)
Sets a new value for a property, triggers setter method if provided, replace with property name
Parameters:-- Setting the caption on the base button concept after a cloning
local custom_button =
Gui.get_concept('Button')
:set_caption('Default Button')
-- In our examples CustomButton is cloned from Button, this means the caption property already exists
-- note that what ever values that properties have at the time of cloning are also copied
local custom_button =
Gui.get_concept('CustomButton')
:set_caption('Custom Button')
Used to define how the concept is turned into an ingame element or "instance" as we may refer to them
Parameters:-- Adding the draw define for the base button concept, we then return the element
local button =
Gui.get_concept('Button')
:define_draw(function(properties,parent,element)
-- Properties will include all the information that you need to draw the element
-- Parent is the parent element for the element, this may have been altered by previous draw functions
-- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function
-- You can also pass any other arguments that you want to this function from the draw call
if properties.type == 'button' then
element = parent.add{
type = properties.type,
name = properties.name,
caption = properties.caption,
tooltip = properties.tooltip
}
else
element = parent.add{
type = properties.type,
name = properties.name,
sprite = properties.sprite,
tooltip = properties.tooltip
}
end
-- If you return element or parent then their values will be updated for the next draw function in the chain
-- It is best practice to always return the values if you have made any changes to them
return element, parent
end)
Calls all the draw functions in order to create this concept in game; will also store and sync the instance if stores are used
Parameters:-- Drawing the custom button concept
local custom_button =
Gui.get_concept('CustomButton')
-- Note that the draw function from button was cloned, so unless we want to alter the base button we dont need a new draw define
custom_button:draw(game.player.gui.left)
Adds an instance store to the concept; when a new instance is made it is stored so you can access it later
Parameters:-- Allowing storing instances of the custom button; stored by the players index
-- Note even thou this is a copy of Button; if Button had an instance store it would not be cloned over
local custom_button =
Gui.get_concept('CustomButton')
:define_instance_store(function(element)
return element.player_index -- The instances are stored based on player id
end)
Gets all insatnces in a category, category may be nil to return all
Parameters:-- Getting all the instances of the player with index 1
local custom_button =
Gui.get_concept('CustomButton')
custom_button.get_instances(1) -- player index 1
Adds an instance to this concept, used automatically during concept:draw
Parameters:-- Adding an element as a instance for this concept, mostly for internal use
local custom_button =
Gui.get_concept('CustomButton')
custom_button.add_instance(element) -- normally not needed due to use in concept:draw
Applies an update function to all instances, simialr use to what table.forEach would be
Parameters:-- Changing the font color of all instances for player 1
local custom_button =
Gui.get_concept('CustomButton')
custom_button.update_instances(1,function(element)
element.style.font_color = {r=1,g=0,b=0}
end)
Adds a data store to this concept which allows you to store synced/percistent data between instances
Parameters:-- Adding a way to store data for this concept; each player has their own store
-- Note even thou this is a copy of Button; if Button had an data store it would not be cloned over
local custom_button =
Gui.get_concept('CustomButton')
:define_data_store(function(element)
return element.player_index -- The data is stored based on player id
end)
Gets the data that is stored for this category
Parameters:-- Getting the stored data for player 1
local custom_button =
Gui.get_concept('CustomButton')
custom_button.get_data(1) -- player index 1
Sets the data that is stored for this category
Parameters:-- Setting the data for player 1 to a table with two keys
local custom_button =
Gui.get_concept('CustomButton')
-- A table is used to show correct way to use a table with self.update_data
-- but a table is not required and can be any data, however upvalues may cause desyncs
custom_button.set_data(1,{
clicks = 0,
required_clicks = 100
}) -- player index 1
Clears the data that is stored for this category
Parameters:-- Clearing the data for player 1
local custom_button =
Gui.get_concept('CustomButton')
custom_button.clear_data(1) -- player index 1
Updates the data that is stored for this category
Parameters:-- Updating the clicks key in the concept data for player 1
local custom_button =
Gui.get_concept('CustomButton')
custom_button.update_data(1,function(tbl)
tbl.clicks = tbl.clicks + 1 -- here we are incrementing the clicks by 1
end) -- player index 1
-- Updating a value when a table is not used, alterative to get set
-- so for this example assume that we did custom_button.set_data(1,0)
custom_button.update_data(1,function(value)
return value + 1 -- here we are incrementing the value by 1, we may only be tracking clicks
end) -- player index 1
Used to add a both instance and data store which are linked together, new instances are synced to the current value, changing the stored value will change all instances
Parameters:-- Adding a check box which is a "global setting" synced between all players
local custom_button =
Gui.get_concept('checkbox'):clone('my_checkbox')
:set_caption('My Checkbox')
:set_tooltip('Clicking this check box will change it for everyone')
:on_state_changed(function(event)
local element = event.element
event.concept.set_data(element,element.state) -- Update the stored data to trigger an update of all other instances
end)
:define_combined_store(function(element,state) -- We could add a category function here if we wanted to
element.state = state or false -- Note that the value passed may be nil if there is no stored value and no default set
end)
Will sync an instance to match the stored value based on the given sync callback
Parameters:-- Setting the caption of this element to be the same as the stored value
local custom_button =
Gui.get_concept('CustomButton')
-- Used internally when first draw and automatically when the store updates
custom_button.sync_instance(element)