Core Module - Gui
-- Making the base button concept
local button =
Gui.new_concept('Button')
:new_event('on_click',defines.events.on_gui_click)
: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)
:define_draw(function(properties,parent,element)
-- Note that element might be nil if this is the first draw function
-- in this case button is a new concept so we know this is the first function and element is nil
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
-- We must return the element or what we want to be seen as the instance, this is so other draw functions have access to it
-- for example if our custom button defined a draw function to change the font color to red
return element
end)
-- Makeing a alternative button based on the first
local custom_button =
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)
:set_caption('Custom Button')
:set_tooltip('Only admins can press this button')
:on_click(function(event)
if not event.player.admin then
event.player.print('You must be admin to use this button')
end
end)
:on_admin_clicked(function(event)
-- Yes i know this can just be an if else but its an example
game.print(event.player.name..' pressed my admin button')
end)
-- Drawing a concept
custom_button:draw(game.player.gui.left)
| button | The basic button element |
| checkbox | The basic checkbox element |
| dropdown | The basic dropdown element |
| elem_button | The basic dropdown element |
| frame | The basic frame element |
| 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 |
| require_concept(concept) | Loads a concept from the concepts file, used internally |
| get_concept(name) | Gets the gui concept with this name |
| Prototype:change_name([new_name=self.name]) | Used internally to save concept names to the core gui module |
| new_concept(name) | Returns a new gui concept with no properties or events |
| clone_concept(name, new_name) | Make a new concept based on the properties and drawing of another |
| draw_concept(name, 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 |
| 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:change_name([new_name=self.name]) | Used internally to save concept names to the core gui module |
| 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, default[, setter_callback]) | 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) | 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 |
The basic button element
Properties / Events:-- Making a basic button
local basic_button =
Gui.clone_concept('button','basic_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.clone_concept('button','sprite_button')
:set_sprite('utility/warning_icon')
:set_tooltip('Sprite button')
:on_click(function(event)
event.player.print('You pressed sprite button!')
end)
The basic checkbox element
Properties / Events:-- Making a basic checkbox
local basic_checkbox =
Gui.clone_concept('checkbox','basic_checkbox')
:set_caption('Basic Checkbox')
:set_tooltip('Basic checkbox')
:on_state_change(function(event)
event.player.print('Basic checkbox is now: '..tostring(event.element.state))
end)
The basic dropdown element
Properties / Events:-- Making a basic dropdown
local static_dropdown =
Gui.clone_concept('dropdown','static_dropdown')
:set_static_items{'Option 1','Option 2','Option 3'}
:on_selection_change(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.clone_concept('dropdown','dynamic_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_change(function(event)
local value = Gui.get_dropdown_value(event.element)
event.player.print('Dynamic dropdown is now: '..value)
end)
The basic dropdown element
Properties / Events:-- Making a basic elem button
local basic_elem_button =
Gui.clone_concept('elem_button',TEST 'basic_elembutton')
:on_selection_change(function(event)
event.player.print('Basic elem button is now: '..event.element.elem_value)
end)
The basic frame element
Properties / Events:-- Making a basic frame, contains a label with hello world
local basic_frame =
Gui.clone_concept('dropdown','basic_frame')
:set_title('Basic Frame')
:define_draw(function(properties,parent,element)
element.add{
type = 'label',
caption = 'Hello, World!'
}
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'})
Loads a concept from the concepts file, used internally
Parameters:-- Load a base concept
Gui.require_concept('frame')
Gets the gui concept with this name
Parameters:-- Getting a gui concept
local button = Gui.get_concept('Button')
Used internally to save concept names to the core gui module
Parameters:-- Internal Saving
-- this is never needed to be done, internal use only!
local button = Gui.get_concept('Button')
button:change_name('Not Button')
Returns a new gui concept with no properties or events
Parameters:-- Making a new concept, see module usage
local button = Gui.new_concept('Button')
Make a new concept based on the properties and drawing of another
Parameters:-- Making a new concept from another, see module usage
local custom_button = Gui.clone_concept('Button','CustomButton')
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)
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('Button'):clone('CustomButton')
Used internally to save concept names to the core gui module
Parameters:-- Internal Saving
-- this is never needed to be done, internal use only!
local button = Gui.get_concept('Button')
button:change_name('Not 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)
-- Note that element might be nil if this is the first draw function
-- for this example we assume button was cloned from Prototype and so has no other draw functions defined
-- this means that there is no element yet and what we return will be the first time the element is returned
-- although not shown here you also can recive any extra arguments here from the call to draw
if properties.type == 'button' then
element = parent.draw{
type = properties.type,
name = properties.name,
caption = properties.caption,
tooltip = properties.tooltip
}
else
element = parent.draw{
type = properties.type,
name = properties.name,
sprite = properties.sprite,
tooltip = properties.tooltip
}
end
-- We must return the element or what we want to be seen as the instance, this is so other draw functions have access to it
-- for example if our custom button defined a draw function to change the font color to red
return element
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_change(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 -- When you sync an instance this is what is called
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)