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 |
| progress_bar | The basic checkbox element |
| slider | The basic slider element |
| text_box | The text box element |
| text_field | The text field 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 |
| 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) | 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_changed(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_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.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_changed(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','basic_elembutton')
:on_selection_changed(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)
The basic checkbox element
Properties / Events:-- Making a basic progress bar, will increase when pressed then will reset when full
local basic_progress_bar =
Gui.clone_concept('progress_bar','basic_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)
The basic slider element
Properties / Events:-- Making a basic slider
local basic_slider =
Gui.clone_concept('slider','basic_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.clone_concept('slider','discrete_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)
The text box element
Properties / Events:-- Making a text box
local basic_text_box =
Gui.clone_concept('text_box','basic_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.clone_concept('text_box','editible_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)
The text field element
Properties / Events:-- Making a text field
local basic_text_field =
Gui.clone_concept('text_field','basic_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.clone_concept('text_field','better_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.clone_concept('text_field','decimal_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, 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_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)