mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Revert
This commit is contained in:
@@ -39,12 +39,12 @@ return {
|
||||
'modules.addons.discord-alerts',
|
||||
'modules.addons.chat-reply',
|
||||
-- GUI
|
||||
--'modules.gui.rocket-info',
|
||||
--'modules.gui.science-info',
|
||||
--'modules.gui.warp-list',
|
||||
--'modules.gui.task-list',
|
||||
'modules.gui.rocket-info',
|
||||
'modules.gui.science-info',
|
||||
'modules.gui.warp-list',
|
||||
'modules.gui.task-list',
|
||||
'modules.gui.player-list',
|
||||
--'modules.commands.debug',
|
||||
'modules.commands.debug',
|
||||
-- Config Files
|
||||
'config.expcore-commands.auth_admin', -- commands tagged with admin_only are blocked for non admins
|
||||
'config.expcore-commands.auth_roles', -- commands must be allowed via the role config
|
||||
|
||||
@@ -15,16 +15,12 @@ local Jail = require 'modules.control.jail' --- @dep modules.control.jail
|
||||
local Colors = require 'resources.color_presets' --- @dep resources.color_presets
|
||||
local format_chat_player_name = ext_require('expcore.common','format_chat_player_name') --- @dep expcore.common
|
||||
|
||||
Gui.require_concept('button')
|
||||
|
||||
local action_player_store = 'gui.left.player-list.action-player'
|
||||
local action_name_store = 'gui.left.player-list.action-name'
|
||||
|
||||
-- common style used by all action buttons
|
||||
local function tool_button_style(properties,parent,element)
|
||||
element.style = 'tool_button'
|
||||
local style = element.style
|
||||
style.padding = -1
|
||||
local function tool_button_style(style)
|
||||
Gui.set_padding_style(style,-1,-1,-1,-1)
|
||||
style.height = 28
|
||||
style.width = 28
|
||||
end
|
||||
@@ -59,12 +55,11 @@ end
|
||||
--- Teleports the user to the action player
|
||||
-- @element goto_player
|
||||
local goto_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/export')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/export')
|
||||
:set_tooltip{'player-list.goto-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
local action_player_name = get_action_player_name(player)
|
||||
local action_player = Game.get_player_from_any(action_player_name)
|
||||
if not player.character or not action_player.character then
|
||||
@@ -77,12 +72,11 @@ end)
|
||||
--- Teleports the action player to the user
|
||||
-- @element bring_player
|
||||
local bring_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/import')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/import')
|
||||
:set_tooltip{'player-list.bring-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
local action_player_name = get_action_player_name(player)
|
||||
local action_player = Game.get_player_from_any(action_player_name)
|
||||
if not player.character or not action_player.character then
|
||||
@@ -95,12 +89,11 @@ end)
|
||||
--- Kills the action player, if there are alive
|
||||
-- @element kill_player
|
||||
local kill_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/too_far')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/too_far')
|
||||
:set_tooltip{'player-list.kill-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
local action_player_name = get_action_player_name(player)
|
||||
local action_player = Game.get_player_from_any(action_player_name)
|
||||
if action_player.character then
|
||||
@@ -113,12 +106,11 @@ end)
|
||||
--- Reports the action player, requires a reason to be given
|
||||
-- @element report_player
|
||||
local report_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/spawn_flag')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/spawn_flag')
|
||||
:set_tooltip{'player-list.report-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
local action_player_name = get_action_player_name(player)
|
||||
if Reports.is_reported(action_player_name,player.name) then
|
||||
player.print({'expcom-report.already-reported'},Colors.orange_red)
|
||||
@@ -138,12 +130,11 @@ end
|
||||
--- Gives the action player a warning, requires a reason
|
||||
-- @element warn_player
|
||||
local warn_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/spawn_flag')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/spawn_flag')
|
||||
:set_tooltip{'player-list.warn-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
Store.set(action_name_store,player.name,'command/give-warning')
|
||||
end)
|
||||
|
||||
@@ -157,12 +148,11 @@ end
|
||||
--- Jails the action player, requires a reason
|
||||
-- @element jail_player
|
||||
local jail_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/item_editor_icon')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/item_editor_icon')
|
||||
:set_tooltip{'player-list.jail-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
local action_player_name,action_player_name_color = get_action_player_name(player)
|
||||
if Jail.is_jailed(action_player_name) then
|
||||
player.print({'expcom-jail.already-jailed',action_player_name_color},Colors.orange_red)
|
||||
@@ -181,12 +171,11 @@ end
|
||||
--- Temp bans the action player, requires a reason
|
||||
-- @element temp_ban_player
|
||||
local temp_ban_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/clock')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/clock')
|
||||
:set_tooltip{'player-list.temp-ban-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
local action_player_name,action_player_name_color = get_action_player_name(player)
|
||||
if Jail.is_jailed(action_player_name) then
|
||||
player.print({'expcom-jail.already-banned',action_player_name_color},Colors.orange_red)
|
||||
@@ -205,12 +194,11 @@ end
|
||||
--- Kicks the action player, requires a reason
|
||||
-- @element kick_player
|
||||
local kick_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/warning_icon')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/warning_icon')
|
||||
:set_tooltip{'player-list.kick-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
Store.set(action_name_store,player.name,'command/kick')
|
||||
end)
|
||||
|
||||
@@ -222,12 +210,11 @@ end
|
||||
--- Bans the action player, requires a reason
|
||||
-- @element ban_player
|
||||
local ban_player =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/danger_icon')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/danger_icon')
|
||||
:set_tooltip{'player-list.ban-player'}
|
||||
:define_draw(tool_button_style)
|
||||
:on_click(function(event)
|
||||
local player = event.player
|
||||
:set_style('tool_button',tool_button_style)
|
||||
:on_click(function(player,element)
|
||||
Store.set(action_name_store,player.name,'command/ban')
|
||||
end)
|
||||
|
||||
|
||||
345
expcore/gui.lua
345
expcore/gui.lua
@@ -1,71 +1,284 @@
|
||||
--[[-- Core Module - Gui
|
||||
- This file is used to require all the different elements of the gui module
|
||||
- each module has an outline here but for more details see their separate files in ./gui
|
||||
- please read the files for more documentation that cant be shown here
|
||||
- please note there is a rework planned but not started
|
||||
@core Gui
|
||||
@alias Gui
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- Drawing a concept
|
||||
custom_button:draw(game.player.gui.left)
|
||||
]]
|
||||
|
||||
return require 'expcore.gui.core'
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
|
||||
--[[
|
||||
Core
|
||||
|
||||
Gui.new_define(prototype) --- Used internally to create new element defines from a class prototype
|
||||
Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to
|
||||
|
||||
Gui.categorize_by_player(element) --- A categorize function to be used with add_store, each player has their own value
|
||||
Gui.categorize_by_force(element) --- A categorize function to be used with add_store, each force has its own value
|
||||
Gui.categorize_by_surface(element) --- A categorize function to be used with add_store, each surface has its own value
|
||||
|
||||
Gui.toggle_enabled(element) --- Will toggle the enabled state of an element
|
||||
Gui.toggle_visible(element) --- Will toggle the visibility of an element
|
||||
Gui.set_padding(element,up,down,left,right) --- Sets the padding for a gui element
|
||||
Gui.set_padding_style(style,up,down,left,right) --- Sets the padding for a gui style
|
||||
Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into
|
||||
Gui.destroy_if_valid(element) --- Destroys an element but tests for it being present and valid first
|
||||
Gui.create_scroll_table(element,table_size,maximal_height,name) --- Creates a scroll area with a table inside, table can be any size
|
||||
Gui.create_header(element,caption,tooltip,right_align,name) --- Creates a header section with a label and button area
|
||||
|
||||
Prototype Constructor
|
||||
|
||||
Constructor.event(event_name) --- Creates a new function to add functions to an event handler
|
||||
Constructor.extend(new_prototype) --- Extents a prototype with the base functions of all gui prototypes, no metatables
|
||||
Constructor.store(sync,callback) --- Creates a new function which adds a store to a gui define
|
||||
Constructor.setter(value_type,key,second_key) --- Creates a setter function that checks the type when a value is set
|
||||
|
||||
Base Prototype
|
||||
|
||||
Prototype:uid() --- Gets the uid for the element define
|
||||
Prototype:debug_name(value) --- Sets a debug alias for the define
|
||||
Prototype:set_caption(value) --- Sets the caption for the element define
|
||||
Prototype:set_tooltip(value) --- Sets the tooltip for the element define
|
||||
Prototype:set_style(style,callback) --- Sets the style for the element define
|
||||
Prototype:set_embedded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function
|
||||
|
||||
Prototype:set_pre_authenticator --- Sets an authenticator that blocks the draw function if check fails
|
||||
Prototype:set_post_authenticator --- Sets an authenticator that disables the element if check fails
|
||||
|
||||
Prototype:raise_event(event_name,...) --- Raises a custom event for this define, any number of params can be given
|
||||
Prototype:draw_to(element,...) --- The main function for defines, when called will draw an instance of this define to the given element
|
||||
|
||||
Prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used
|
||||
Prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used
|
||||
Prototype:clear_store(category) --- Sets the value in this elements store to nil, category needed if categorize function used
|
||||
]]
|
||||
|
||||
local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances
|
||||
Gui.new_instance_group = Instances.registers
|
||||
Gui.get_instances = Instances.get_elements
|
||||
Gui.add_instance = Instances.get_elements
|
||||
Gui.update_instances = Instances.apply_to_elements
|
||||
Gui.classes.instances = Instances
|
||||
--[[
|
||||
Instances.has_categories(name) --- Returns if a instance group has a categorise function; must be registered
|
||||
Instances.is_registered(name) --- Returns if the given name is a registered instance group
|
||||
Instances.register(name,categorise) --- Registers the name of an instance group to allow for storing element instances
|
||||
|
||||
Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered
|
||||
Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered
|
||||
Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid
|
||||
|
||||
Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered
|
||||
Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered
|
||||
]]
|
||||
|
||||
local Button = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons
|
||||
Gui.new_button = Button.new_button
|
||||
Gui.classes.button = Button
|
||||
--[[
|
||||
Button.new_button(name) --- Creates a new button element define
|
||||
|
||||
Button._prototype:on_click(player,element) --- Registers a handler for when the button is clicked
|
||||
Button._prototype:on_left_click(player,element) --- Registers a handler for when the button is clicked with the left mouse button
|
||||
Button._prototype:on_right_click(player,element) --- Registers a handler for when the button is clicked with the right mouse button
|
||||
|
||||
Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite) --- Adds sprites to a button making it a sprite button
|
||||
Button._prototype:set_click_filter(filter,...) --- Adds a click / mouse button filter to the button
|
||||
Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button
|
||||
]]
|
||||
|
||||
local Checkbox = require 'expcore.gui.elements.checkbox' --- @dep expcore.gui.elements.checkbox
|
||||
Gui.new_checkbox = Checkbox.new_checkbox
|
||||
Gui.new_radiobutton = Checkbox.new_radiobutton
|
||||
Gui.new_radiobutton_option_set = Checkbox.new_option_set
|
||||
Gui.draw_option_set = Checkbox.draw_option_set
|
||||
Gui.classes.checkbox = Checkbox
|
||||
--[[
|
||||
Checkbox.new_checkbox(name) --- Creates a new checkbox element define
|
||||
Checkbox._prototype_checkbox:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Checkbox._prototype_checkbox:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Checkbox.new_radiobutton(name) --- Creates a new radiobutton element define
|
||||
Checkbox._prototype_radiobutton:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Checkbox._prototype_radiobutton:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) --- Adds this radiobutton to be an option in the given option set (only one can be true at a time)
|
||||
|
||||
Checkbox.new_option_set(name,callback,categorize) --- Registers a new option set that can be linked to radiobuttons (only one can be true at a time)
|
||||
Checkbox.draw_option_set(name,element) --- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work)
|
||||
|
||||
Checkbox.reset_radiobutton(element,exclude,recursive) --- Sets all radiobuttons in a element to false (unless excluded) and can act recursively
|
||||
]]
|
||||
|
||||
local Dropdown = require 'expcore.gui.elements.dropdown' --- @dep expcore.gui.elements.dropdown
|
||||
Gui.new_dropdown = Dropdown.new_dropdown
|
||||
Gui.new_list_box = Dropdown.new_list_box
|
||||
Gui.classes.dropdown = Dropdown
|
||||
--[[
|
||||
Dropdown.new_dropdown(name) --- Creates a new dropdown element define
|
||||
Dropdown.new_list_box(name) --- Creates a new list box element define
|
||||
|
||||
Dropdown._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Dropdown._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Dropdown._prototype:new_static_options(options,...) --- Adds new static options to the dropdown which will trigger the general callback
|
||||
Dropdown._prototype:new_dynamic_options(callback) --- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options)
|
||||
Dropdown._prototype:add_option_callback(option,callback) --- Adds a case specific callback which will only run when that option is selected (general case still triggered)
|
||||
|
||||
Dropdown.select_value(element,value) --- Selects the option from a dropdown or list box given the value rather than key
|
||||
Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index
|
||||
]]
|
||||
|
||||
local Slider = require 'expcore.gui.elements.slider' --- @dep expcore.gui.elements.slider
|
||||
Gui.new_slider = Slider.new_slider
|
||||
Gui.classes.slider = Slider
|
||||
--[[
|
||||
Slider.new_slider(name) --- Creates a new slider element define
|
||||
|
||||
Slider._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Slider._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Slider._prototype:set_range(min,max) --- Sets the range of a slider, if not used will use default values for a slider
|
||||
Slider._prototype:draw_label(element) --- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player
|
||||
Slider._prototype:enable_auto_draw_label(state) --- Enables auto draw of the label, the label will share the same parent element as the slider
|
||||
]]
|
||||
|
||||
local Text = require 'expcore.gui.elements.text' --- @dep expcore.gui.elements.text
|
||||
Gui.new_text_filed = Text.new_text_field
|
||||
Gui.new_text_box = Text.new_text_box
|
||||
Gui.classes.text = Text
|
||||
--[[
|
||||
Text.new_text_field(name) --- Creates a new text field element define
|
||||
Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Text.new_text_box(name) --- Creates a new text box element define
|
||||
Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
Text._prototype_box:set_selectable(state) --- Sets the text box to be selectable
|
||||
Text._prototype_box:set_word_wrap(state) --- Sets the text box to have word wrap
|
||||
Text._prototype_box:set_read_only(state) --- Sets the text box to be read only
|
||||
]]
|
||||
|
||||
local ElemButton = require 'expcore.gui.elements.elem-button' --- @dep expcore.gui.elements.elem-button
|
||||
Gui.new_elem_button = ElemButton.new_elem_button
|
||||
Gui.classes.elem_button = ElemButton
|
||||
--[[
|
||||
ElemButton.new_elem_button(name) --- Creates a new elem button element define
|
||||
|
||||
ElemButton._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
ElemButton._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
ElemButton._prototype:set_type(type) --- Sets the type of the elem button, the type is required so this must be called at least once
|
||||
ElemButton._prototype:set_default(value) --- Sets the default value for the elem button, this may be a function or a string
|
||||
]]
|
||||
|
||||
local ProgressBar = require 'expcore.gui.elements.progress-bar' --- @dep expcore.gui.elements.progress-bar
|
||||
Gui.new_progressbar = ProgressBar.new_progressbar
|
||||
Gui.set_progressbar_maximum = ProgressBar.set_maximum
|
||||
Gui.increment_progressbar = ProgressBar.increment
|
||||
Gui.decrement_progressbar = ProgressBar.decrement
|
||||
Gui.classes.progressbar = ProgressBar
|
||||
--[[
|
||||
ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
|
||||
ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented
|
||||
ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decreased
|
||||
|
||||
ProgressBar.new_progressbar(name) --- Creates a new progressbar element define
|
||||
ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
|
||||
ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0
|
||||
ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar
|
||||
ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store
|
||||
ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar
|
||||
ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store
|
||||
ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store
|
||||
ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0
|
||||
|
||||
ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element completes (hits 0 or 1)
|
||||
ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1)
|
||||
ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggers, can filter which elements are incremented
|
||||
ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggers, can filter which elements are decremented
|
||||
]]
|
||||
|
||||
local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar
|
||||
Gui.new_toolbar_button = Toolbar.new_button
|
||||
Gui.add_button_to_toolbar = Toolbar.add_button
|
||||
Gui.update_toolbar = Toolbar.update
|
||||
Gui.classes.toolbar = Toolbar
|
||||
--[[
|
||||
Toolbar.new_button(name) --- Adds a new button to the toolbar
|
||||
Toolbar.add_button(button) --- Adds an existing buttton to the toolbar
|
||||
Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return
|
||||
]]
|
||||
|
||||
local LeftFrames = require 'expcore.gui.concepts.left' --- @dep expcore.gui.concepts.left
|
||||
Gui.get_left_frame_flow = LeftFrames.get_flow
|
||||
Gui.toggle_left_frame = LeftFrames.toggle_frame
|
||||
Gui.new_left_frame = LeftFrames.new_frame
|
||||
Gui.classes.left_frames = LeftFrames
|
||||
--[[
|
||||
LeftFrames.get_flow(player) --- Gets the left frame flow for a player
|
||||
LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name
|
||||
LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button
|
||||
LeftFrames.toggle_frame(name,player,state) --- Toggles the visibility of a left frame, or sets its visibility state
|
||||
|
||||
LeftFrames.new_frame(permission_name) --- Creates a new left frame define
|
||||
LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean
|
||||
LeftFrames._prototype:set_direction(direction) --- Sets the direction of the frame, either vertical or horizontal
|
||||
LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow
|
||||
LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible
|
||||
LeftFrames._prototype:toggle(player) --- Toggles the visibility of the left frame
|
||||
|
||||
LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw
|
||||
LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update
|
||||
LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame
|
||||
LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw
|
||||
|
||||
LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame
|
||||
LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it
|
||||
LeftFrames._prototype:on_player_toggle(player,frame) --- Triggered when the player toggle the left frame
|
||||
LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
|
||||
]]
|
||||
|
||||
local CenterFrames = require 'expcore.gui.concepts.center' --- @dep expcore.gui.concepts.center
|
||||
Gui.get_center_flow = CenterFrames.get_flow
|
||||
Gui.toggle_center_frame = CenterFrames.toggle_frame
|
||||
Gui.draw_center_frame = CenterFrames.draw_frame
|
||||
Gui.redraw_center_frame = CenterFrames.redraw_frames
|
||||
Gui.new_center_frame = CenterFrames.new_frame
|
||||
Gui.classes.center_frames = CenterFrames
|
||||
--[[
|
||||
CenterFrames.get_flow(player) --- Gets the center flow for a player
|
||||
CenterFrames.clear_flow(player) --- Clears the center flow for a player
|
||||
CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing
|
||||
CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destroy it and redraw
|
||||
CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open
|
||||
|
||||
CenterFrames.new_frame(permission_name) --- Sets the frame to be the current active gui when opened and closes all other frames
|
||||
CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame
|
||||
CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames
|
||||
CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
|
||||
CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
|
||||
CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it
|
||||
CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
|
||||
]]
|
||||
|
||||
local PopupFrames = require 'expcore.gui.concepts.popups' --- @dep expcore.gui.concepts.popups
|
||||
Gui.get_popup_flow = PopupFrames.get_flow
|
||||
Gui.open_popup = PopupFrames.open
|
||||
Gui.new_popup = PopupFrames.new_popup
|
||||
Gui.classes.popup_frames = PopupFrames
|
||||
--[[
|
||||
PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames
|
||||
PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
|
||||
|
||||
PopupFrames.close_progress --- Progress bar which when depleted will close the popup frame
|
||||
PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out
|
||||
|
||||
PopupFrames.new_popup(name) --- Creates a new popup frame define
|
||||
PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open
|
||||
PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function
|
||||
]]
|
||||
|
||||
return Gui
|
||||
@@ -1,90 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Clickable elements that fire on_gui_click when clicked.
|
||||
@element button
|
||||
|
||||
@param on_click fired when the player clicks the button
|
||||
@param on_left_click fired when the player clicks with the left mouse button
|
||||
@param on_left_click fired when the player clicks with the right mouse button
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString caption the message that is shown on the button
|
||||
@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the button
|
||||
@tparam Concepts.SpritePath sprite upto three sprites in the order: default, hovered, clicked
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('button')
|
||||
|
||||
-- Events
|
||||
:new_event('on_click',defines.events.on_gui_click)
|
||||
:new_event('on_left_click',defines.events.on_gui_click,function(event)
|
||||
return event.mouse_button == defines.mouse_button_type.left
|
||||
end)
|
||||
:new_event('on_right_click',defines.events.on_gui_click,function(event)
|
||||
return event.mouse_button == defines.mouse_button_type.right
|
||||
end)
|
||||
|
||||
-- Properties
|
||||
:new_property('tooltip')
|
||||
:new_property('caption',function(properties,value)
|
||||
properties.caption = value
|
||||
properties.type = 'button'
|
||||
end)
|
||||
:new_property('sprite',function(properties,value,hovered_sprite,clicked_sprite)
|
||||
properties.sprite = value
|
||||
properties.hovered_sprite = hovered_sprite
|
||||
properties.clicked_sprite = clicked_sprite
|
||||
properties.type = 'sprite-button'
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Check if it should be a sprite button
|
||||
if properties.type == 'sprite-button' then
|
||||
-- Draw a sprite button
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'sprite-button',
|
||||
sprite = properties.sprite,
|
||||
hovered_sprite = properties.hovered_sprite,
|
||||
clicked_sprite = properties.clicked_sprite,
|
||||
tooltip = properties.tooltip
|
||||
}
|
||||
|
||||
else
|
||||
-- Draw a button
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'button',
|
||||
caption = properties.caption,
|
||||
tooltip = properties.tooltip
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
198
expcore/gui/concepts/center.lua
Normal file
198
expcore/gui/concepts/center.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Center Guis.
|
||||
-- Gui structure define for center gui frames
|
||||
-- @section center
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
CenterFrames.get_flow(player) --- Gets the center flow for a player
|
||||
CenterFrames.clear_flow(player) --- Clears the center flow for a player
|
||||
CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing
|
||||
CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destroy it and redraw
|
||||
CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open
|
||||
|
||||
CenterFrames.new_frame(permission_name) --- Sets the frame to be the current active gui when opened and closes all other frames
|
||||
CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame
|
||||
CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames
|
||||
CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
|
||||
CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
|
||||
CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it
|
||||
CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
local CenterFrames = {
|
||||
_prototype = Prototype.extend{
|
||||
on_creation = Prototype.event
|
||||
}
|
||||
}
|
||||
|
||||
--- Gets the center flow for a player
|
||||
-- @tparam LuaPlayer player the player to get the flow for
|
||||
-- @treturn LuaGuiElement the center flow
|
||||
function CenterFrames.get_flow(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
return player.gui.center
|
||||
end
|
||||
|
||||
--- Clears the center flow for a player
|
||||
-- @tparam LuaPlayer player the player to clear the flow for
|
||||
function CenterFrames.clear_flow(player)
|
||||
local flow = CenterFrames.get_flow(player)
|
||||
flow.clear()
|
||||
end
|
||||
|
||||
--- Draws the center frame for a player, if already open then will do nothing
|
||||
-- @tparam LuaPlayer player the player that will have the frame drawn
|
||||
-- @tparam string name the name of the hui that will drawn
|
||||
-- @treturn LuaGuiElement the new frame that was made
|
||||
function CenterFrames.draw_frame(player,name)
|
||||
local define = Gui.get_define(name,true)
|
||||
if define then
|
||||
return define:draw_frame(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Draws the center frame for a player, if already open then will destroy it and redraw
|
||||
-- @tparam LuaPlayer player the player that will have the frame drawn
|
||||
-- @tparam string name the name of the hui that will drawn
|
||||
-- @treturn LuaGuiElement the new frame that was made
|
||||
function CenterFrames.redraw_frame(player,name)
|
||||
local define = Gui.get_define(name,true)
|
||||
if define then
|
||||
return define:draw_frame(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Toggles if the frame is currently open or not, will open if closed and close if open
|
||||
-- @tparam LuaPlayer player the player that will have the frame toggled
|
||||
-- @tparam string name the name of the hui that will be toggled
|
||||
-- @tparam[opt] boolean state when set will force a state for the frame
|
||||
-- @treturn boolean if the frame if no open or closed
|
||||
function CenterFrames.toggle_frame(player,name,state)
|
||||
local define = Gui.get_define(name,true)
|
||||
if define then
|
||||
if state == true then
|
||||
define:draw_frame(player)
|
||||
return true
|
||||
elseif state == false then
|
||||
local flow = CenterFrames.get_flow(player)
|
||||
if flow[define.name..'-frame'] then
|
||||
flow[define.name..'-frame'].destroy()
|
||||
end
|
||||
return false
|
||||
else
|
||||
return define:toggle_frame(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a new center frame define
|
||||
-- @tparam string permission_name the name that can be used with the permission system
|
||||
-- @treturn table the new center frame define
|
||||
function CenterFrames.new_frame(permission_name)
|
||||
local self = Toolbar.new_button(permission_name)
|
||||
|
||||
self:on_click(function(player,element)
|
||||
self:toggle_frame(player)
|
||||
end)
|
||||
|
||||
local mt = getmetatable(self)
|
||||
mt.__index = CenterFrames._prototype
|
||||
mt.__call = self.event_handler
|
||||
|
||||
Gui.on_custom_close(self.name..'-frame',function(event)
|
||||
local element = event.element
|
||||
if element and element.valid then element.destroy() end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the frame to be the current active gui when opened and closes all other frames
|
||||
-- @tparam[opt=true] boolean state when true will auto close other frames and set this frame as player.opened
|
||||
function CenterFrames._prototype:set_auto_focus(state)
|
||||
if state == false then
|
||||
self.auto_focus = false
|
||||
else
|
||||
self.auto_focus = true
|
||||
end
|
||||
end
|
||||
|
||||
--- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
|
||||
-- @tparam LuaPlayer player the player to draw the frame for
|
||||
-- @treturn LuaGuiElement the new frame that was drawn
|
||||
function CenterFrames._prototype:draw_frame(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
local flow = CenterFrames.get_flow(player)
|
||||
|
||||
if flow[self.name..'-frame'] then
|
||||
return flow[self.name..'-frame']
|
||||
end
|
||||
|
||||
if self.auto_focus then
|
||||
flow.clear()
|
||||
end
|
||||
|
||||
local frame = flow.add{
|
||||
type='frame',
|
||||
name=self.name..'-frame'
|
||||
}
|
||||
|
||||
if self.auto_focus then
|
||||
player.opened = frame
|
||||
end
|
||||
|
||||
self:raise_event('on_creation',player,frame)
|
||||
|
||||
return frame
|
||||
end
|
||||
|
||||
--- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
|
||||
-- @tparam LuaPlayer player the player to draw the frame for
|
||||
-- @treturn LuaGuiElement the new frame that was drawn
|
||||
function CenterFrames._prototype:redraw_frame(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
local flow = CenterFrames.get_flow(player)
|
||||
|
||||
if flow[self.name..'-frame'] then
|
||||
flow[self.name..'-frame'].destroy()
|
||||
end
|
||||
|
||||
return self:draw_frame(player)
|
||||
end
|
||||
|
||||
--- Toggles if the frame is open, if open it will close it and if closed it will open it
|
||||
-- @tparam LuaPlayer player the player to draw the frame for
|
||||
-- @treturn boolean with the gui frame is now open
|
||||
function CenterFrames._prototype:toggle_frame(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
local flow = CenterFrames.get_flow(player)
|
||||
|
||||
if flow[self.name..'-frame'] then
|
||||
flow[self.name..'-frame'].destroy()
|
||||
return false
|
||||
else
|
||||
self:draw_frame(player)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates an event handler that will trigger one of its functions, use with Event.add
|
||||
-- @tparam[opt=update] string action the action to take on this event
|
||||
function CenterFrames._prototype:event_handler(action)
|
||||
action = action or 'update'
|
||||
return function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
self[action](self,player)
|
||||
end
|
||||
end
|
||||
|
||||
return CenterFrames
|
||||
@@ -1,62 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Clickable elements with a cross in the middle that can be turned off or on.
|
||||
@element checkbox
|
||||
|
||||
@param on_state_changed fired when the state of the element is changed
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString caption the message that is shown next to the checkbox
|
||||
@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the checkbox
|
||||
@tparam ?boolean|function default the default state of this checkbox, or a function which returns the default state
|
||||
@tparam boolean use_radio setting to true will use radio buttons rather than checkboxs
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('checkbox')
|
||||
|
||||
-- Events
|
||||
:new_event('on_state_changed',defines.events.on_gui_checked_state_changed)
|
||||
|
||||
-- Properties
|
||||
:new_property('tooltip')
|
||||
:new_property('caption')
|
||||
:new_property('default',nil,false)
|
||||
:new_property('use_radio',nil,false)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
local default = properties.default
|
||||
local state = type(default) == 'boolean' and default
|
||||
|
||||
-- Draw a checkbox
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = properties.use_radio and 'radiobutton' or 'checkbox',
|
||||
caption = properties.caption,
|
||||
tooltip = properties.tooltip,
|
||||
state = state
|
||||
}
|
||||
|
||||
-- Set the default state
|
||||
default = Gui.resolve_property(default,element)
|
||||
if default and default ~= state then
|
||||
element.state = default
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,169 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
local array_insert = ext_require('expcore.common','array_insert')
|
||||
|
||||
--[[-- A drop down list of other elements.
|
||||
@element dropdown
|
||||
|
||||
@param on_selection_changed fired when the selected value is changed
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString|function default the option which is selected by default, or a function which returns the default
|
||||
@tparam boolean use_list_box when true a list box will be used rather than a dropdown menu
|
||||
@tparam ?nil|table static_items when called with a table the values will be added as items for the dropdown, if called with nil then all items are cleared
|
||||
@tparam function dynamic_items the given function will be called to return a list of items and optional start index to add items to the dropdown when it is first drawn
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('dropdown')
|
||||
|
||||
-- Events
|
||||
:new_event('on_selection_changed',defines.events.on_gui_selection_state_changed)
|
||||
|
||||
-- Properties
|
||||
:new_property('default')
|
||||
:new_property('use_list_box',nil,false)
|
||||
:new_property('static_items',function(properties,value,start_index)
|
||||
-- Clear all items if value is nil
|
||||
if not value then
|
||||
properties.items = {}
|
||||
end
|
||||
|
||||
-- Convert value to a table
|
||||
if type(value) ~= 'table' then
|
||||
value = {value}
|
||||
end
|
||||
|
||||
-- If there are no items then set and return
|
||||
local items = properties.items
|
||||
if not items then
|
||||
properties.items = value
|
||||
return
|
||||
end
|
||||
|
||||
-- Otherwise insert into the array
|
||||
array_insert(items,start_index,value)
|
||||
end)
|
||||
:new_property('dynamic_items',function(properties,value)
|
||||
-- Check that a function value was given
|
||||
if type(value) ~= 'function' then
|
||||
error('Dynamic items must be a function')
|
||||
end
|
||||
|
||||
-- If no dynamic items then set and return
|
||||
local items = properties.dynamic_items
|
||||
if not items then
|
||||
properties.dynamic_items = {value}
|
||||
return
|
||||
end
|
||||
|
||||
-- Otherwise append to the end
|
||||
items[#items+1] = value
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a dropdown
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = properties.use_list_box and 'list-box' or 'drop-down',
|
||||
items = properties.items
|
||||
}
|
||||
|
||||
-- If there are dynamic items then add them
|
||||
if properties.dynamic_items then
|
||||
for _,callback in pairs(properties.dynamic_items) do
|
||||
local dynamic_items, start_index = callback(element)
|
||||
Gui.add_dropdown_items(element,start_index,dynamic_items)
|
||||
end
|
||||
end
|
||||
|
||||
-- If there is a default, select it
|
||||
local default = Gui.resolve_property(properties.default,element)
|
||||
if default then
|
||||
Gui.set_dropdown_value(element,default)
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
|
||||
--- Dropdowns.
|
||||
-- functions used with dropdowns
|
||||
-- @section dropdowns
|
||||
|
||||
--[[-- Selects the index of a dropdown with this value
|
||||
@tparam LuaGuiElement element the dropdown that you want to set the selection for
|
||||
@tparam ?string|Concepts.LocalisedString value the value that you want selected
|
||||
@treturn boolean if an item with this value was found
|
||||
@usage-- Selecting the item with the value 'foo'
|
||||
Gui.set_dropdown_value(element,'foo')
|
||||
]]
|
||||
function Gui.set_dropdown_value(element,value)
|
||||
for index, item in pairs(element.items) do
|
||||
if item == value then
|
||||
element.selected_index = index
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[-- Gets the selected item value of a dropdown
|
||||
@tparam LuaGuiElement element the dropdown that you want the selected value of
|
||||
@treturn ?string|Concepts.LocalisedString the value that is currently selected
|
||||
@usage-- Getting the selected value
|
||||
local selected_value = Gui.get_dropdown_value(element)
|
||||
]]
|
||||
function Gui.get_dropdown_value(element)
|
||||
return element.items[element.selected_index]
|
||||
end
|
||||
|
||||
--[[-- Adds the given items into the list of items for this dropdown
|
||||
@tparam LuaGuiElement element the dropdown that you want to add the items to
|
||||
@tparam[opt] number start_index the index at which the items will be added, if not given appened to the end
|
||||
@tparam table new_items the list of new items that you want to add
|
||||
@treturn table the list of items that the element now has
|
||||
@usage-- Add the items 'foo' and 'bar' to the end
|
||||
Gui.add_dropdown_items(element,{'foo','bar'})
|
||||
@usage-- Add the items 'foo' and 'bar' to the start
|
||||
Gui.add_dropdown_items(element,1,{'foo','bar'})
|
||||
]]
|
||||
function Gui.add_dropdown_items(element,start_index,new_items)
|
||||
if not new_items then
|
||||
new_items = start_index
|
||||
start_index = nil
|
||||
end
|
||||
|
||||
local items = element.items
|
||||
element.items = array_insert(items,start_index,new_items)
|
||||
|
||||
return items
|
||||
end
|
||||
@@ -1,51 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- A button that lets the player pick one of an: item, entity, tile, or signal similar to the filter-select window.
|
||||
@element elem_button
|
||||
|
||||
@param on_selection_changed fired when the selected value is changed
|
||||
|
||||
@tparam ?string|Concepts.SignalID|function default the option which is selected by default, or a function which returns the default
|
||||
@tparam string elem_type the type of elem selection that this is, default is item selection
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('elem_button')
|
||||
|
||||
-- Events
|
||||
:new_event('on_selection_changed',defines.events.on_gui_elem_changed)
|
||||
|
||||
-- Properties
|
||||
:new_property('default')
|
||||
:new_property('elem_type',nil,'item')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a chose elem button
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'choose-elem-button',
|
||||
elem_type = properties.elem_type
|
||||
}
|
||||
|
||||
-- If there is a default, select it
|
||||
local default = Gui.resolve_property(properties.default,element)
|
||||
if default then
|
||||
element.elem_value = default
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,36 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- A empty widget that just exists. The root GUI element screen is an empty-widget.
|
||||
@element empty
|
||||
|
||||
@tparam string style the style that the element will have
|
||||
|
||||
@usage-- Making a draggable space styled widget
|
||||
local draggable_space =
|
||||
Gui.new_concept('empty')
|
||||
:set_style('draggable_space')
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('empty')
|
||||
|
||||
-- Properties
|
||||
:new_property('style')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw an empty widget
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'empty-widget',
|
||||
style = properties.style
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,42 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Invisible containers that lay out children either horizontally or vertically. The root GUI elements (top, left and center; see LuaGui) are flows.
|
||||
@element flow
|
||||
|
||||
@tparam string direction the direction that children will be added
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('flow')
|
||||
|
||||
-- Properties
|
||||
:new_property('direction')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a flow
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'flow',
|
||||
caption = properties.title,
|
||||
direction = properties.direction
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,45 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Grey semi-transparent boxes that contain other elements. They have a caption, and, just like flows, they lay out children either horizontally or vertically.
|
||||
@element frame
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString title the title that will show in the frame
|
||||
@tparam string direction the direction that children will be added
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('frame')
|
||||
|
||||
-- Properties
|
||||
:new_property('title')
|
||||
:new_property('direction')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a frame
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'frame',
|
||||
caption = properties.title,
|
||||
direction = properties.direction
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,46 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- A piece of text.
|
||||
@element label
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString caption the caption that will show in the label
|
||||
@tparam ?string|Concepts.LocalisedString description the description that will show on the label
|
||||
@tparam defines.rich_text_setting rich_text how this element handles rich text
|
||||
|
||||
@usage-- Making a basic label
|
||||
local basic_label =
|
||||
Gui.new_concept('label')
|
||||
:set_caption('Hello, World!')
|
||||
|
||||
]]
|
||||
Gui.new_concept()
|
||||
:save_as('label')
|
||||
|
||||
-- Properties
|
||||
:new_property('caption')
|
||||
:new_property('description')
|
||||
:new_property('rich_text')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a label
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'label',
|
||||
caption = properties.caption,
|
||||
description = properties.description
|
||||
}
|
||||
|
||||
-- Change rich text setting if present
|
||||
local rich_text = properties.rich_text
|
||||
if rich_text then
|
||||
element.style.rich_text_setting = rich_text
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
322
expcore/gui/concepts/left.lua
Normal file
322
expcore/gui/concepts/left.lua
Normal file
@@ -0,0 +1,322 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Left Guis.
|
||||
-- Gui structure define for left frames
|
||||
-- @section left
|
||||
|
||||
--[[
|
||||
>>>> Example formating
|
||||
|
||||
-- first we add config that relates to the button on the toolbar, all normal button functions are present
|
||||
local left_frame =
|
||||
Gui.new_left_frame('test-left-frame')
|
||||
:set_caption('Test Left Gui')
|
||||
:set_post_authenticator(function(player,button_name)
|
||||
return global.show_test_gui
|
||||
end)
|
||||
|
||||
-- then we add the config for the left frame, on_draw should draw the gui from an empty frame, on_update should take a frame from on_draw on edit it
|
||||
:set_open_by_default()
|
||||
:on_draw(function(_player,frame)
|
||||
for _,player in pairs(game.connected_players) do
|
||||
frame.add{
|
||||
type='label',
|
||||
caption=player.name
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
-- now we can use the action factory to call events on the gui, actions are: 'update', 'update_all', 'redraw', 'redraw_all'
|
||||
Event.add(defines.events.on_player_joined_game,left_frame 'update_all')
|
||||
Event.add(defines.events.on_player_left_game,left_frame 'update_all')
|
||||
|
||||
>>>> Functions
|
||||
LeftFrames.get_flow(player) --- Gets the left frame flow for a player
|
||||
LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name
|
||||
LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button
|
||||
LeftFrames.toggle_frame(name,player,state) --- Toggles the visibility of a left frame, or sets its visibility state
|
||||
|
||||
LeftFrames.new_frame(permission_name) --- Creates a new left frame define
|
||||
LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean
|
||||
LeftFrames._prototype:set_direction(direction) --- Sets the direction of the frame, either vertical or horizontal
|
||||
LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow
|
||||
LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible
|
||||
LeftFrames._prototype:toggle(player) --- Toggles the visibility of the left frame
|
||||
|
||||
LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw
|
||||
LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update
|
||||
LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame
|
||||
LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw
|
||||
|
||||
LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame
|
||||
LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it
|
||||
LeftFrames._prototype:on_player_toggle(player,frame) --- Is triggered when the player presses the toggle button
|
||||
LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar
|
||||
local Buttons = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
|
||||
local LeftFrames = {
|
||||
frames={},
|
||||
_prototype=Prototype.extend{
|
||||
on_creation = Prototype.event,
|
||||
on_update = Prototype.event,
|
||||
on_player_toggle = Prototype.event
|
||||
}
|
||||
}
|
||||
setmetatable(LeftFrames._prototype, {
|
||||
__index = Buttons._prototype
|
||||
})
|
||||
|
||||
--- Gets the left frame flow for a player
|
||||
-- @tparam LuaPlayer player the player to get the flow of
|
||||
-- @treturn LuaGuiElement the left frame flow for the player
|
||||
function LeftFrames.get_flow(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
return mod_gui.get_frame_flow(player)
|
||||
end
|
||||
|
||||
--- Gets one frame from the left flow by its name
|
||||
-- @tparam string name the name of the gui frame to get
|
||||
-- @tparam LuaPlayer player the player to get the frame of
|
||||
-- @treturn LuaGuiElement the frame in the left frame flow with that name
|
||||
function LeftFrames.get_frame(name,player)
|
||||
local define = LeftFrames.frames[name]
|
||||
if not define then
|
||||
return error('Left Frame '..name..' is not defined.',2)
|
||||
end
|
||||
return define:get_frame(player)
|
||||
end
|
||||
|
||||
--- Gets all open frames for a player, if non are open it will remove the close all button
|
||||
-- @tparam LuaPlayer player the player to get the flow of
|
||||
-- @treturn table contains all the open (and registered) frames for the player
|
||||
function LeftFrames.get_open(player)
|
||||
local open = {}
|
||||
local flow = LeftFrames.get_flow(player)
|
||||
|
||||
for _,define in pairs(LeftFrames.frames) do
|
||||
if define:is_open(player) then
|
||||
table.insert(open,define)
|
||||
end
|
||||
end
|
||||
|
||||
flow[LeftFrames.toggle_button.name].visible = #open ~= 0
|
||||
|
||||
return open
|
||||
end
|
||||
|
||||
--- Toggles the visibility of a left frame, or sets its visibility state
|
||||
-- @tparam string name the name of the gui frame to toggle
|
||||
-- @tparam LuaPlayer player the player to get the frame of
|
||||
-- @tparam[opt] boolean state when given will be the state that the visibility is set to
|
||||
-- @treturn boolean the new state of the visibility
|
||||
function LeftFrames.toggle_frame(name,player,state)
|
||||
local define = LeftFrames.frames[name]
|
||||
if not define then
|
||||
return error('Left Frame '..name..' is not defined.',2)
|
||||
end
|
||||
|
||||
local frame = LeftFrames.get_frame(name,player)
|
||||
if state ~= nil then
|
||||
frame.visible = state
|
||||
else
|
||||
Gui.toggle_visible(frame)
|
||||
end
|
||||
|
||||
LeftFrames.get_open(player)
|
||||
|
||||
return frame.visible
|
||||
end
|
||||
|
||||
--- Creates a new left frame define
|
||||
-- @tparam string permission_name the name that can be used with the permission system
|
||||
-- @treturn table the new left frame define
|
||||
function LeftFrames.new_frame(permission_name)
|
||||
local self = Toolbar.new_button(permission_name)
|
||||
|
||||
local mt = getmetatable(self)
|
||||
mt.__index = LeftFrames._prototype
|
||||
mt.__call = self.event_handler
|
||||
|
||||
self:on_click(function(player,_element)
|
||||
local visible = self:toggle(player)
|
||||
local frame = self:get_frame(player)
|
||||
self:raise_event('on_player_toggle',player,frame,visible)
|
||||
end)
|
||||
|
||||
LeftFrames.frames[self.name] = self
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets if the frame is visible when a player joins, can also be a function to return a boolean
|
||||
-- @tparam[opt=true] ?boolean|function state the default state of the visibility, can be a function
|
||||
-- state param - player LuaPlayer - the player that has joined the game
|
||||
-- state param - define_name string - the define name for the frame
|
||||
-- state return - boolean - false will hide the frame
|
||||
function LeftFrames._prototype:set_open_by_default(state)
|
||||
if state == false then
|
||||
self.open_by_default = false
|
||||
elseif state == nil then
|
||||
self.open_by_default = true
|
||||
else
|
||||
self.open_by_default = state
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the direction of the frame, either vertical or horizontal
|
||||
-- @tparam string direction the direction to have the elements be added to the frame
|
||||
function LeftFrames._prototype:set_direction(direction)
|
||||
self.direction = direction
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates the gui for the first time, used internally
|
||||
-- @tparam LuaPlayer player the player to draw the frame to
|
||||
-- @treturn LuaGuiElement the frame that was made
|
||||
function LeftFrames._prototype:_internal_draw(player)
|
||||
local flow = LeftFrames.get_flow(player)
|
||||
local frame = flow.add{
|
||||
type='frame',
|
||||
name=self.name..'-frame',
|
||||
direction=self.direction
|
||||
}
|
||||
|
||||
self:raise_event('on_creation',player,frame)
|
||||
|
||||
if not self.open_by_default then
|
||||
frame.visible = false
|
||||
elseif type(self.open_by_default) == 'function' then
|
||||
if not self.open_by_default(player,self.name) then
|
||||
frame.visible = false
|
||||
end
|
||||
end
|
||||
|
||||
if not Toolbar.allowed(player,self.name) then
|
||||
frame.visible = false
|
||||
end
|
||||
|
||||
return frame
|
||||
end
|
||||
|
||||
--- Gets the frame for this define from the left frame flow
|
||||
-- @tparam LuaPlayer player the player to get the frame of
|
||||
-- @treturn LuaGuiElement the frame in the left frame flow for this define
|
||||
function LeftFrames._prototype:get_frame(player)
|
||||
local flow = LeftFrames.get_flow(player)
|
||||
if flow[self.name..'-frame'] and flow[self.name..'-frame'].valid then
|
||||
return flow[self.name..'-frame']
|
||||
else
|
||||
return self:_internal_draw(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns if the player currently has this define visible
|
||||
-- @tparam LuaPlayer player the player to get the frame of
|
||||
-- @treturn boolean true if it is open/visible
|
||||
function LeftFrames._prototype:is_open(player)
|
||||
local frame = self:get_frame(player)
|
||||
return frame and frame.visible or false
|
||||
end
|
||||
|
||||
--- Toggles the visibility of the left frame
|
||||
-- @tparam LuaPlayer player the player to toggle the frame of
|
||||
-- @treturn boolean the new state of the visibility
|
||||
function LeftFrames._prototype:toggle(player)
|
||||
local frame = self:get_frame(player)
|
||||
Gui.toggle_visible(frame)
|
||||
LeftFrames.get_open(player)
|
||||
return frame.visible
|
||||
end
|
||||
|
||||
--- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw
|
||||
-- @tparam LuaPlayer player the player to update the frame of
|
||||
function LeftFrames._prototype:update(player)
|
||||
local frame = self:get_frame(player)
|
||||
if self:raise_event('on_update',player,frame) == 0 then
|
||||
frame.clear()
|
||||
self:raise_event('on_creation',player,frame)
|
||||
end
|
||||
end
|
||||
|
||||
--- Updates the frame for all players, see update
|
||||
-- @tparam[opt=false] boolean update_offline when true will update the frame for offline players
|
||||
function LeftFrames._prototype:update_all(update_offline)
|
||||
local players = update_offline == true and game.players or game.connected_players
|
||||
for _,player in pairs(players) do
|
||||
self:update(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Redraws the frame by calling on_draw, will always clear the frame
|
||||
-- @tparam LuaPlayer player the player to update the frame of
|
||||
function LeftFrames._prototype:redraw(player)
|
||||
local frame = self:get_frame(player)
|
||||
frame.clear()
|
||||
self:raise_event('on_creation',player,frame)
|
||||
end
|
||||
|
||||
--- Redraws the frame for all players, see redraw
|
||||
-- @tparam[opt=false] boolean update_offline when true will update the frame for offline players
|
||||
function LeftFrames._prototype:redraw_all(update_offline)
|
||||
local players = update_offline == true and game.players or game.connected_players
|
||||
for _,player in pairs(players) do
|
||||
self:redraw(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates an event handler that will trigger one of its functions, use with Event.add
|
||||
-- @tparam[opt=update] string action the action to take on this event
|
||||
function LeftFrames._prototype:event_handler(action)
|
||||
action = action or 'update'
|
||||
return function(event)
|
||||
local player
|
||||
if event and event.player_index then
|
||||
player = Game.get_player_by_index(event.player_index)
|
||||
end
|
||||
self[action](self,player)
|
||||
end
|
||||
end
|
||||
|
||||
LeftFrames.toggle_button =
|
||||
Buttons.new_button()
|
||||
:set_tooltip{'expcore-gui.left-button-tooltip'}
|
||||
:set_caption('<')
|
||||
:on_click(function(player,element)
|
||||
for _,define in pairs(LeftFrames.frames) do
|
||||
local frame = LeftFrames.get_frame(define.name,player)
|
||||
frame.visible = false
|
||||
define:raise_event('on_player_toggle',player,frame,false)
|
||||
end
|
||||
element.visible = false
|
||||
end)
|
||||
|
||||
Event.add(defines.events.on_player_created,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
local flow = LeftFrames.get_flow(player)
|
||||
|
||||
local close_button = LeftFrames.toggle_button(flow)
|
||||
Gui.set_padding(close_button)
|
||||
local style = close_button.style
|
||||
style.width = 18
|
||||
style.height = 36
|
||||
style.font = 'default-small-bold'
|
||||
|
||||
for _,define in pairs(LeftFrames.frames) do
|
||||
define:_internal_draw(player)
|
||||
end
|
||||
|
||||
LeftFrames.get_open(player)
|
||||
end)
|
||||
|
||||
return LeftFrames
|
||||
@@ -1,35 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- A vertical or horizontal line.
|
||||
@element line
|
||||
|
||||
@tparam string direction the direction that children will be added
|
||||
|
||||
@usage-- Making a basic frame, contains a label with hello world
|
||||
local basic_line =
|
||||
Gui.new_concept('line')
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('line')
|
||||
|
||||
-- Properties
|
||||
:new_property('direction')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a line
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'line',
|
||||
direction = properties.direction
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
230
expcore/gui/concepts/popups.lua
Normal file
230
expcore/gui/concepts/popups.lua
Normal file
@@ -0,0 +1,230 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Popups.
|
||||
-- Gui structure define for popup gui
|
||||
-- @section popups
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames
|
||||
PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
|
||||
|
||||
PopupFrames.close_progress --- Progress bar which when depleted will close the popup frame
|
||||
PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out
|
||||
|
||||
PopupFrames.new_popup(name) --- Creates a new popup frame define
|
||||
PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open
|
||||
PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local ProgressBar = require 'expcore.gui.elements.progress-bar' --- @dep expcore.gui.elements.progress-bar
|
||||
local Button = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
local Color = require 'resources.color_presets' --- @dep resources.color_presets
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
|
||||
local PopupFrames = {
|
||||
paused_popups={},
|
||||
popup_flow_name = Gui.uid_name(),
|
||||
main_frame_name = Gui.uid_name(),
|
||||
close_frame_name = Gui.uid_name(),
|
||||
_prototype = Prototype.extend{
|
||||
on_creation = Prototype.event
|
||||
}
|
||||
}
|
||||
Global.register(PopupFrames.paused_popups,function(tbl)
|
||||
PopupFrames.paused_popups = tbl
|
||||
end)
|
||||
|
||||
--- Sets the state of the element in the paused list, nil or true
|
||||
-- @tparam LuaGuiElement element the element to set the state of
|
||||
-- @tparam[opt] boolean state the state to set it to, true will pause the the progress bar
|
||||
local function set_paused_state(element,state)
|
||||
local name = element.player_index..':'..element.index
|
||||
PopupFrames.paused_popups[name] = state
|
||||
end
|
||||
|
||||
--- Gets the state of the element in the paused list, nil or true
|
||||
-- @tparam LuaGuiElement element the element to get the state of
|
||||
local function get_paused_state(element)
|
||||
local name = element.player_index..':'..element.index
|
||||
return PopupFrames.paused_popups[name]
|
||||
end
|
||||
|
||||
--- Gets the left flow that contains the popup frames
|
||||
-- @tparam LuaPlayer player the player to get the flow for
|
||||
-- @treturn LuaGuiElement the left flow that contains the popup frames
|
||||
function PopupFrames.get_flow(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
local flow = mod_gui.get_frame_flow(player)
|
||||
return flow[PopupFrames.popup_flow_name]
|
||||
end
|
||||
|
||||
--- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
|
||||
-- @tparam string define_name the name of the define that you want to open for the player
|
||||
-- @tparam LuaPlayer player the player to open the popup for
|
||||
-- @tparam[opt] number open_time the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default
|
||||
-- @tparam any ... the other params that you want to pass to your on_draw event
|
||||
-- @treturn LuaGuiElement the frame that was drawn, the inner gui flow which contains the content
|
||||
function PopupFrames.open(define_name,player,open_time,...)
|
||||
local define = Gui.get_define(define_name,true)
|
||||
player = Game.get_player_from_any(player)
|
||||
return define:open(player,open_time,...)
|
||||
end
|
||||
|
||||
--- Closes the popup, is called by progress bar and close button
|
||||
-- @tparam LuaGuiElement element either the progress bar or the close button
|
||||
local function close_popup(element)
|
||||
local frame = element.parent.parent.parent
|
||||
if not frame or not frame.valid then return end
|
||||
set_paused_state(element.parent[PopupFrames.close_progress:uid()])
|
||||
frame.destroy()
|
||||
end
|
||||
|
||||
--- Progress bar which when depleted will close the popup frame
|
||||
PopupFrames.close_progress =
|
||||
ProgressBar.new_progressbar()
|
||||
:use_count_down()
|
||||
:set_tooltip('Pause/Resume Auto-close')
|
||||
:on_complete(function(player,element)
|
||||
close_popup(element)
|
||||
end)
|
||||
|
||||
--- A button which can be used to close the gui before the timer runs out
|
||||
PopupFrames.close_button =
|
||||
Button.new_button()
|
||||
:set_sprites('utility/close_white')
|
||||
:set_tooltip('Close Popup')
|
||||
:on_click(function(player,element)
|
||||
close_popup(element)
|
||||
end)
|
||||
|
||||
--- When the progress bar is clicked it will pause its progress, or resume if previously paused
|
||||
Gui.on_click(PopupFrames.close_progress:uid(),function(event)
|
||||
local element = event.element
|
||||
if get_paused_state(element) then
|
||||
set_paused_state(element)
|
||||
else
|
||||
set_paused_state(element,true)
|
||||
end
|
||||
end)
|
||||
|
||||
--- When the parent flow of the progress bar is clicked it will pause its progress, or resume if previously paused
|
||||
Gui.on_click(PopupFrames.close_frame_name,function(event)
|
||||
local element = event.element[PopupFrames.close_progress:uid()]
|
||||
if get_paused_state(element) then
|
||||
set_paused_state(element)
|
||||
else
|
||||
set_paused_state(element,true)
|
||||
end
|
||||
end)
|
||||
|
||||
--- Creates a new popup frame define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new popup frame define
|
||||
function PopupFrames.new_popup(name)
|
||||
local self = Gui.new_define(PopupFrames._prototype,name)
|
||||
self.draw_data.type = 'flow'
|
||||
self.draw_data.direction = 'vertical'
|
||||
|
||||
local mt = getmetatable(self)
|
||||
mt.__call = function(tbl,player,open_time,...)
|
||||
return tbl:open(player,open_time,...)
|
||||
end
|
||||
|
||||
self:on_draw(function(player,element,maximum,...)
|
||||
-- main content frame
|
||||
local frame = element.add{
|
||||
type='flow',
|
||||
name=PopupFrames.main_frame_name
|
||||
}
|
||||
frame.style.horizontally_stretchable = true
|
||||
|
||||
-- flow for progress bar and close button
|
||||
local close_flow = element.add{
|
||||
type='flow',
|
||||
name=PopupFrames.close_frame_name
|
||||
}
|
||||
close_flow.style.horizontally_stretchable = true
|
||||
|
||||
-- progress bar, when 0 then a static full one is drawn
|
||||
local progress_style
|
||||
if maximum == 0 then
|
||||
progress_style = close_flow.add{
|
||||
type='progressbar',
|
||||
tooltip='No Auto-close',
|
||||
value=1
|
||||
}.style
|
||||
else
|
||||
progress_style = PopupFrames.close_progress(close_flow,maximum).style
|
||||
end
|
||||
progress_style.top_padding = 6
|
||||
progress_style.bottom_padding = 3
|
||||
progress_style.height = 11
|
||||
progress_style.color = Color.grey
|
||||
|
||||
-- close button, will close the popup when clicked
|
||||
local close_button = PopupFrames.close_button(close_flow)
|
||||
Gui.set_padding(close_button)
|
||||
local close_button_style = close_button.style
|
||||
close_button_style.width = 20
|
||||
close_button_style.height = 20
|
||||
|
||||
-- event trigger to draw the gui content
|
||||
self:raise_event('on_creation',player,frame,...)
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the default open time for the popup, will be used if non is provided with open
|
||||
-- @tparam number amount the number of ticks, by default, the popup will be open for
|
||||
-- @treturn table the define to allow for chaining
|
||||
function PopupFrames._prototype:set_default_open_time(amount)
|
||||
self.default_open_time = amount
|
||||
return self
|
||||
end
|
||||
|
||||
--- Opens this define for a player, can be given open time and any other params for the draw function
|
||||
-- @tparam LuaPlayer player the player to open the popup for
|
||||
-- @tparam[opt] number open_time the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default
|
||||
-- @tparam any ... the other params that you want to pass to your on_draw event
|
||||
-- @treturn LuaGuiElement the frame that was drawn, the inner gui flow which contains the content
|
||||
function PopupFrames._prototype:open(player,open_time,...)
|
||||
open_time = open_time or self.default_open_time or 0
|
||||
player = Game.get_player_from_any(player)
|
||||
|
||||
local flow = PopupFrames.get_flow(player)
|
||||
local frame = flow.add{
|
||||
type='frame',
|
||||
style='blurry_frame'
|
||||
}
|
||||
|
||||
Gui.set_padding(frame,3,3,4,4)
|
||||
return self:draw_to(frame,open_time,...)[PopupFrames.main_frame_name]
|
||||
end
|
||||
|
||||
--- When player is first created the popup flow is added to they left flow
|
||||
Event.add(defines.events.on_player_created,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
local flow = mod_gui.get_frame_flow(player)
|
||||
|
||||
flow.add{
|
||||
type='flow',
|
||||
direction='vertical',
|
||||
name=PopupFrames.popup_flow_name
|
||||
}
|
||||
end)
|
||||
|
||||
--- Every tick any, not paused, progress bars will go down by one tick
|
||||
Event.add(defines.events.on_tick,PopupFrames.close_progress:event_countdown(function(element)
|
||||
return not get_paused_state(element)
|
||||
end))
|
||||
|
||||
return PopupFrames
|
||||
@@ -1,168 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Indicate progress by displaying a partially filled bar.
|
||||
@element progress_bar
|
||||
|
||||
@param on_completion fired when increment reaches the maxium value set by set_maximum
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString tooltip the tooltip that will show for this element
|
||||
@tparam number maximum the maxium amount an instance can be increased, default 100
|
||||
@tparam boolean delay_completion when true the progress will be completed untill after the maximum rather than at the maximum
|
||||
@tparam boolean inverted although this will NOT effect how you use the functions it will make the element start full and reduce as you call increase, note issues with 0 detections
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
local progress_bar =
|
||||
Gui.new_concept()
|
||||
:save_as('progress_bar')
|
||||
|
||||
-- Events
|
||||
:new_event('on_completion')
|
||||
|
||||
-- Properties
|
||||
:new_property('tooltip')
|
||||
:new_property('maximum',nil,100)
|
||||
:new_property('delay_completion',nil,false)
|
||||
:new_property('inverted',nil,false)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a progress bar
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
tooltip = properties.tooltip,
|
||||
type = 'progressbar',
|
||||
value = properties.inverted and 1 or 0
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
|
||||
--- Progress Bars.
|
||||
-- functions used with progress bars
|
||||
-- @section progress_bars
|
||||
|
||||
-- logic for changing the value of a progress bar
|
||||
local function raw_update(concept,element,amount)
|
||||
local old_value = element.value
|
||||
local new_value = old_value + amount
|
||||
element.value = new_value
|
||||
|
||||
local check_value = concept.properties.delay_completion and old_value or new_value
|
||||
if amount < 0 and check_value <= 0 or amount > 0 and check_value >= 1 then
|
||||
concept:raise_event('on_completion',{
|
||||
element = element
|
||||
})
|
||||
else
|
||||
return new_value
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[-- 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
|
||||
@tparam ?LuaGuiElement|string element either the element that is changed or the category that is being changed (only if an instance store is defined)
|
||||
@tparam[opt=1] number amount the amount that will bar will increase, note that this amount must be less than the max
|
||||
@treturn ?number|nil the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed
|
||||
@usage-- Incrementing progress bar with no instance store
|
||||
local new_value = progress_bar:increment(element)
|
||||
@usage-- Incrementing progress bar with an instance store
|
||||
progress_bar:increment(category)
|
||||
]]
|
||||
function progress_bar:increment(element,amount)
|
||||
local properties = self.properties
|
||||
local inverted = properties.inverted
|
||||
local maximum = properties.maximum
|
||||
amount = amount and amount/maximum or 1/maximum
|
||||
amount = inverted and -amount or amount
|
||||
|
||||
if self.instance_store and not self.sync_instance then
|
||||
self.update_instances(element,function(next_element)
|
||||
raw_update(self,next_element,amount)
|
||||
end)
|
||||
|
||||
else
|
||||
return raw_update(self,element,amount)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- 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
|
||||
@tparam ?LuaGuiElement|string element either the element that is changed or the category that is being changed (only if an instance store is defined)
|
||||
@tparam[opt=1] number amount the amount that will bar will decrease, note that this amount must be less than the max
|
||||
@treturn number the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed
|
||||
@usage-- Decrementing progress bar with no instance store
|
||||
local new_value = progress_bar:decrement(element)
|
||||
@usage-- Decrementing progress bar with an instance store
|
||||
progress_bar:decrement(category)
|
||||
]]
|
||||
function progress_bar:decrement(element,amount)
|
||||
self:increment(element,-amount)
|
||||
end
|
||||
|
||||
--[[-- 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
|
||||
@tparam ?LuaGuiElement|string element either the element that is changed or the category that is being changed (only if an instance store is defined)
|
||||
@treturn ?number|nil the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed
|
||||
@usage-- Reseting a progress bar with no instance store
|
||||
local new_value = progress_bar:reset(element)
|
||||
@usage-- Reseting a progress bar with an instance store
|
||||
progress_bar:reset(category)
|
||||
]]
|
||||
function progress_bar:reset(element)
|
||||
local new_value = self.properties.inverted and 1 or 0
|
||||
if self.instacne_store and not self.sync_instance then
|
||||
self.update_instances(element,function(next_element)
|
||||
next_element.value = new_value
|
||||
end)
|
||||
|
||||
else
|
||||
element.value = new_value
|
||||
return new_value
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Increment any progress bar by the given percentage
|
||||
@tparam LuaGuiElement element the progress bar that you want to update
|
||||
@tparam[opt=0.01] number amount the percentage that you want to increment the progress bar by
|
||||
@treturn boolean true if the bar is now full
|
||||
@usage-- Increment any progress bar by 10%
|
||||
Gui.increment_progress_bar(element,0.1)
|
||||
]]
|
||||
function Gui.increment_progress_bar(element,amount)
|
||||
amount = amount or 0.01
|
||||
element.value = element.value + amount
|
||||
return element.value >= 1
|
||||
end
|
||||
|
||||
--[[-- Decrement any progress bar by the given percentage
|
||||
@tparam LuaGuiElement element the progress bar that you want to update
|
||||
@tparam[opt=0.01] number amount the percentage that you want to decrement the progress bar by
|
||||
@treturn boolean true if the bar is now empty
|
||||
@usage-- Decrement any progress bar by 10%
|
||||
Gui.decrement_progress_bar(element,0.1)
|
||||
]]
|
||||
function Gui.decrement_progress_bar(element,amount)
|
||||
amount = amount or 0.01
|
||||
element.value = element.value - amount
|
||||
return element.value <= 0
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Similar to a flow but includes the ability to show and use scroll bars.
|
||||
@element scroll
|
||||
|
||||
@tparam string horizontal_scroll the horizontal scroll policy for this scroll pane
|
||||
@tparam string vertical_scroll the vertical scroll policy for this scroll pane
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('scroll')
|
||||
|
||||
-- Properties
|
||||
:new_property('horizontal_scroll')
|
||||
:new_property('vertical_scroll')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Draw a scroll pane
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'scroll-pane',
|
||||
horizontal_scroll_policy = properties.horizontal_scroll,
|
||||
vertical_scroll_policy = properties.vertical_scroll
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,91 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- A number picker.
|
||||
@element slider
|
||||
|
||||
@param on_value_changed fired when the value of the slider is changed
|
||||
|
||||
@tparam number value_step the minimum amount by which the value of the slider can be changed
|
||||
@tparam ?number|function default the default value of the slider or a function which returns the default value
|
||||
@tparam boolean discrete_slider makes this slider a discrete slider, this means that the slider button will stop at the same interval as the values do
|
||||
@tparam ?number|function range accepts two params the minimum and the maximum for this slider, or a single function to return both
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('slider')
|
||||
|
||||
-- Events
|
||||
:new_event('on_value_changed',defines.events.on_gui_value_changed)
|
||||
|
||||
-- Properties
|
||||
:new_property('value_step')
|
||||
:new_property('default')
|
||||
:new_property('discrete_slider',nil,false)
|
||||
:new_property('range',function(properties,minimum,maximum)
|
||||
if type(minimum) == 'function' then
|
||||
properties.range = minimum
|
||||
else
|
||||
properties.minimum = minimum
|
||||
properties.maximum = maximum
|
||||
end
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
local default = properties.default
|
||||
local value = type(default) == 'number' and default
|
||||
local value_step = properties.value_step
|
||||
|
||||
-- Draw a slider
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'slider',
|
||||
caption = properties.caption,
|
||||
minimum_value = properties.minimum,
|
||||
maximum_value = properties.maximum,
|
||||
discrete_slider = properties.discrete_slider,
|
||||
discrete_values = value_step ~= nil,
|
||||
value_step = value_step,
|
||||
value = value
|
||||
}
|
||||
|
||||
-- Find the range for the slider and set it
|
||||
local min, max = Gui.resolve_property(properties.range,element)
|
||||
if min or max then
|
||||
min = min or element.get_slider_minimum()
|
||||
max = max or element.get_slider_maximum()
|
||||
element.set_slider_minimum_maximum(min,max)
|
||||
end
|
||||
|
||||
-- If there is a default, select it
|
||||
default = Gui.resolve_property(default,element)
|
||||
if default and default ~= value then
|
||||
element.slider_value = default
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,58 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- 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.
|
||||
@element table
|
||||
|
||||
@tparam ?number|function column_count the column count of the table or a function that returns the count being given then parent element
|
||||
@tparam boolean vertical_lines when true vertical lines will be drawn on the table
|
||||
@tparam boolean horizontal_lines when true horizontal lines will be drawn on the table
|
||||
@tparam boolean header_lines when true horizontal lines will be drawn under the first row
|
||||
@tparam boolean vertical_centering when true element will be vertically centered with in the table
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('table')
|
||||
|
||||
-- Properties
|
||||
:new_property('column_count')
|
||||
:new_property('vertical_lines')
|
||||
:new_property('horizontal_lines')
|
||||
:new_property('header_lines')
|
||||
:new_property('vertical_centering')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
local column_count = Gui.resolve_property(properties.column_count,parent)
|
||||
|
||||
-- Draw a table
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'table',
|
||||
column_count = column_count,
|
||||
draw_vertical_lines = properties.vertical_lines,
|
||||
draw_horizontal_lines = properties.horizontal_lines,
|
||||
draw_horizontal_line_after_headers = properties.header_lines,
|
||||
vertical_centering = properties.vertical_centering
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,84 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- A multi-line text box that supports selection and copy-paste.
|
||||
@element text_box
|
||||
|
||||
@param on_text_changed fired when the text within the text box is changed
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the text box
|
||||
@tparam ?string|function default the default text that will appear in the text box, or a function that returns it
|
||||
@tparam defines.rich_text_setting rich_text how this element handles rich text
|
||||
@tparam boolean clear_on_rmb if the text box will be cleared and forcused on a right click
|
||||
@tparam boolean is_selectable when true the text inside the box can be selected
|
||||
@tparam boolean has_word_wrap when true the text will wrap onto the next line if it reachs the end
|
||||
@tparam boolean is_read_only when true the text inside the box can not be edited by the player
|
||||
|
||||
@usage-- 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')
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('text_box')
|
||||
|
||||
-- Events
|
||||
:new_event('on_text_changed',defines.events.on_gui_text_changed)
|
||||
|
||||
-- Properties
|
||||
:new_property('tooltip')
|
||||
:new_property('default')
|
||||
:new_property('rich_text')
|
||||
:new_property('clear_on_rmb',nil,false)
|
||||
:new_property('is_selectable',nil,true)
|
||||
:new_property('has_word_wrap',nil,true)
|
||||
:new_property('is_read_only',nil,true)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
local default = properties.default
|
||||
local text = type(default) == 'string' and default or nil
|
||||
|
||||
-- Draw a text box
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'text-box',
|
||||
tooltip = properties.tooltip,
|
||||
clear_and_focus_on_right_click = properties.clear_on_rmb,
|
||||
text = text
|
||||
}
|
||||
|
||||
-- Set options for text box
|
||||
element.selectable = properties.is_selectable
|
||||
element.word_wrap = properties.has_word_wrap
|
||||
element.read_only = properties.is_read_only
|
||||
|
||||
-- If there is a default, set it
|
||||
default = Gui.resolve_property(default,element)
|
||||
if default and default ~= text then
|
||||
element.text = default
|
||||
end
|
||||
|
||||
-- Change rich text setting if present
|
||||
local rich_text = properties.rich_text
|
||||
if rich_text then
|
||||
element.style.rich_text_setting = rich_text
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,100 +0,0 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.core'
|
||||
|
||||
--[[-- Boxes of text the user can type in.
|
||||
@element text_field
|
||||
|
||||
@param on_text_changed fired when the text within the text field is changed
|
||||
@param on_confirmation fired when the player presses enter with the text field forcused
|
||||
|
||||
@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the text field
|
||||
@tparam ?string|function default the default text that will appear in the text field, or a function that returns it
|
||||
@tparam defines.rich_text_setting rich_text how this element handles rich text
|
||||
@tparam boolean clear_on_rmb if the text field will be cleared and forcused on a right click
|
||||
@tparam boolean lose_forcus if the text field will lose forcus after the confirmation event
|
||||
@tparam boolean is_number if this text field contains a number value, can be ignored if is_decimal or is_negitive is used
|
||||
@tparam boolean is_decimal if this text field contains a decimal value
|
||||
@tparam boolean is_negative if this text field contains a negative value
|
||||
@tparam boolean is_password if this text field contains a password value
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
@usage-- 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)
|
||||
|
||||
]]
|
||||
|
||||
Gui.new_concept()
|
||||
:save_as('text_field')
|
||||
|
||||
-- Events
|
||||
:new_event('on_text_changed',defines.events.on_gui_text_changed)
|
||||
:new_event('on_confirmation',defines.events.on_gui_confirmed)
|
||||
|
||||
-- Properties
|
||||
:new_property('tooltip')
|
||||
:new_property('default')
|
||||
:new_property('rich_text')
|
||||
:new_property('clear_on_rmb',nil,false)
|
||||
:new_property('lose_forcus',nil,false)
|
||||
:new_property('is_number',nil,false)
|
||||
:new_property('is_decimal',nil,false)
|
||||
:new_property('is_negative',nil,false)
|
||||
:new_property('is_password',nil,false)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
local default = properties.default
|
||||
local text = type(default) == 'string' and default or nil
|
||||
|
||||
-- Draw a text field
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'textfield',
|
||||
tooltip = properties.tooltip,
|
||||
clear_and_focus_on_right_click = properties.clear_on_rmb,
|
||||
lose_focus_on_confirm = properties.lose_forcus,
|
||||
numeric = properties.is_number or properties.is_decimal or properties.is_negative,
|
||||
allow_decimal = properties.is_decimal,
|
||||
allow_negative = properties.is_negative,
|
||||
is_password = properties.is_password,
|
||||
text = text
|
||||
}
|
||||
|
||||
-- If there is a default, set it
|
||||
default = Gui.resolve_property(default,element)
|
||||
if default and default ~= text then
|
||||
element.text = default
|
||||
end
|
||||
|
||||
-- Change rich text setting if present
|
||||
local rich_text = properties.rich_text
|
||||
if rich_text then
|
||||
element.style.rich_text_setting = rich_text
|
||||
end
|
||||
|
||||
return element
|
||||
end)
|
||||
114
expcore/gui/concepts/toolbar.lua
Normal file
114
expcore/gui/concepts/toolbar.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Toolbar.
|
||||
-- Gui structure for the toolbar (top left)
|
||||
-- @section toolbar
|
||||
|
||||
--[[
|
||||
>>>> Example format
|
||||
-- this is the same as any other button define, this just automatically draws it
|
||||
-- you can use add_button if you already defined the button
|
||||
local toolbar_button =
|
||||
Toolbar.new_button('print-click')
|
||||
:on_click(function(player,_element)
|
||||
player.print('You clicked a button!')
|
||||
end)
|
||||
|
||||
>>>> Functions
|
||||
Toolbar.new_button(name) --- Adds a new button to the toolbar
|
||||
Toolbar.add_button(button) --- Adds an existing buttton to the toolbar
|
||||
Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Buttons = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons
|
||||
local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
|
||||
local Toolbar = {
|
||||
permission_names = {},
|
||||
buttons = {}
|
||||
}
|
||||
|
||||
function Toolbar.allowed(player,define_name)
|
||||
local permission_name = Toolbar.permission_names[define_name] or define_name
|
||||
return Roles.player_allowed(player,permission_name)
|
||||
end
|
||||
|
||||
function Toolbar.permission_alias(define_name,permission_name)
|
||||
Toolbar.permission_names[define_name] = permission_name
|
||||
end
|
||||
|
||||
--- Adds a new button to the toolbar
|
||||
-- @tparam[opt] string name when given allows an alias to the button for the permission system
|
||||
-- @treturn table the button define
|
||||
function Toolbar.new_button(name)
|
||||
local button =
|
||||
Buttons.new_button()
|
||||
:set_post_authenticator(Toolbar.allowed)
|
||||
:set_style(mod_gui.button_style,function(style)
|
||||
Gui.set_padding_style(style,-2,-2,-2,-2)
|
||||
end)
|
||||
Toolbar.add_button(button)
|
||||
Toolbar.permission_alias(button.name,name)
|
||||
return button
|
||||
end
|
||||
|
||||
--- Adds an existing buttton to the toolbar
|
||||
-- @tparam table button the button define for the button to be added
|
||||
function Toolbar.add_button(button)
|
||||
table.insert(Toolbar.buttons,button)
|
||||
Gui.allow_player_to_toggle_top_element_visibility(button.name)
|
||||
Gui.on_player_show_top(button.name,function(event)
|
||||
if not button.post_authenticator(event.player,button.name) then
|
||||
event.element.visible = false
|
||||
end
|
||||
end)
|
||||
if not button.post_authenticator then
|
||||
button:set_post_authenticator(function() return true end)
|
||||
end
|
||||
end
|
||||
|
||||
--- Updates the player's toolbar with an new buttons or expected change in auth return
|
||||
-- @tparam LuaPlayer player the player to update the toolbar for
|
||||
function Toolbar.update(player)
|
||||
local top = Gui.get_top_element_flow(player)
|
||||
if not top then return end
|
||||
local visible = top[Gui.top_toggle_button_name].caption == '<'
|
||||
for _,button in pairs(Toolbar.buttons) do
|
||||
local element
|
||||
if top[button.name] then element = top[button.name]
|
||||
else element = button:draw_to(top) end
|
||||
if button.post_authenticator(player,button.name) then
|
||||
element.visible = visible
|
||||
element.enabled = true
|
||||
else
|
||||
element.visible = false
|
||||
element.enabled = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- When there is a new player they will have the toolbar update
|
||||
Event.add(defines.events.on_player_created,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
Toolbar.update(player)
|
||||
end)
|
||||
|
||||
--- When a player gets a new role they will have the toolbar updated
|
||||
Event.add(Roles.events.on_role_assigned,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
Toolbar.update(player)
|
||||
end)
|
||||
|
||||
--- When a player loses a role they will have the toolbar updated
|
||||
Event.add(Roles.events.on_role_unassigned,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
Toolbar.update(player)
|
||||
end)
|
||||
|
||||
return Toolbar
|
||||
@@ -1,293 +1,368 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
local Game = require 'utils.game' -- @dep utils.game
|
||||
local resolve_value = ext_require('expcore.common','resolve_value') -- @dep expcore.common
|
||||
local Prototype = require 'expcore.gui.prototype'
|
||||
--- Core.
|
||||
-- Core gui file for making element defines and element classes (use require 'expcore.gui')
|
||||
-- see utils.gui for event handlering
|
||||
-- see expcore.gui.test for examples for element defines
|
||||
-- @section core
|
||||
|
||||
local Gui = {
|
||||
concepts = {}
|
||||
}
|
||||
--[[
|
||||
>>>> Basic useage with no defines
|
||||
This module can be igroned if you are only wanting only event handlers as utils.gui adds the following:
|
||||
|
||||
--- Concept Control.
|
||||
-- Functions that act as a landing point for the other funtions
|
||||
-- @section concept-control
|
||||
Gui.uid_name() --- Generates a unqiue name to register events to
|
||||
Gui.on_checked_state_changed(callback) --- Register a handler for the on_gui_checked_state_changed event
|
||||
Gui.on_click(callback) --- Register a handler for the on_gui_click event
|
||||
Gui.on_elem_changed(callback) --- Register a handler for the on_gui_elem_changed
|
||||
Gui.on_selection_state_changed(callback) --- Register a handler for the on_gui_selection_state_changed event
|
||||
Gui.on_text_changed(callback) --- Register a handler for the on_gui_text_changed event
|
||||
Gui.on_value_changed(callback) --- Register a handler for the on_gui_value_changed event
|
||||
|
||||
--[[-- Loads a concept from the concepts file
|
||||
@tparam string concept_name the name of the concept to require
|
||||
@usage-- Load a base concept
|
||||
Gui.require_concept('frame') --- @dep Gui.concept.frame
|
||||
Note that all event handlers will include event.player as a valid player and that if the player or the
|
||||
element is not valid then the callback will not be run.
|
||||
|
||||
>>>> Basic prototype functions (see expcore.gui.prototype)
|
||||
Using a class defination you can create a new element dinfation in our examples we will be using the checkbox.
|
||||
|
||||
local checkbox_example = Gui.new_checkbox()
|
||||
|
||||
Although all class definations are stored in Gui.classes the main function used to make new element defination are
|
||||
made aviable in the top level gui module. All functions which return a new element defination will accept a name argument
|
||||
which is a name which is used while debuging and is not required to be used (has not been used in examples)
|
||||
|
||||
Every element define will accept a caption and tooltip (although some may not show) and to do this you would use the two
|
||||
set function provided for the element defines:
|
||||
|
||||
checkbox_example:set_caption('Example Checkbox')
|
||||
checkbox_example:set_tooltip('Example checkbox')
|
||||
|
||||
Each element define can have event handlers set, for our example checkbox we only have access to on_change which will trigger
|
||||
when the state of the checkbox changes; if we want to assign handlers using the utils.gui methods then we can get the uid by calling
|
||||
the uid function on the element define; however, each element can only have one handler (of each event) so it is not possible to use
|
||||
Gui.on_checked_state_changed and on_change at the same time in our example.
|
||||
|
||||
checkbox_example:on_change(function(player,element,value)
|
||||
player.print('Example checkbox is now: '..tostring(value))
|
||||
end)
|
||||
|
||||
local checkbox_example_uid = checkbox_example:uid()
|
||||
Gui.on_click(checkbox_example_uid,function(event)
|
||||
event.player.print('You clicked the example checkbox!')
|
||||
end)
|
||||
|
||||
Finally you will want to draw your element defines for which you can call deirectly on the deinfe or use Gui.draw to do; when Gui.draw is
|
||||
used it can be given either the element define, the define's uid or the debug name of the define (if set):
|
||||
|
||||
checkbox_example:draw_to(parent_element)
|
||||
Gui.draw(checkbox_example_uid,parent_element)
|
||||
|
||||
>>>> Using authenticators with draw
|
||||
When an element is drawn to its parent it can always be used but if you want to limit who can use it then you can use an authenticator. There
|
||||
are two types which can be used: post and pre; using a pre authenticator will mean that the draw function is stoped before the element is added
|
||||
to the parent element while using a post authenticator will draw the element to the parent but will disable the element from interaction. Both may
|
||||
be used if you have use for such.
|
||||
|
||||
-- unless global.checkbox_example_allow_pre_auth is true then the checkbox will not be drawn
|
||||
checkbox_example:set_pre_authenticator(function(player,define_name)
|
||||
player.print('Example checkbox pre auth callback ran')
|
||||
return global.checkbox_example_allow_pre_auth
|
||||
end)
|
||||
|
||||
-- unless global.checkbox_example_allow_post_auth is true then the checkbox will be drawn but deactiveated (provided pre auth returns true)
|
||||
checkbox_example:set_post_authenticator(function(player,define_name)
|
||||
player.print('Example checkbox pre auth callback ran')
|
||||
return global.checkbox_example_allow_post_auth
|
||||
end)
|
||||
|
||||
>>>> Using store (see expcore.gui.prototype and expcore.gui.instances)
|
||||
A powerful assept of this gui system is allowing an automatic store for the state of a gui element, this means that when a gui is closed and re-opened
|
||||
the elements which have a store will retain they value even if the element was previously destroied. The store is not limited to only per player and can
|
||||
be catergorised by any method you want such as one that is shared between all players or by all players on a force. Using a method that is not limited to
|
||||
one player means that when one player changes the state of the element it will be automaticlly updated for all other player (even if the element is already drawn)
|
||||
and so this is a powerful and easy way to sync gui elements.
|
||||
|
||||
-- note the example below is the same as checkbox_example:add_store(Gui.categorize_by_player)
|
||||
checkbox_example:add_store(function(element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
return player.force.name
|
||||
end)
|
||||
|
||||
Of course this tool is not limited to only player interactions; the current satate of a define can be gotten using a number of methods and the value can
|
||||
even be updated by the script and have all instances of the element define be updated. When you use a category then we must give a category to the get
|
||||
and set functions; in our case we used Gui.categorize_by_player which uses the player's name as the category which is why 'Cooldude2606' is given as a argument,
|
||||
if we did not set a function for add_store then all instances for all players have the same value and so a category is not required.
|
||||
|
||||
checkbox_example:get_store('Cooldude2606')
|
||||
Gui.get_store(name,'Cooldude2606')
|
||||
|
||||
checkbox_example:set_store('Cooldude2606',true)
|
||||
Gui.set_store(name,'Cooldude2606',true)
|
||||
|
||||
These methods use the Store module which means that if you have the need to access these sotre location (for example if you want to add a watch function) then
|
||||
you can get the store location of any define using checkbox_example.store
|
||||
|
||||
Important note about event handlers: when the store is updated it will also trigger the event handlers (such as on_element_update) for that define but only
|
||||
for the valid instances of the define which means if a player does not have the element drawn on a gui then it will not trigger the events; if you want a
|
||||
trigger for all updates then you can use on_store_update however you will be required to parse the category which may or may not be a
|
||||
player name (depends what store categorize function you use)
|
||||
|
||||
>>>> Example formating
|
||||
|
||||
local checkbox_example =
|
||||
Gui.new_checkbox()
|
||||
:set_caption('Example Checkbox')
|
||||
:set_tooltip('Example checkbox')
|
||||
:add_store(Gui.categorize_by_player)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Example checkbox is now: '..tostring(value))
|
||||
end)
|
||||
|
||||
>>>> Functions
|
||||
Gui.new_define(prototype) --- Used internally to create new element defines from a class prototype
|
||||
Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to
|
||||
|
||||
Gui.categorize_by_player(element) --- A categorize function to be used with add_store, each player has their own value
|
||||
Gui.categorize_by_force(element) --- A categorize function to be used with add_store, each force has its own value
|
||||
Gui.categorize_by_surface(element) --- A categorize function to be used with add_store, each surface has its own value
|
||||
|
||||
Gui.toggle_enabled(element) --- Will toggle the enabled state of an element
|
||||
Gui.toggle_visible(element) --- Will toggle the visiblity of an element
|
||||
Gui.set_padding(element,up,down,left,right) --- Sets the padding for a gui element
|
||||
Gui.set_padding_style(style,up,down,left,right) --- Sets the padding for a gui style
|
||||
Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into
|
||||
Gui.destroy_if_valid(element) --- Destroies an element but tests for it being present and valid first
|
||||
Gui.create_scroll_table(element,table_size,maximal_height,name) --- Creates a scroll area with a table inside, table can be any size
|
||||
Gui.create_header(element,caption,tooltip,right_align,name) --- Creates a header section with a label and button area
|
||||
]]
|
||||
function Gui.require_concept(concept_name)
|
||||
require('expcore.gui.concepts.'..concept_name)
|
||||
end
|
||||
local Gui = require 'utils.gui' --- @dep utils.gui
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
--[[-- Loads a set of concepts from the styles file
|
||||
@tparam string style_name the name of the style to require
|
||||
@usage-- Load a base style
|
||||
Gui.require_concept('expgaming') --- @dep Gui.style.frame
|
||||
]]
|
||||
function Gui.require_style(style_name)
|
||||
require('expcore.gui.styles.'..style_name..'.index')
|
||||
end
|
||||
Gui.classes = {} -- Stores the class definations used to create element defines
|
||||
Gui.defines = {} -- Stores the indivdual element definations
|
||||
Gui.names = {} -- Stores debug names to link to gui uids
|
||||
|
||||
--[[-- Gets a gui concept from name, id, or its self
|
||||
@tparam ?string|number|table name the name, id, or the concept you want to get
|
||||
@usage-- Getting a gui concept
|
||||
local button = Gui.get_concept('Button')
|
||||
]]
|
||||
function Gui.get_concept(name)
|
||||
if not name then return end
|
||||
local vtype = type(name)
|
||||
|
||||
if vtype == 'string' then
|
||||
return Gui.concepts[name]
|
||||
|
||||
elseif vtype == 'table' then
|
||||
if name.draw_callbacks then
|
||||
return name
|
||||
--- Used to create new element defines from a class prototype, please use the own given by the class
|
||||
-- @tparam table prototype the class prototype that will be used for the element define
|
||||
-- @tparam[opt] string debug_name the name that you want to see while debuging
|
||||
-- @treturn table the new element define with all functions accessed via __index metamethod
|
||||
function Gui.new_define(prototype,debug_name)
|
||||
local name = Gui.uid_name()
|
||||
local define = setmetatable({
|
||||
debug_name = debug_name,
|
||||
name = name,
|
||||
events = {},
|
||||
draw_data = {
|
||||
name = name
|
||||
}
|
||||
},{
|
||||
__index = prototype,
|
||||
__call = function(self,...)
|
||||
return self:draw_to(...)
|
||||
end
|
||||
|
||||
elseif vtype == 'number' then
|
||||
for _,concept in pairs(Gui.concepts) do
|
||||
if concept.name == name then
|
||||
return concept
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
})
|
||||
Gui.defines[define.name] = define
|
||||
return define
|
||||
end
|
||||
|
||||
--[[-- Used to save the concept to the main gui module to allow access from other files
|
||||
@function Prototype:save_as
|
||||
@tparam string save_name the new name of the concept
|
||||
@usage-- Save a concept to allow access in another file
|
||||
button:save_as('button')
|
||||
@usage-- Access concept after being saved
|
||||
Gui.concepts.button
|
||||
Gui.get_concept('button')
|
||||
]]
|
||||
function Prototype:save_as(save_name)
|
||||
Gui.concepts[save_name] = self
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Returns a new gui concept, option to provide a base concept to copy properties and draw functions from
|
||||
@tparam[opt] ?string|number|table base_concept the concept that you want to copy the details of
|
||||
@usage-- Making a new button, see module usage
|
||||
local button = Gui.new_concept('Button')
|
||||
]]
|
||||
function Gui.new_concept(base_concept)
|
||||
if base_concept then
|
||||
base_concept = Gui.get_concept(base_concept) or error('Invalid gui concept "'..tostring(base_concept)..'"',2)
|
||||
return base_concept:clone()
|
||||
else
|
||||
return Prototype:clone()
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Used to draw a concept to a parent element
|
||||
@tparam ?string|number|table concept the name of the concept that you want to draw
|
||||
@tparam LuaGuiElement parent the element that will act as a parent for the new element
|
||||
@treturn LuaGuiElement the element that was created
|
||||
@usage-- Drawing a new element
|
||||
Gui.draw_concept('Button',element)
|
||||
]]
|
||||
function Gui.draw_concept(concept,parent,...)
|
||||
concept = Gui.get_concept(concept) or error('Invalid gui concept "'..tostring(concept)..'"',2)
|
||||
return concept:draw(parent,...)
|
||||
end
|
||||
|
||||
--- Element Control.
|
||||
-- Functions that aim to making working with gui elements easier
|
||||
-- @section element-control
|
||||
|
||||
--[[-- Gets the player who owns this element
|
||||
@tparam LuaGuiElement element the element that you want to get the player of
|
||||
@treturn LuaPlayer the player who owns this element
|
||||
@usage-- Getting the player of an element
|
||||
local player = Gui.get_player_from_element(element)
|
||||
]]
|
||||
function Gui.get_player_from_element(element)
|
||||
return Game.get_player_by_index(element.player_index)
|
||||
end
|
||||
|
||||
--[[-- Simple check for if an element is valid
|
||||
@tparam LuaGuiElement element the element that you want to check is valid
|
||||
@treturn boolean true if the element is valid
|
||||
@usage-- Return if not valid
|
||||
if not Gui.valid(element) then return end
|
||||
]]
|
||||
function Gui.valid(element)
|
||||
return element and element.valid or false
|
||||
end
|
||||
|
||||
--[[-- Destroies and element if it is valid
|
||||
@tparam LuaGuiElement element the element that you want to destroy
|
||||
@treturn boolean true if the element was valid and was destoried
|
||||
@usage-- Destoring an element
|
||||
Gui.destroy(element)
|
||||
]]
|
||||
function Gui.destroy(element)
|
||||
if element and element.valid then
|
||||
element.destroy()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[-- Finds and returns a gui element if it is valid from a long chain of element names or concepts
|
||||
@tparam LuaGuiElement element the root element to start checking from
|
||||
@tparam ?string|table ... element names or element concepts that point to your element
|
||||
@treturn[1] boolean if the element was found, failed
|
||||
@treturn[1] string the path of the element that the search stoped at
|
||||
@treturn[2] boolean if the element was found, found
|
||||
@treturn[2] LuaGuiElement the element that was found
|
||||
@usage-- Getting the center gui
|
||||
local exists, center = Gui.exists(player,'gui','center')
|
||||
]]
|
||||
function Gui.exists(element,...)
|
||||
local path = tostring(element.name)
|
||||
for _,next_element_name in pairs{...} do
|
||||
if type(next_element_name) == 'table' then
|
||||
next_element_name = next_element_name.name
|
||||
end
|
||||
|
||||
element = element[next_element_name]
|
||||
path = path..'.'..tostring(next_element_name)
|
||||
if not Gui.valid(element) then
|
||||
return false, path
|
||||
--- Gets an element define give the uid, debug name or a copy of the element define
|
||||
-- @tparam ?string|table name the uid, debug name or define for the element define to get
|
||||
-- @tparam[opt] boolean internal when true the error trace is one level higher (used internally)
|
||||
-- @treturn table the element define that was found or an error
|
||||
function Gui.get_define(name,internal)
|
||||
if type(name) == 'table' then
|
||||
if name.name and Gui.defines[name.name] then
|
||||
return Gui.defines[name.name]
|
||||
end
|
||||
end
|
||||
return true, element
|
||||
end
|
||||
|
||||
--[[-- Checks if a gui element exists or not, if not found will throw an error
|
||||
@see Gui.exists
|
||||
@tparam LuaGuiElement element the root element to start checking from
|
||||
@tparam ?string|table ... element names or element concepts that point to your element
|
||||
@treturn LuaGuiElement the element that was found
|
||||
@usage-- Getting the center gui
|
||||
local exists, center = Gui.find(player,'gui','center')
|
||||
]]
|
||||
function Gui.find(element,...)
|
||||
local exists, element = Gui.exists(element,...)
|
||||
if not exists then
|
||||
return error('Could not find element: '..element,2)
|
||||
else
|
||||
return element
|
||||
local define = Gui.defines[name]
|
||||
|
||||
if not define and Gui.names[name] then
|
||||
return Gui.defines[Gui.names[name]]
|
||||
|
||||
elseif not define then
|
||||
return error('Invalid name for element define, name not found.',internal and 3 or 2) or nil
|
||||
|
||||
end
|
||||
|
||||
return define
|
||||
end
|
||||
|
||||
--[[-- Toggles the enabled state of an element
|
||||
@tparam LuaGuiElement element the element that you want to toggle the enabled state of
|
||||
@treturn boolean the new enabled state of the element
|
||||
@usage-- Toggle the enabled state of an element
|
||||
Gui.toggle_enabled(element)
|
||||
]]
|
||||
function Gui.toggle_enabled(element)
|
||||
if not element or not element.valid then return end
|
||||
if not element.enabled then
|
||||
element.enabled = true
|
||||
return true
|
||||
else
|
||||
element.enabled = false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Toggles the visible state of an element
|
||||
@tparam LuaGuiElement element the element that you want to toggle the visible state of
|
||||
@treturn boolean the new visible state of the element
|
||||
@usage-- Toggle the visible state of an element
|
||||
Gui.toggle_visible(element)
|
||||
]]
|
||||
function Gui.toggle_visible(element)
|
||||
if not element or not element.valid then return end
|
||||
if not element.visible then
|
||||
element.visible = true
|
||||
return true
|
||||
else
|
||||
element.visible = false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Sets the padding for a gui element
|
||||
@tparam LuaGuiElement element the element to set the padding for
|
||||
@tparam[opt=0] ?number|boolean up the amount of padding on the top, true leaves unchanged
|
||||
@tparam[opt=0] ?number|boolean down the amount of padding on the bottom, true leaves unchanged
|
||||
@tparam[opt=0] ?number|boolean left the amount of padding on the left, true leaves unchanged
|
||||
@tparam[opt=0] ?number|boolean right the amount of padding on the right, true leaves unchanged
|
||||
@usage-- Remove all padding of an element
|
||||
Gui.set_padding(element)
|
||||
@usage-- Remove side padding but keep vertical padding
|
||||
Gui.set_padding(element,true,true)
|
||||
@usage-- Remove all padding but set right to 2
|
||||
Gui.set_padding(element,false,false,false,2)
|
||||
]]
|
||||
function Gui.set_padding(element,up,down,left,right)
|
||||
local style = element.style
|
||||
style.top_padding = up == true and style.top_padding or up or 0
|
||||
style.bottom_padding = down == true and style.top_padding or down or 0
|
||||
style.left_padding = left == true and style.top_padding or left or 0
|
||||
style.right_padding = right == true and style.top_padding or right or 0
|
||||
end
|
||||
|
||||
--[[ Used to check a property exists and if it is a function then call the function
|
||||
@function Gui.resolve_property
|
||||
@tparam any value the value that you are testing exists and call if its a function
|
||||
@tparam LuaGuiElement element the element that is passed to the function if it is a function
|
||||
@treturn any the value or what it returns if it is a function
|
||||
@usage-- Getting the default value
|
||||
local default = Gui.resolve_property(properties.default,element)
|
||||
if default then
|
||||
element.value = default
|
||||
end
|
||||
]]
|
||||
Gui.resolve_property = resolve_value
|
||||
|
||||
--- Store Categories.
|
||||
-- Functions that are common types of categories
|
||||
-- @section store-categories
|
||||
|
||||
--[[-- A categorize function to be used with add_store, each player has their own category
|
||||
@tparam LuaGuiElement element the element that will be converted to a string
|
||||
@treturn string the player's name who owns this element
|
||||
@usage-- 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 player has their own value
|
||||
-- @tparam LuaGuiElement element the element that will be converted to a string
|
||||
-- @treturn string the player's name who owns this element
|
||||
function Gui.categorize_by_player(element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
return player.name
|
||||
end
|
||||
|
||||
--[[-- A categorize function to be used with add_store, each force has its own category
|
||||
@tparam LuaGuiElement element the element that will be converted to a string
|
||||
@treturn string the player's force name who owns this element
|
||||
@usage-- 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 force has its own value
|
||||
-- @tparam LuaGuiElement element the element that will be converted to a string
|
||||
-- @treturn string the player's force name who owns this element
|
||||
function Gui.categorize_by_force(element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
return player.force.name
|
||||
end
|
||||
|
||||
--[[-- A categorize function to be used with add_store, each surface has its own category
|
||||
@tparam LuaGuiElement element the element that will be converted to a string
|
||||
@treturn string the player's surface name who owns this element
|
||||
@usage-- Storing data on a per surface basis, can be used with instances
|
||||
Gui.get_concept('CustomButton')
|
||||
:define_data_store(Gui.categorize_by_surface)
|
||||
]]
|
||||
--- A categorize function to be used with add_store, each surface has its own value
|
||||
-- @tparam LuaGuiElement element the element that will be converted to a string
|
||||
-- @treturn string the player's surface name who owns this element
|
||||
function Gui.categorize_by_surface(element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
return player.surface.name
|
||||
end
|
||||
|
||||
--- Draws a copy of the element define to the parent element, see draw_to
|
||||
-- @tparam ?string|table name the uid, debug name or define for the element define to draw
|
||||
-- @tparam LuaGuiEelement element the parent element that it the define will be drawn to
|
||||
-- @treturn LuaGuiElement the new element that was created
|
||||
function Gui.draw(name,element,...)
|
||||
local define = Gui.get_define(name,true)
|
||||
return define:draw_to(element,...)
|
||||
end
|
||||
|
||||
--- Will toggle the enabled state of an element
|
||||
-- @tparam LuaGuiElement element the gui element to toggle
|
||||
-- @treturn boolean the new state that the element has
|
||||
function Gui.toggle_enabled(element)
|
||||
if not element or not element.valid then return end
|
||||
if not element.enabled then
|
||||
element.enabled = true
|
||||
else
|
||||
element.enabled = false
|
||||
end
|
||||
return element.enabled
|
||||
end
|
||||
|
||||
--- Will toggle the visiblity of an element
|
||||
-- @tparam LuaGuiElement element the gui element to toggle
|
||||
-- @treturn boolean the new state that the element has
|
||||
function Gui.toggle_visible(element)
|
||||
if not element or not element.valid then return end
|
||||
if not element.visible then
|
||||
element.visible = true
|
||||
else
|
||||
element.visible = false
|
||||
end
|
||||
return element.visible
|
||||
end
|
||||
|
||||
--- Sets the padding for a gui element
|
||||
-- @tparam LuaGuiElement element the element to set the padding for
|
||||
-- @tparam[opt=0] number up the amount of padding on the top
|
||||
-- @tparam[opt=0] number down the amount of padding on the bottom
|
||||
-- @tparam[opt=0] number left the amount of padding on the left
|
||||
-- @tparam[opt=0] number right the amount of padding on the right
|
||||
function Gui.set_padding(element,up,down,left,right)
|
||||
local style = element.style
|
||||
style.top_padding = up or 0
|
||||
style.bottom_padding = down or 0
|
||||
style.left_padding = left or 0
|
||||
style.right_padding = right or 0
|
||||
end
|
||||
|
||||
--- Sets the padding for a gui style
|
||||
-- @tparam LuaStyle style the element to set the padding for
|
||||
-- @tparam[opt=0] number up the amount of padding on the top
|
||||
-- @tparam[opt=0] number down the amount of padding on the bottom
|
||||
-- @tparam[opt=0] number left the amount of padding on the left
|
||||
-- @tparam[opt=0] number right the amount of padding on the right
|
||||
function Gui.set_padding_style(style,up,down,left,right)
|
||||
style.top_padding = up or 0
|
||||
style.bottom_padding = down or 0
|
||||
style.left_padding = left or 0
|
||||
style.right_padding = right or 0
|
||||
end
|
||||
|
||||
--- Allows the creation of an alignment flow to place elements into
|
||||
-- @tparam LuaGuiElement element the element to add this alignment into
|
||||
-- @tparam[opt] string name the name to use for the alignment
|
||||
-- @tparam[opt='right'] string horizontal_align the horizontal alignment of the elements in this flow
|
||||
-- @tparam[opt='center'] string vertical_align the vertical alignment of the elements in this flow
|
||||
-- @treturn LuaGuiElement the new flow that was created
|
||||
function Gui.create_alignment(element,name,horizontal_align,vertical_align)
|
||||
local flow = element.add{name=name,type='flow'}
|
||||
local style = flow.style
|
||||
Gui.set_padding(flow,1,1,2,2)
|
||||
style.horizontal_align = horizontal_align or 'right'
|
||||
style.vertical_align = vertical_align or 'center'
|
||||
style.horizontally_stretchable =style.horizontal_align ~= 'center'
|
||||
style.vertically_stretchable = style.vertical_align ~= 'center'
|
||||
return flow
|
||||
end
|
||||
|
||||
--- Destroies an element but tests for it being present and valid first
|
||||
-- @tparam LuaGuiElement element the element to be destroied
|
||||
-- @treturn boolean true if it was destoried
|
||||
function Gui.destroy_if_valid(element)
|
||||
if element and element.valid then
|
||||
element.destroy()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a scroll area with a table inside, table can be any size
|
||||
-- @tparam LuaGuiElement element the element to add this scroll into
|
||||
-- @tparam number table_size the number of columns in the table
|
||||
-- @tparam number maximal_height the max hieght of the scroll
|
||||
-- @tparam[opt='scroll'] string name the name of the scoll element
|
||||
-- @treturn LuaGuiElement the table that was made
|
||||
function Gui.create_scroll_table(element,table_size,maximal_height,name)
|
||||
local list_scroll =
|
||||
element.add{
|
||||
name=name or 'scroll',
|
||||
type='scroll-pane',
|
||||
direction='vertical',
|
||||
horizontal_scroll_policy='never',
|
||||
vertical_scroll_policy='auto-and-reserve-space'
|
||||
}
|
||||
Gui.set_padding(list_scroll,1,1,2,2)
|
||||
list_scroll.style.horizontally_stretchable = true
|
||||
list_scroll.style.maximal_height = maximal_height
|
||||
|
||||
local list_table =
|
||||
list_scroll.add{
|
||||
name='table',
|
||||
type='table',
|
||||
column_count=table_size
|
||||
}
|
||||
Gui.set_padding(list_table)
|
||||
list_table.style.horizontally_stretchable = true
|
||||
list_table.style.vertical_align = 'center'
|
||||
list_table.style.cell_padding = 0
|
||||
|
||||
return list_table
|
||||
end
|
||||
|
||||
--- Creates a header section with a label and button area
|
||||
-- @tparam LuaGuiElement element the element to add this header into
|
||||
-- @tparam localeString caption the caption that is used as the title
|
||||
-- @tparam[opt] localeString tooltip the tooltip that is shown on the caption
|
||||
-- @tparam[opt] boolean right_align when true will include the right align area
|
||||
-- @tparam[opt='header'] string name the name of the header area
|
||||
-- @treturn LuaGuiElement the header that was made, or the align area if that was created
|
||||
function Gui.create_header(element,caption,tooltip,right_align,name)
|
||||
local header =
|
||||
element.add{
|
||||
name=name or 'header',
|
||||
type='frame',
|
||||
style='subheader_frame'
|
||||
}
|
||||
Gui.set_padding(header,2,2,4,4)
|
||||
header.style.horizontally_stretchable = true
|
||||
header.style.use_header_filler = false
|
||||
|
||||
header.add{
|
||||
type='label',
|
||||
style='heading_1_label',
|
||||
caption=caption,
|
||||
tooltip=tooltip
|
||||
}
|
||||
|
||||
return right_align and Gui.create_alignment(header,'header-align') or header
|
||||
end
|
||||
|
||||
return Gui
|
||||
128
expcore/gui/elements/buttons.lua
Normal file
128
expcore/gui/elements/buttons.lua
Normal file
@@ -0,0 +1,128 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Buttons.
|
||||
-- Gui class define for buttons and sprite buttons
|
||||
-- @section Buttons
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
Button.new_button(name) --- Creates a new button element define
|
||||
|
||||
Button._prototype:on_click(player,element) --- Registers a handler for when the button is clicked
|
||||
Button._prototype:on_left_click(player,element) --- Registers a handler for when the button is clicked with the left mouse button
|
||||
Button._prototype:on_right_click(player,element) --- Registers a handler for when the button is clicked with the right mouse button
|
||||
|
||||
Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite) --- Adds sprites to a button making it a sprite button
|
||||
Button._prototype:set_click_filter(filter,...) --- Adds a click / mouse button filter to the button
|
||||
Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
|
||||
local Button = {
|
||||
_prototype=Prototype.extend{
|
||||
on_raw_click = Prototype.event,
|
||||
on_click = Prototype.event,
|
||||
on_left_click = Prototype.event,
|
||||
on_right_click = Prototype.event,
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new button element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new button element define
|
||||
function Button.new_button(name)
|
||||
|
||||
local self = Gui.new_define(Button._prototype,name)
|
||||
self.draw_data.type = 'button'
|
||||
self.draw_data.style = mod_gui.button_style
|
||||
|
||||
Gui.on_click(self.name,function(event)
|
||||
local mouse_button = event.button
|
||||
local keys = {alt=event.alt,control=event.control,shift=event.shift}
|
||||
local player,element = event.player,event.element
|
||||
event.keys = keys
|
||||
|
||||
self:raise_event('on_raw_click',event)
|
||||
|
||||
if self.post_authenticator then
|
||||
if not self.post_authenticator(event.player,self.name) then return end
|
||||
end
|
||||
|
||||
if mouse_button == defines.mouse_button_type.left then
|
||||
self:raise_event('on_left_click',player,element)
|
||||
elseif mouse_button == defines.mouse_button_type.right and self.events.on_right_click then
|
||||
self:raise_event('on_right_click',player,element)
|
||||
end
|
||||
|
||||
if self.mouse_button_filter and not self.mouse_button_filter[mouse_button] then return end
|
||||
if self.key_button_filter then
|
||||
for key,state in pairs(self.key_button_filter) do
|
||||
if state and not keys[key] then return end
|
||||
end
|
||||
end
|
||||
|
||||
self:raise_event('on_click',player,element)
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds sprites to a button making it a sprite button
|
||||
-- @tparam SpritePath sprite the sprite path for the default sprite for the button
|
||||
-- @tparam[opt] SpritePath hovered_sprite the sprite path for the sprite when the player hovers over the button
|
||||
-- @tparam[opt] SpritePath clicked_sprite the sprite path for the sprite when the player clicks the button
|
||||
-- @treturn self returns the button define to allow chaining
|
||||
function Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite)
|
||||
self.draw_data.type = 'sprite-button'
|
||||
self.draw_data.sprite = sprite
|
||||
self.draw_data.hovered_sprite = hovered_sprite
|
||||
self.draw_data.clicked_sprite = clicked_sprite
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds a click / mouse button filter to the button
|
||||
-- @tparam table filter ?string|table either a of mouse buttons or the first mouse button to filter, with a table true means allowed
|
||||
-- @tparam[opt] table ... when filter is not a you can add the mouse buttons one after each other
|
||||
-- @treturn self returns the button define to allow chaining
|
||||
function Button._prototype:set_click_filter(filter,...)
|
||||
if type(filter) == 'string' then
|
||||
filter = {[filter]=true}
|
||||
for _,v in pairs({...}) do
|
||||
filter[v] = true
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs(filter) do
|
||||
if type(v) == 'string' then
|
||||
filter[k] = defines.mouse_button_type[v]
|
||||
end
|
||||
end
|
||||
|
||||
self.mouse_button_filter = filter
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds a control key filter to the button
|
||||
-- @tparam table filter ?string|table either a of control keys or the first control keys to filter, with a table true means allowed
|
||||
-- @tparam[opt] table ... when filter is not a you can add the control keys one after each other
|
||||
-- @treturn self returns the button define to allow chaining
|
||||
function Button._prototype:set_key_filter(filter,...)
|
||||
if type(filter) == 'string' then
|
||||
filter = {[filter]=true}
|
||||
for _,v in pairs({...}) do
|
||||
filter[v] = true
|
||||
end
|
||||
end
|
||||
|
||||
self.key_button_filter = filter
|
||||
return self
|
||||
end
|
||||
|
||||
return Button
|
||||
252
expcore/gui/elements/checkbox.lua
Normal file
252
expcore/gui/elements/checkbox.lua
Normal file
@@ -0,0 +1,252 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Checkboxs.
|
||||
-- Gui class define for checkbox and radiobuttons
|
||||
-- @section checkboxs
|
||||
|
||||
--[[
|
||||
>>>> Using an option set
|
||||
An option set is a set of radio buttons where only one of them can be active at a time, this means that when one
|
||||
is clicked all the other ones are set to false, an option set must be defined before hand and will always store
|
||||
its state but is not limited by how it can categorize the store.
|
||||
|
||||
First you must register the store with a name and a update callback, and an optional function for categorize:
|
||||
|
||||
local example_option_set =
|
||||
Gui.new_option_set('example-option-set',function(value,category)
|
||||
game.print('Example options set '..category..' is now: '..tostring(value))
|
||||
end,Gui.categorize_by_player)
|
||||
|
||||
Then you must register some radiobutton defines and include them in the option set:
|
||||
|
||||
local example_option_one =
|
||||
Gui.new_radiobutton()
|
||||
:set_caption('Option One')
|
||||
:add_as_option(example_option_set,'One')
|
||||
|
||||
local example_option_two =
|
||||
Gui.new_radiobutton()
|
||||
:set_caption('Option Two')
|
||||
:add_as_option(example_option_set,'Two')
|
||||
|
||||
Note that these radiobuttons can still have on_element_update events but this may result in a double trigger of events as
|
||||
the option set update is always triggered; also add_store cant be used as the option set acts as the store however get
|
||||
and set store will still work but will effect the option set rather than the individual radiobuttons.
|
||||
|
||||
>>>> Functions
|
||||
Checkbox.new_checkbox(name) --- Creates a new checkbox element define
|
||||
Checkbox._prototype_checkbox:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Checkbox._prototype_checkbox:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Checkbox.new_radiobutton(name) --- Creates a new radiobutton element define
|
||||
Checkbox._prototype_radiobutton:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Checkbox._prototype_radiobutton:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) --- Adds this radiobutton to be an option in the given option set (only one can be true at a time)
|
||||
|
||||
Checkbox.new_option_set(name,callback,categorize) --- Registers a new option set that can be linked to radiobutton (only one can be true at a time)
|
||||
Checkbox.draw_option_set(name,element) --- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work)
|
||||
|
||||
Checkbox.reset_radiobutton(element,exclude,recursive) --- Sets all radiobutton in a element to false (unless excluded) and can act recursively
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Store = require 'expcore.store' --- @dep expcore.store
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam boolean value the new state of the checkbox
|
||||
local function store_update(define,element,value)
|
||||
element.state = value
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
define:raise_event('on_element_update',player,element,value)
|
||||
end
|
||||
|
||||
local Checkbox = {
|
||||
option_sets={},
|
||||
option_categorize={},
|
||||
_prototype_checkbox=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
},
|
||||
_prototype_radiobutton=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new checkbox element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new checkbox element define
|
||||
function Checkbox.new_checkbox(name)
|
||||
|
||||
local self = Gui.new_define(Checkbox._prototype_checkbox,name)
|
||||
self.draw_data.type = 'checkbox'
|
||||
self.draw_data.state = false
|
||||
|
||||
self:on_draw(function(player,element)
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local state = self:get_store(category,true)
|
||||
if state then element.state = true end
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.on_checked_state_changed(self.name,function(event)
|
||||
local element = event.element
|
||||
|
||||
if self.option_set then
|
||||
local value = Checkbox.option_sets[self.option_set][element.name]
|
||||
local category = self.categorize and self.categorize(element)
|
||||
self:set_store(category,value)
|
||||
|
||||
elseif self.store then
|
||||
local value = element.state
|
||||
local category = self.categorize and self.categorize(element)
|
||||
self:set_store(category,value)
|
||||
|
||||
else
|
||||
self:raise_event('on_element_update',event.player,element,element.state)
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new radiobutton element define, has all functions checkbox has
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new button element define
|
||||
function Checkbox.new_radiobutton(name)
|
||||
local self = Checkbox.new_checkbox(name)
|
||||
self.draw_data.type = 'radiobutton'
|
||||
|
||||
local mt = getmetatable(self)
|
||||
mt.__index = Checkbox._prototype_radiobutton
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds this radiobutton to be an option in the given option set (only one can be true at a time)
|
||||
-- @tparam string option_set the name of the option set to add this element to
|
||||
-- @tparam string option_name the name of this option that will be used to identify it
|
||||
-- @treturn self the define to allow chaining
|
||||
function Checkbox._prototype_radiobutton:add_as_option(option_set,option_name)
|
||||
self.option_set = option_set
|
||||
self.option_name = option_name or self.name
|
||||
|
||||
Checkbox.option_sets[option_set][self.option_name] = self.name
|
||||
Checkbox.option_sets[option_set][self.name] = self.option_name
|
||||
|
||||
self:add_store(Checkbox.option_categorize[option_set])
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Gets the stored value of the radiobutton or the option set if present
|
||||
-- @tparam string category[opt] the category to get such as player name or force name
|
||||
-- @tparam boolean internal used to prevent stackover flow
|
||||
-- @treturn any the value that is stored for this define
|
||||
function Checkbox._prototype_radiobutton:get_store(category,internal)
|
||||
if not self.store then return end
|
||||
local location = not internal and self.option_set or self.store
|
||||
return Store.get(location,category)
|
||||
end
|
||||
|
||||
--- Sets the stored value of the radiobutton or the option set if present
|
||||
-- @tparam string category[opt] the category to get such as player name or force name
|
||||
-- @tparam boolean value the value to set for this define, must be valid for its type ie for checkbox etc
|
||||
-- @tparam boolean internal used to prevent stackover flow
|
||||
-- @treturn boolean true if the value was set
|
||||
function Checkbox._prototype_radiobutton:set_store(category,value,internal)
|
||||
if not self.store then return end
|
||||
local location = not internal and self.option_set or self.store
|
||||
return Store.set(location,category,value)
|
||||
end
|
||||
|
||||
--- Registers a new option set that can be linked to radiobuttons (only one can be true at a time)
|
||||
-- @tparam string name the name of the option set, must be unique
|
||||
-- @tparam function callback the update callback when the value of the option set changes
|
||||
-- callback param - value string - the new selected option for this option set
|
||||
-- callback param - category string - the category that updated if categorize was used
|
||||
-- @tparam function categorize the function used to convert an element into a string
|
||||
-- @treturn string the name of this option set to be passed to add_as_option
|
||||
function Checkbox.new_option_set(name,callback,categorize)
|
||||
|
||||
Store.register(name,function(value,category)
|
||||
local options = Checkbox.option_sets[name]
|
||||
for opt_name,define_name in pairs(options) do
|
||||
if Gui.defines[define_name] then
|
||||
local define = Gui.get_define(define_name)
|
||||
local state = opt_name == value
|
||||
define:set_store(category,state,true)
|
||||
end
|
||||
end
|
||||
callback(value,category)
|
||||
end)
|
||||
|
||||
Checkbox.option_categorize[name] = categorize
|
||||
Checkbox.option_sets[name] = {}
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
--- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work)
|
||||
-- @tparam string name the name of the option set to draw the radiobuttons of
|
||||
-- @tparam LuaGuiElement element the parent element that the radiobuttons will be drawn to
|
||||
function Checkbox.draw_option_set(name,element)
|
||||
if not Checkbox.option_sets[name] then return end
|
||||
local options = Checkbox.option_sets[name]
|
||||
|
||||
for _,option in pairs(options) do
|
||||
if Gui.defines[option] then
|
||||
Gui.defines[option]:draw_to(element)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Sets all radiobutton in a element to false (unless excluded) and can act recursively
|
||||
-- @tparam LuaGuiElement element the root gui element to start setting radio buttons from
|
||||
-- @tparam[opt] table exclude ?string|table the name of the radiobutton to exclude or a of radiobuttons where true will set the state true
|
||||
-- @tparam[opt=false] ?number|boolean recursive if true will recur as much as possible, if a will recur that number of times
|
||||
-- @treturn boolean true if successful
|
||||
function Checkbox.reset_radiobuttons(element,exclude,recursive)
|
||||
if not element or not element.valid then return end
|
||||
exclude = type(exclude) == 'table' and exclude or exclude ~= nil and {[exclude]=true} or {}
|
||||
recursive = type(recursive) == 'number' and recursive-1 or recursive
|
||||
|
||||
for _,child in pairs(element.children) do
|
||||
if child and child.valid and child.type == 'radiobutton' then
|
||||
local state = exclude[child.name] or false
|
||||
local define = Gui.defines[child.name]
|
||||
|
||||
if define then
|
||||
local category = define.categorize and define.categorize(child) or state
|
||||
define:set_store(category,state)
|
||||
|
||||
else
|
||||
child.state = state
|
||||
|
||||
end
|
||||
|
||||
elseif child.children and (type(recursive) == 'number' and recursive >= 0 or recursive == true) then
|
||||
Checkbox.reset_radiobutton(child,exclude,recursive)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return Checkbox
|
||||
187
expcore/gui/elements/dropdown.lua
Normal file
187
expcore/gui/elements/dropdown.lua
Normal file
@@ -0,0 +1,187 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Dropdowns.
|
||||
-- Gui class define for dropdowns and list box
|
||||
-- @section dropdowns
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
Dropdown.new_dropdown(name) --- Creates a new dropdown element define
|
||||
Dropdown.new_list_box(name) --- Creates a new list box element define
|
||||
|
||||
Dropdown._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Dropdown._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Dropdown._prototype:new_static_options(options,...) --- Adds new static options to the dropdown which will trigger the general callback
|
||||
Dropdown._prototype:new_dynamic_options(callback) --- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options)
|
||||
Dropdown._prototype:add_option_callback(option,callback) --- Adds a case specific callback which will only run when that option is selected (general case still triggered)
|
||||
|
||||
Dropdown.select_value(element,value) --- Selects the option from a dropdown or list box given the value rather than key
|
||||
Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
local select_value
|
||||
--- Store call for store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam string value the new option for the dropdown
|
||||
local function store_update(define,element,value)
|
||||
select_value(element,value)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
define:raise_event('on_element_update',player,element,value)
|
||||
|
||||
if define.option_callbacks and define.option_callbacks[value] then
|
||||
define.option_callbacks[value](player,element,value)
|
||||
end
|
||||
end
|
||||
|
||||
local Dropdown = {
|
||||
_prototype=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new dropdown element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new dropdown element define
|
||||
function Dropdown.new_dropdown(name)
|
||||
|
||||
local self = Gui.new_define(Dropdown._prototype,name)
|
||||
self.draw_data.type = 'drop-down'
|
||||
|
||||
self:on_draw(function(player,element)
|
||||
if self.dynamic_options then
|
||||
local dynamic_options = self.dynamic_options(player,element)
|
||||
local items = element.items
|
||||
for _,v in pairs(dynamic_options) do
|
||||
table.insert(items,v)
|
||||
end
|
||||
element.items = items
|
||||
end
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local value = self:get_store(category)
|
||||
if value then Dropdown.select_value(element,value) end
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.on_selection_state_changed(self.name,function(event)
|
||||
local element = event.element
|
||||
local value = Dropdown.get_selected_value(element)
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
self:set_store(category,value)
|
||||
|
||||
else
|
||||
local player = event.player
|
||||
local option_callbacks = self.option_callbacks
|
||||
self:raise_event('on_element_update',player,element,value)
|
||||
if option_callbacks and option_callbacks[value] then
|
||||
option_callbacks[value](player,element,value)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new list box element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new list box element define
|
||||
function Dropdown.new_list_box(name)
|
||||
local self = Dropdown.new_dropdown(name)
|
||||
self.draw_data.type = 'list-box'
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds new static options to the dropdown which will trigger the general callback
|
||||
-- @tparam table options ?string|table either a of option strings or the first option string, with a table values are the options
|
||||
-- @tparam[opt] table ... when options is not a you can add the options one after each other
|
||||
-- @tparam self the define to allow chaining
|
||||
function Dropdown._prototype:new_static_options(options,...)
|
||||
if type(options) == 'string' then
|
||||
options = {options}
|
||||
for _,v in pairs({...}) do
|
||||
table.insert(options,v)
|
||||
end
|
||||
end
|
||||
|
||||
self.options = options
|
||||
self.draw_data.items = options
|
||||
return self
|
||||
end
|
||||
Dropdown._prototype.add_options = Dropdown._prototype.new_static_options
|
||||
|
||||
--- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options)
|
||||
-- @tparam function callback the function that will run to get the options for the dropdown
|
||||
-- callback param - player LuaPlayer - the player that the element is being drawn to
|
||||
-- callback param - element LuaGuiElement - the element that is being drawn
|
||||
-- callback return - table - the values of this table will be appended to the static options of the dropdown
|
||||
-- @treturn self the define to allow chaining
|
||||
function Dropdown._prototype:new_dynamic_options(callback)
|
||||
if type(callback) ~= 'function' then
|
||||
return error('Dynamic options callback must be a function',2)
|
||||
end
|
||||
self.dynamic_options = callback
|
||||
return self
|
||||
end
|
||||
Dropdown._prototype.add_dynamic = Dropdown._prototype.new_dynamic_options
|
||||
|
||||
--- Adds a case specific callback which will only run when that option is selected (general case still triggered)
|
||||
-- @tparam string option the name of the option to trigger the callback on; if not already added then will be added as an option
|
||||
-- @tparam function callback the function that will be called when that option is selected
|
||||
-- callback param - player LuaPlayer - the player who owns the gui element
|
||||
-- callback param - element LuaGuiElement - the element which is being effected
|
||||
-- callback param - value string - the new option that has been selected
|
||||
-- @treturn self the define to allow chaining
|
||||
function Dropdown._prototype:add_option_callback(option,callback)
|
||||
if not self.option_callbacks then self.option_callbacks = {} end
|
||||
if not self.options then self.options = {} end
|
||||
|
||||
self.option_callbacks[option] = callback
|
||||
if not table.contains(self.options,option) then
|
||||
table.insert(self.options,option)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Selects the option from a dropdown or list box given the value rather than key
|
||||
-- @tparam LuaGuiElement element the element that contains the option
|
||||
-- @tparam string value the option to select from the dropdown
|
||||
-- @treturn number the key where the value was
|
||||
function Dropdown.select_value(element,value)
|
||||
for k,item in pairs(element.items) do
|
||||
if item == value then
|
||||
element.selected_index = k
|
||||
return k
|
||||
end
|
||||
end
|
||||
end
|
||||
select_value = Dropdown.select_value
|
||||
|
||||
--- Returns the currently selected value rather than index
|
||||
-- @tparam LuaGuiElement element the gui element that you want to get the value of
|
||||
-- @treturn string the value that is currently selected
|
||||
function Dropdown.get_selected_value(element)
|
||||
local index = element.selected_index
|
||||
return element.items[index]
|
||||
end
|
||||
|
||||
return Dropdown
|
||||
99
expcore/gui/elements/elem-button.lua
Normal file
99
expcore/gui/elements/elem-button.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Elem Buttons.
|
||||
-- Gui class defines for elem buttons
|
||||
-- @section elem-buttons
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
ElemButton.new_elem_button(name) --- Creates a new elem button element define
|
||||
|
||||
ElemButton._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
ElemButton._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
ElemButton._prototype:set_type(type) --- Sets the type of the elem button, the type is required so this must be called at least once
|
||||
ElemButton._prototype:set_default(value) --- Sets the default value for the elem button, this may be a function or a string
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam string value the new value for the elem button
|
||||
local function store_update(define,element,value)
|
||||
element.elem_value = value
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
define:raise_event('on_element_update',player,element,value)
|
||||
end
|
||||
|
||||
local ElemButton = {
|
||||
_prototype=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new elem button element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new elem button element define
|
||||
function ElemButton.new_elem_button(name)
|
||||
|
||||
local self = Gui.new_define(ElemButton._prototype,name)
|
||||
self.draw_data.type = 'choose-elem-button'
|
||||
|
||||
self:on_draw(function(player,element)
|
||||
if type(self.default) == 'function' then
|
||||
element.elem_value = self.default(player,element)
|
||||
end
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local value = self:get_store(category)
|
||||
if value then element.elem_value = value end
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.on_elem_changed(self.name,function(event)
|
||||
local element = event.element
|
||||
local value = element.elem_value
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
self:set_store(category,value)
|
||||
|
||||
else
|
||||
self:raise_event('on_element_update',event.player,element,value)
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the type of the elem button, the type is required so this must be called at least once
|
||||
-- @tparam string type the type that this elem button is see factorio api
|
||||
-- @treturn the element define to allow for chaining
|
||||
ElemButton._prototype.set_type = Prototype.setter('string','draw_data','elem_type')
|
||||
|
||||
--- Sets the default value for the elem button, this may be a function or a string
|
||||
-- @tparam ?string|function value string a will be a static default and a function will be called when drawn to get the default
|
||||
-- @treturn the element define to allow for chaining
|
||||
function ElemButton._prototype:set_default(value)
|
||||
self.default = value
|
||||
if type(value) ~= 'function' then
|
||||
self.draw_data[self.draw_data.elem_type] = value
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
return ElemButton
|
||||
390
expcore/gui/elements/progress-bar.lua
Normal file
390
expcore/gui/elements/progress-bar.lua
Normal file
@@ -0,0 +1,390 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Progress Bars.
|
||||
-- Gui element define for progress bars
|
||||
-- @section progress-bars
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
|
||||
ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances have incremented
|
||||
ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances have decremented
|
||||
|
||||
ProgressBar.new_progressbar(name) --- Creates a new progressbar element define
|
||||
ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
|
||||
ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0
|
||||
ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar
|
||||
ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store
|
||||
ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar
|
||||
ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store
|
||||
ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store
|
||||
ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0
|
||||
|
||||
ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element completes (hits 0 or 1)
|
||||
ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1)
|
||||
ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented
|
||||
ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
--- Event call for when the value is outside the range 0-1
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
local function event_call(define,element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
define:raise_event('on_complete',player,element,function()
|
||||
define:add_element(element)
|
||||
define:reset_element(element)
|
||||
end)
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam number value the new value for the progress bar
|
||||
local function store_update(define,element,value)
|
||||
if value then
|
||||
element.value = value
|
||||
if define.count_down and value <= 0
|
||||
or not define.count_down and value >= 1 then
|
||||
event_call(define,element)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ProgressBar = {
|
||||
unregistered={}, -- elements with no callbacks
|
||||
independent={}, -- elements with a link to a define
|
||||
_prototype=Prototype.extend{
|
||||
on_complete = Prototype.event,
|
||||
on_store_complete = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
}
|
||||
}
|
||||
|
||||
Global.register({
|
||||
unregistered = ProgressBar.unregistered,
|
||||
independent = ProgressBar.independent
|
||||
},function(tbl)
|
||||
ProgressBar.unregistered = tbl.unregistered
|
||||
ProgressBar.independent = tbl.independent
|
||||
end)
|
||||
|
||||
--- Gets the define data, cant use Gui.get_define as it would error
|
||||
-- @tparam ?table|string define the define to get
|
||||
-- @treturn table the define or nil
|
||||
local function get_define(define)
|
||||
if type(define) == 'table' then
|
||||
if define.name and Gui.defines[define.name] then
|
||||
return Gui.defines[define.name]
|
||||
end
|
||||
end
|
||||
|
||||
return Gui.defines[define]
|
||||
end
|
||||
|
||||
--- Gets the element data, used when there is no define
|
||||
-- @tparam LuaGuiElement element the element to get the data of
|
||||
-- @treturn table the element data similar to define
|
||||
local function get_element(element)
|
||||
if not element.valid then return end
|
||||
local name = element.player_index..':'..element.index
|
||||
|
||||
if ProgressBar.unregistered[name] then
|
||||
return ProgressBar.unregistered[name]
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets the maximum value that represents the end value of the progress bar
|
||||
-- @tparam ?LuaGuiElement|string element either a gui element or a registered define
|
||||
-- @tparam number amount the amount to have set as the maximum
|
||||
function ProgressBar.set_maximum(element,amount)
|
||||
amount = amount > 0 and amount or error('amount must be greater than 0')
|
||||
|
||||
local define = get_define(element)
|
||||
if define then
|
||||
define:set_default_maximum(amount)
|
||||
|
||||
else
|
||||
local element_data = get_element(element)
|
||||
|
||||
if element_data then
|
||||
element_data.maximum = amount
|
||||
|
||||
else
|
||||
local name = element.player_index..':'..element.index
|
||||
ProgressBar.unregistered[name] = {
|
||||
element=element,
|
||||
maximum=amount or 1
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- Increases the value of the progressbar, if a define is given all of its instances have incremented
|
||||
-- @tparam ?LuaGuiElement|string element either a gui element or a registered define
|
||||
-- @tparam[opt=1] number amount the amount to increase the progressbar by
|
||||
function ProgressBar.increment(element,amount)
|
||||
amount = type(amount) == 'number' and amount or 1
|
||||
|
||||
local define = get_define(element)
|
||||
if define then
|
||||
define:increment(amount)
|
||||
|
||||
else
|
||||
local element_data = get_element(element)
|
||||
|
||||
if element_data then
|
||||
local real_amount = amount/element_data.maximum
|
||||
element.value = element.value + real_amount
|
||||
|
||||
if element.value >= 1 then
|
||||
local name = element.player_index..':'..element.index
|
||||
ProgressBar.unregistered[name] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- Decreases the value of the progressbar, if a define is given all of its instances have decremented
|
||||
-- @tparam ?LuaGuiElement|string element either a gui element or a registered define
|
||||
-- @tparam[opt=1] number amount the amount to decrease the progressbar by
|
||||
function ProgressBar.decrement(element,amount)
|
||||
amount = type(amount) == 'number' and amount or 1
|
||||
|
||||
local define = get_define(element)
|
||||
if define then
|
||||
define:decrement(amount)
|
||||
|
||||
else
|
||||
local element_data = get_element(element)
|
||||
|
||||
if element_data then
|
||||
local real_amount = amount/element_data.maximum
|
||||
element.value = element.value - real_amount
|
||||
|
||||
if element.value <= 0 then
|
||||
local name = element.player_index..':'..element.index
|
||||
ProgressBar.unregistered[name] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a new progressbar element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new progressbar element define
|
||||
function ProgressBar.new_progressbar(name)
|
||||
|
||||
local self = Gui.new_define(ProgressBar._prototype,name)
|
||||
self.draw_data.type = 'progressbar'
|
||||
|
||||
self:on_draw(function(player,element,maximum)
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local value = self:get_store(category)
|
||||
if not value then
|
||||
value = self.count_down and 1 or 0
|
||||
self:set_store(category,value)
|
||||
end
|
||||
element.value = value
|
||||
|
||||
else
|
||||
if self.count_down then
|
||||
element.value = 1
|
||||
end
|
||||
|
||||
if not ProgressBar.independent[self.name] then
|
||||
ProgressBar.independent[self.name] = {}
|
||||
end
|
||||
|
||||
table.insert(ProgressBar.independent[self.name],{
|
||||
element = element,
|
||||
maximum = maximum
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the maximum value that represents the end value of the progress bar
|
||||
-- @tparam number amount the amount to have set as the maximum
|
||||
-- @treturn table the define to allow chaining
|
||||
function ProgressBar._prototype:set_default_maximum(amount)
|
||||
amount = amount > 0 and amount or error('amount must be greater than 0')
|
||||
self.default_maximum = amount
|
||||
return self
|
||||
end
|
||||
|
||||
--- Will set the progress bar to start at 1 and trigger when it hits 0
|
||||
-- @tparam[opt=true] boolean state when true the bar will start filled, to be used with decrease
|
||||
-- @treturn table the define to allow chaining
|
||||
function ProgressBar._prototype:use_count_down(state)
|
||||
if state == false then
|
||||
self.count_down = false
|
||||
else
|
||||
self.count_down = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Main logic for changing the value of a progress bar, this only applies when its a registered define
|
||||
-- @tparam table self the define that is being changed
|
||||
-- @tparam number amount the amount which it is being changed by, may be negative
|
||||
-- @tparam[opt] string category the category to use with store
|
||||
-- @tparam[opt] function filter when given the filter must return true for the value of the element to be changed
|
||||
local function change_value_prototype(self,amount,category,filter)
|
||||
|
||||
local function reset_store()
|
||||
local value = self.count_down and 1 or 0
|
||||
self:set_store(category,value)
|
||||
end
|
||||
|
||||
if self.store then
|
||||
local value = self:get_store(category) or self.count_down and 1 or 0
|
||||
local maximum = self.default_maximum or 1
|
||||
local new_value = value + (amount/maximum)
|
||||
|
||||
self:set_store(category,new_value)
|
||||
|
||||
if self.count_down and new_value <= 0
|
||||
or not self.count_down and new_value >= 1 then
|
||||
self:clear_store(category)
|
||||
self:raise_event('on_store_complete',category,reset_store)
|
||||
return
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if ProgressBar.independent[self.name] then
|
||||
for key,element_data in pairs(ProgressBar.independent[self.name]) do
|
||||
local element = element_data.element
|
||||
if not element or not element.valid then
|
||||
ProgressBar.independent[self.name][key] = nil
|
||||
|
||||
else
|
||||
if not filter or filter(element) then
|
||||
local maximum = element_data.maximum or self.default_maximum or 1
|
||||
element.value = element.value + (amount/maximum)
|
||||
|
||||
if self.count_down and element.value <= 0
|
||||
or not self.count_down and element.value >= 1 then
|
||||
ProgressBar.independent[self.name][key] = nil
|
||||
event_call(self,element)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Increases the value of the progressbar
|
||||
-- @tparam[opt=1] number amount the amount to increase the progressbar by
|
||||
-- @tparam[opt] string category the category that is used with a store
|
||||
function ProgressBar._prototype:increment(amount,category)
|
||||
amount = type(amount) == 'number' and amount or 1
|
||||
change_value_prototype(self,amount,category)
|
||||
end
|
||||
|
||||
--- Increases the value of the progressbar, if the filter condition is met, does not work with store
|
||||
-- @tparam[opt=1] number amount the amount to increase the progressbar by
|
||||
-- @tparam function filter the filter to be used
|
||||
function ProgressBar._prototype:increment_filtered(amount,filter)
|
||||
amount = type(amount) == 'number' and amount or 1
|
||||
change_value_prototype(self,amount,nil,filter)
|
||||
end
|
||||
|
||||
--- Decreases the value of the progressbar
|
||||
-- @tparam[opt=1] number amount the amount to decrease the progressbar by
|
||||
-- @tparam[opt] string category the category that is used with a store
|
||||
function ProgressBar._prototype:decrement(amount,category)
|
||||
amount = type(amount) == 'number' and amount or 1
|
||||
change_value_prototype(self,-amount,category)
|
||||
end
|
||||
|
||||
--- Decreases the value of the progressbar, if the filter condition is met, does not work with store
|
||||
-- @tparam[opt=1] number amount the amount to decrease the progressbar by
|
||||
-- @tparam function filter the filter to be used
|
||||
function ProgressBar._prototype:decrement_filtered(amount,filter)
|
||||
amount = type(amount) == 'number' and amount or 1
|
||||
change_value_prototype(self,-amount,nil,filter)
|
||||
end
|
||||
|
||||
--- Adds an element into the list of instances that will are waiting to complete, does not work with store
|
||||
-- note use store if you want persistent data, this only stores the elements not the values which they have
|
||||
-- @tparam LuaGuiElement element the element that you want to add into the waiting to complete list
|
||||
-- @tparam[opt] number maximum the maximum for this element if not given the default for this define is used
|
||||
function ProgressBar._prototype:add_element(element,maximum)
|
||||
if self.store then return end
|
||||
if not ProgressBar.independent[self.name] then
|
||||
ProgressBar.independent[self.name] = {}
|
||||
end
|
||||
table.insert(ProgressBar.independent[self.name],{
|
||||
element = element,
|
||||
maximum = maximum
|
||||
})
|
||||
end
|
||||
|
||||
--- Resets an element, or its store, to be back at the start, either 1 or 0
|
||||
-- @tparam LuaGuiElement element the element that you want to reset the progress of
|
||||
function ProgressBar._prototype:reset_element(element)
|
||||
if not element or not element.valid then return end
|
||||
local value = self.count_down and 1 or 0
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
self:set_store(category,value)
|
||||
else
|
||||
element.value = value
|
||||
end
|
||||
end
|
||||
|
||||
--- Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented
|
||||
-- @tparam[opt] function filter when given will use filtered increment
|
||||
-- @treturn function the event handler
|
||||
function ProgressBar._prototype:event_counter(filter)
|
||||
if type(filter) == 'function' then
|
||||
return function()
|
||||
self:increment_filtered(1,filter)
|
||||
end
|
||||
else
|
||||
return function()
|
||||
self:increment()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented
|
||||
-- @tparam[opt] function filter when given will use filtered decrement
|
||||
-- @treturn function the event handler
|
||||
function ProgressBar._prototype:event_countdown(filter)
|
||||
if type(filter) == 'function' then
|
||||
return function()
|
||||
self:decrement_filtered(1,filter)
|
||||
end
|
||||
else
|
||||
return function()
|
||||
self:decrement()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ProgressBar
|
||||
177
expcore/gui/elements/slider.lua
Normal file
177
expcore/gui/elements/slider.lua
Normal file
@@ -0,0 +1,177 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Sliders.
|
||||
-- Gui class define for sliders
|
||||
-- @section sliders
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
Slider.new_slider(name) --- Creates a new slider element define
|
||||
|
||||
Slider._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Slider._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Slider._prototype:set_range(min,max) --- Sets the range of a slider, if not used will use default values for a slider
|
||||
Slider._prototype:draw_label(element) --- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player
|
||||
Slider._prototype:enable_auto_draw_label(state) --- Enables auto draw of the label, the label will share the same parent element as the slider
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
--- Event call for on_value_changed and store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam number value the new value for the slider
|
||||
local function event_call(define,element,value)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
local min,max = element.get_slider_minimum(),element.get_slider_maximum()
|
||||
local delta = max-min
|
||||
local percent = delta == 0 and 0 or (value-min)/delta
|
||||
|
||||
define:raise_event('on_element_update',player,element,value,percent)
|
||||
|
||||
local category = player.name
|
||||
if define.categorize then
|
||||
category = define.categorize(element)
|
||||
end
|
||||
|
||||
Instances.unregistered_get_elements(define.name..'-label',category,function(label)
|
||||
label.caption = tostring(math.round(value,2))
|
||||
end)
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam number value the new value for the slider
|
||||
local function store_update(define,element,value)
|
||||
element.slider_value = value
|
||||
event_call(define,element,value)
|
||||
end
|
||||
|
||||
local Slider = {
|
||||
_prototype=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new slider element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new slider element define
|
||||
function Slider.new_slider(name)
|
||||
|
||||
local self = Gui.new_define(Slider._prototype,name)
|
||||
self.draw_data.type = 'slider'
|
||||
|
||||
self:on_draw(function(player,element)
|
||||
local min,max = element.get_slider_minimum(),element.get_slider_maximum()
|
||||
|
||||
if type(self.min) == 'function' then
|
||||
min = self.min(player,element)
|
||||
end
|
||||
|
||||
if type(self.max) == 'function' then
|
||||
max = self.max(player,element)
|
||||
end
|
||||
|
||||
element.set_slider_minimum_maximum(min,max)
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local value = self:get_store(category)
|
||||
if value then element.slider_value = value end
|
||||
end
|
||||
|
||||
if self.auto_label then
|
||||
self:draw_label(element.parent)
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.on_value_changed(self.name,function(event)
|
||||
local element = event.element
|
||||
local value = element.slider_value
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
self:set_store(category,value)
|
||||
|
||||
else
|
||||
event_call(self,element,value)
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the range of a slider, if not used will use default values for a slider
|
||||
-- @tparam[opt] number min the minimum value that the slider can take
|
||||
-- @tparam[opt] number max the maximum value that the slider can take
|
||||
-- @treturn self the define to allow chaining
|
||||
function Slider._prototype:set_range(min,max)
|
||||
self.min = min
|
||||
self.max = max
|
||||
|
||||
if type(min) == 'number' then
|
||||
self.draw_data.minimum_value = min
|
||||
end
|
||||
|
||||
if type(max) == 'number' then
|
||||
self.draw_data.maximum_value = max
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player
|
||||
-- @tparam LuaGuiElement element the parent element that the label will be drawn to
|
||||
-- @treturn LuaGuiElement the new label element so that styles can be applied
|
||||
function Slider._prototype:draw_label(element)
|
||||
local name = self.name..'-label'
|
||||
if element[name] then return end
|
||||
|
||||
local value = 0
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
value = self:get_store(category) or 0
|
||||
end
|
||||
|
||||
local new_element = element.add{
|
||||
name=name,
|
||||
type='label',
|
||||
caption=tostring(math.round(value,2))
|
||||
}
|
||||
|
||||
local categorise = self.categorise or Gui.categorize_by_player
|
||||
local category = categorise(new_element)
|
||||
|
||||
Instances.unregistered_add_element(name,category,new_element)
|
||||
|
||||
return new_element
|
||||
end
|
||||
|
||||
--- Enables auto draw of the label, the label will share the same parent element as the slider
|
||||
-- @tparam[opt=true] boolean state when false will disable the auto draw of the label
|
||||
-- @treturn self the define to allow chaining
|
||||
function Slider._prototype:enable_auto_draw_label(state)
|
||||
if state == false then
|
||||
self.auto_label = false
|
||||
else
|
||||
self.auto_label = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
return Slider
|
||||
149
expcore/gui/elements/text.lua
Normal file
149
expcore/gui/elements/text.lua
Normal file
@@ -0,0 +1,149 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Text.
|
||||
-- Gui class define for text fields and text boxes
|
||||
-- @section text
|
||||
|
||||
--[[
|
||||
>>>> Functions
|
||||
Text.new_text_field(name) --- Creates a new text field element define
|
||||
Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
|
||||
Text.new_text_box(name) --- Creates a new text box element define
|
||||
Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates
|
||||
Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates
|
||||
Text._prototype_box:set_selectable(state) --- Sets the text box to be selectable
|
||||
Text._prototype_box:set_word_wrap(state) --- Sets the text box to have word wrap
|
||||
Text._prototype_box:set_read_only(state) --- Sets the text box to be read only
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core
|
||||
local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam table define the define that this is acting on
|
||||
-- @tparam LuaGuiElement element the element that triggered the event
|
||||
-- @tparam string value the new text for the text field
|
||||
local function store_update(define,element,value)
|
||||
element.text = value
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
define:raise_event('on_element_update',player,element,value)
|
||||
end
|
||||
|
||||
local Text = {
|
||||
_prototype_field=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
},
|
||||
_prototype_box=Prototype.extend{
|
||||
on_element_update = Prototype.event,
|
||||
on_store_update = Prototype.event,
|
||||
add_store = Prototype.store(false,store_update),
|
||||
add_sync_store = Prototype.store(true,store_update)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new text field element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new text field element define
|
||||
function Text.new_text_field(name)
|
||||
|
||||
local self = Gui.new_define(Text._prototype_field,name)
|
||||
self.draw_data.type = 'textfield'
|
||||
|
||||
self:on_draw(function(player,element)
|
||||
if self.selectable then
|
||||
element.selectable = true
|
||||
end
|
||||
|
||||
if self.word_wrap then
|
||||
element.word_wrap = true
|
||||
end
|
||||
|
||||
if self.read_only then
|
||||
element.read_only = true
|
||||
end
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local value = self:get_store(category)
|
||||
if value then element.text = value end
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.on_text_changed(self.name,function(event)
|
||||
local element = event.element
|
||||
local value = element.text
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
self:set_store(category,value)
|
||||
|
||||
else
|
||||
self:raise_event('on_element_update',event.player,element,value)
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new text box element define
|
||||
-- @tparam[opt] string name the optional debug name that can be added
|
||||
-- @treturn table the new text box element define
|
||||
function Text.new_text_box(name)
|
||||
local self = Text.new_text_field(name)
|
||||
self.draw_data.type = 'text-box'
|
||||
|
||||
local mt = getmetatable(self)
|
||||
mt.__index = Text._prototype_box
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the text box to be selectable
|
||||
-- @tparam[opt=true] boolean state when false will set the state to false
|
||||
-- @treturn self table the define to allow for chaining
|
||||
function Text._prototype_box:set_selectable(state)
|
||||
if state == false then
|
||||
self.selectable = false
|
||||
else
|
||||
self.selectable = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the text box to have word wrap
|
||||
-- @tparam[opt=true] boolean state when false will set the state to false
|
||||
-- @treturn self table the define to allow for chaining
|
||||
function Text._prototype_box:set_word_wrap(state)
|
||||
if state == false then
|
||||
self.word_wrap = false
|
||||
else
|
||||
self.word_wrap = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the text box to be read only
|
||||
-- @tparam[opt=true] boolean state when false will set the state to false
|
||||
-- @treturn self table the define to allow for chaining
|
||||
function Text._prototype_box:set_read_only(state)
|
||||
if state == false then
|
||||
self.read_only = false
|
||||
else
|
||||
self.read_only = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
return Text
|
||||
235
expcore/gui/instances.lua
Normal file
235
expcore/gui/instances.lua
Normal file
@@ -0,0 +1,235 @@
|
||||
--[[-- Core Module - Gui
|
||||
@module Gui
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Instances.
|
||||
-- This file is a breakout from core which forcues on instance management of defines
|
||||
-- @section instances
|
||||
|
||||
--[[
|
||||
>>>> Using registered instance groups
|
||||
The main use of this module is to register a group of elements referred here as "instances of an element define" in which
|
||||
is meant that you define the name of a group of drawn elements that are really just multiple versions of a single element.
|
||||
For example this might be that you have one label in multiple places (either for one player or many) and you want to update
|
||||
the caption of all of them at once; this is where this module comes it.
|
||||
|
||||
First you must register the way that the instances are stored and under what name, using Instances.register you will give the
|
||||
name of the collective group of instances followed by an optional categorise function which allows variants to be stored under one
|
||||
name (like one for each force or player)
|
||||
|
||||
-- categorise works in the same way as store categorise
|
||||
-- so the function will world here but no value is stored only gui elements
|
||||
Instances.register('score',Gui.categorize_by_force)
|
||||
|
||||
Then when you draw the new element to a gui you will want to add the element to the group:
|
||||
|
||||
Instances.add_element('score',new_element)
|
||||
|
||||
Then when you want to get the instances you have two options; Instances.get_elements or Instances.apply_to_elements when you want loop
|
||||
over the elements it is more efficient to use apply_to_elements:
|
||||
|
||||
Instances.get_elements('score','player') -- returns all elements that were added with the 'player' category
|
||||
Instances.apply_to_elements('score','player',function(element) -- runs the function on every valid element
|
||||
element.caption = 0
|
||||
end)
|
||||
|
||||
Note that if you don't give a categorise function then you don't need to give a category when getting the elements.
|
||||
|
||||
>>>> Using unregistered instance groups
|
||||
When using a registered group and the functions that go with them it is much simpler to use and more importantly includes error checking
|
||||
for valid instance group names; the down side is that the group must be registered which can only be done during start-up and not during runtime.
|
||||
To counter this there are two functions similar to those above in order to add and get instances but may lead to errors not being noticed due to
|
||||
the error internal error checking being skipped to allow it to work.
|
||||
|
||||
The main difference between the two groups of functions is that the category must always be present even if is nil; example below shows how a
|
||||
instance group would work when registered vs unregistered:
|
||||
|
||||
-- Registered with category
|
||||
Instances.register('score',Gui.categorize_by_force) -- force_store will return the force name of an element
|
||||
Instances.add_element('score',new_element) -- the new element is added to the category based on in force
|
||||
Instances.apply_to_elements('score','player',function(element)
|
||||
element.caption = '0'
|
||||
end) -- gets all instances from the player force and sets the caption to 0
|
||||
|
||||
-- Unregistered with category
|
||||
Instances.unregistered_add_element('score','player',new_element) -- adds the new element to the player category
|
||||
Instances.unregistered_apply_to_elements('score','player',function(element)
|
||||
element.caption = '0'
|
||||
end) -- gets all instances from the player force and sets the caption to 0
|
||||
|
||||
-- Registered without category; note that category can just be ignored
|
||||
Instances.register('score') -- all instances will be under one group with no categories
|
||||
Instances.add_element('score',new_element) -- adds the new element to the instance list
|
||||
Instances.apply_to_elements('score',function(element)
|
||||
element.caption = '0'
|
||||
end) -- gets all instances and sets the element caption to 0
|
||||
|
||||
-- Unregistered without category; note that category must be given as nil
|
||||
Instances.unregistered_add_element('score',nil,new_element) -- adds the new element to a single group with no categories
|
||||
Instances.unregistered_apply_to_elements('score',nil,function(element)
|
||||
element.caption = '0'
|
||||
end) -- gets all instances and sets the element caption to 0
|
||||
|
||||
>>>> Functions
|
||||
Instances.has_categories(name) --- Returns if a instance group has a categorise function; must be registered
|
||||
Instances.is_registered(name) --- Returns if the given name is a registered instance group
|
||||
Instances.register(name,categorise) --- Registers the name of an instance group to allow for storing element instances
|
||||
|
||||
Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered
|
||||
Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered
|
||||
Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid
|
||||
|
||||
Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered
|
||||
Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered
|
||||
]]
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
|
||||
local Instances = {
|
||||
categorise={},
|
||||
data={}
|
||||
}
|
||||
Global.register(Instances.data,function(tbl)
|
||||
Instances.data = tbl
|
||||
end)
|
||||
|
||||
--- Returns if a instance group has a categorise function; must be registered
|
||||
-- @tparam string name the name of the instance group
|
||||
-- @treturn boolean true if there is a categorise function
|
||||
function Instances.has_categories(name)
|
||||
return type(Instances.categorise[name]) == 'function'
|
||||
end
|
||||
|
||||
--- Returns if the given name is a registered instance group
|
||||
-- @tparam string name the name of the instance group you are testing
|
||||
-- @treturn boolean true if the name is registered
|
||||
function Instances.is_registered(name)
|
||||
return Instances.categorise[name] ~= nil
|
||||
end
|
||||
|
||||
--- Registers the name of an instance group to allow for storing element instances
|
||||
-- @tparam string name the name of the instance group; must to unique
|
||||
-- @tparam[opt] function categorise function used to turn the element into a string
|
||||
-- categorise param - element LuaGuiElement - the gui element to be turned into a string
|
||||
-- categorise return - string - the category that the element will be added to like the player's name or force's name
|
||||
-- @treturn string the name that was added so it can be used as a variable
|
||||
function Instances.register(name,categorise)
|
||||
if _LIFECYCLE ~= _STAGE.control then
|
||||
return error('Can only be called during the control stage', 2)
|
||||
end
|
||||
|
||||
if Instances.categorise[name] then
|
||||
return error('Instances for '..name..' already exist.',2)
|
||||
end
|
||||
|
||||
categorise = type(categorise) == 'function' and categorise or true
|
||||
|
||||
Instances.data[name] = {}
|
||||
Instances.categorise[name] = categorise
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
--- Adds an element to the instance group under the correct category; must be registered
|
||||
-- @tparam string name the name of the instance group to add the element to
|
||||
-- @tparam LuaGuiElement element the element to add the the instance group
|
||||
function Instances.add_element(name,element)
|
||||
if not Instances.categorise[name] then
|
||||
return error('Invalid name for instance group: '..name,2)
|
||||
end
|
||||
|
||||
if Instances.has_categories(name) then
|
||||
local category = Instances.categorise[name](element)
|
||||
if not Instances.data[name][category] then Instances.data[name][category] = {} end
|
||||
table.insert(Instances.data[name][category],element)
|
||||
else
|
||||
table.insert(Instances.data[name],element)
|
||||
end
|
||||
end
|
||||
|
||||
--- Gets all element instances without first removing any invalid ones; used internally and must be registered
|
||||
-- @tparam string name the name of the instance group to get the instances of
|
||||
-- @tparam[opt] string category the category to get the instance from, not needed when no categorise function
|
||||
-- @treturn table the table of element instances of which some may be invalid
|
||||
function Instances.get_elements_raw(name,category)
|
||||
if not Instances.categorise[name] then
|
||||
return error('Invalid name for instance group: '..name,2)
|
||||
end
|
||||
|
||||
if Instances.has_categories(name) then
|
||||
return Instances.data[name][category] or {}
|
||||
else
|
||||
return Instances.data[name]
|
||||
end
|
||||
end
|
||||
|
||||
--- Gets all valid element instances and has the option of running a callback on those that are valid
|
||||
-- @tparam string name the name of the instance group to get the instances of
|
||||
-- @tparam[opt] string category the category to get the instances of, not needed when no categorise function
|
||||
-- @tparam[opt] function callback when given the callback will be ran on all valid elements
|
||||
-- callback param - element LuaGuiElement - the current valid element
|
||||
-- @treturn table the table of element instances with all invalid ones removed
|
||||
function Instances.get_valid_elements(name,category,callback)
|
||||
if not Instances.categorise[name] then
|
||||
return error('Invalid name for instance group: '..name,2)
|
||||
end
|
||||
|
||||
category = category or callback
|
||||
local elements = Instances.get_elements_raw(name,category)
|
||||
local categorise = Instances.has_categories(name)
|
||||
|
||||
for key,element in pairs(elements) do
|
||||
if not element or not element.valid then
|
||||
elements[key] = nil
|
||||
else
|
||||
if categorise and callback then callback(element)
|
||||
elseif category then category(element) end
|
||||
end
|
||||
end
|
||||
|
||||
return elements
|
||||
end
|
||||
Instances.get_elements = Instances.get_valid_elements
|
||||
Instances.apply_to_elements = Instances.get_valid_elements
|
||||
|
||||
--- A version of add_element that does not require the group to be registered
|
||||
-- @tparam string name the name of the instance group to add the element to
|
||||
-- @tparam ?string|nil category the category to add the element to, can be nil but must still be given
|
||||
-- @tparam LuaGuiElement element the element to add to the instance group
|
||||
function Instances.unregistered_add_element(name,category,element)
|
||||
if not Instances.data[name] then Instances.data[name] = {} end
|
||||
if category then
|
||||
if not Instances.data[name][category] then Instances.data[name][category] = {} end
|
||||
table.insert(Instances.data[name][category],element)
|
||||
else
|
||||
table.insert(Instances.data[name],element)
|
||||
end
|
||||
end
|
||||
|
||||
--- A version of get_elements that does not require the group to be registered
|
||||
-- @tparam string name the name of the instance group to get the instances of
|
||||
-- @tparam ?string|nil category the category to get the instances of, can be nil but must still be given
|
||||
-- @tparam[opt] function callback when given will be called on all valid instances
|
||||
-- callback param - element LuaGuiElement - the current valid element
|
||||
-- @treturn table the table of element instances with all invalid ones removed
|
||||
function Instances.unregistered_get_elements(name,category,callback)
|
||||
local elements = Instances.data[name]
|
||||
if elements and category then
|
||||
elements = elements[category]
|
||||
end
|
||||
|
||||
if not elements then return {} end
|
||||
|
||||
for key,element in pairs(elements) do
|
||||
if not element or not element.valid then
|
||||
elements[key] = nil
|
||||
else
|
||||
if callback then callback(element) end
|
||||
end
|
||||
end
|
||||
|
||||
return elements
|
||||
end
|
||||
Instances.unregistered_apply_to_elements = Instances.runtime_get_elements
|
||||
|
||||
return Instances
|
||||
@@ -3,721 +3,309 @@
|
||||
@alias Prototype
|
||||
]]
|
||||
|
||||
--- Concept Base.
|
||||
-- Functions that are used to make concepts
|
||||
-- @section concept-base
|
||||
--- Prototype.
|
||||
-- Used to create new gui prototypes see elements and concepts
|
||||
-- @section prototype
|
||||
|
||||
local Event = require 'utils.event' -- @dep utils.event
|
||||
local Store = require 'expcore.store' -- @dep expcore.store
|
||||
local Game = require 'utils.game' -- @dep utils.game
|
||||
local Token = require 'utils.token' -- @dep utils.token
|
||||
--[[
|
||||
>>>> Functions
|
||||
Constructor.event(event_name) --- Creates a new function to add functions to an event handler
|
||||
Constructor.extend(new_prototype) --- Extents a prototype with the base functions of all gui prototypes, no metatables
|
||||
Constructor.store(sync,callback) --- Creates a new function which adds a store to a gui define
|
||||
Constructor.setter(value_type,key,second_key) --- Creates a setter function that checks the type when a value is set
|
||||
|
||||
local Factorio_Events = {}
|
||||
local Prototype = {
|
||||
draw_callbacks = {},
|
||||
clone_callbacks = {},
|
||||
properties = {},
|
||||
factorio_events = {},
|
||||
events = {}
|
||||
}
|
||||
Prototype:uid() --- Gets the uid for the element define
|
||||
Prototype:debug_name(value) --- Sets a debug alias for the define
|
||||
Prototype:set_caption(value) --- Sets the caption for the element define
|
||||
Prototype:set_tooltip(value) --- Sets the tooltip for the element define
|
||||
Prototype:set_style(style,callback) --- Sets the style for the element define
|
||||
Prototype:set_embedded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function
|
||||
|
||||
--- Acts as a gernal handler for any factorio event
|
||||
local function factorio_event_handler(event)
|
||||
local element = event.element
|
||||
local rasied_event = event.name
|
||||
local factorio_event_concepts = Factorio_Events[rasied_event]
|
||||
if element then
|
||||
if not element.valid then return end
|
||||
local concept = factorio_event_concepts[element.name]
|
||||
if concept then
|
||||
for event_name, factorio_event in pairs(concept.factorio_events) do
|
||||
if rasied_event == factorio_event then
|
||||
concept:raise_event(event_name,event,true)
|
||||
end
|
||||
end
|
||||
Prototype:set_pre_authenticator --- Sets an authenticator that blocks the draw function if check fails
|
||||
Prototype:set_post_authenticator --- Sets an authenticator that disables the element if check fails
|
||||
|
||||
Prototype:raise_event(event_name,...) --- Raises a custom event for this define, any number of params can be given
|
||||
Prototype:draw_to(element,...) --- The main function for defines, when called will draw an instance of this define to the given element
|
||||
|
||||
Prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used
|
||||
Prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used
|
||||
Prototype:clear_store(category) --- Sets the value in this elements store to nil, category needed if categorize function used
|
||||
]]
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local Store = require 'expcore.store' --- @dep expcore.store
|
||||
local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances
|
||||
|
||||
local Constructor = {}
|
||||
local Prototype = {}
|
||||
|
||||
--- Creates a new function to add functions to an event handler
|
||||
-- @tparam string event_name the name of the event that callbacks will be added to
|
||||
-- @treturn function the function used to register handlers
|
||||
function Constructor.event(event_name)
|
||||
--- Adds a callback as a handler for an event
|
||||
-- @tparam table self the gui define being acted on
|
||||
-- @tparam function callback the function that will be added as a handler for the event
|
||||
-- @treturn table self returned to allowing chaining of functions
|
||||
return function(self,callback)
|
||||
if type(callback) ~= 'function' then
|
||||
return error('Event callback for '..event_name..' must be a function',2)
|
||||
end
|
||||
|
||||
else
|
||||
for _,concept in pairs(factorio_event_concepts) do
|
||||
for event_name, factorio_event in pairs(concept.factorio_events) do
|
||||
if rasied_event == factorio_event then
|
||||
concept:raise_event(event_name,event,true)
|
||||
end
|
||||
end
|
||||
local handlers = self.events[event_name]
|
||||
if not handlers then
|
||||
handlers = {}
|
||||
self.events[event_name] = handlers
|
||||
end
|
||||
|
||||
handlers[#handlers+1] = callback
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Used to copy all the settings from one concept to another and removing links to the orginal
|
||||
@tparam string concept_name the name of the new concept; must be unique
|
||||
@treturn GuiConcept the base for building a custom gui
|
||||
@usage-- Clones the base Button concept to make a alternative button
|
||||
local custom_button =
|
||||
Gui.get_concept(Gui.concepts.button):clone()
|
||||
]]
|
||||
function Prototype:clone()
|
||||
local concept = table.deep_copy(self)
|
||||
|
||||
-- Replace name of the concept
|
||||
local uid = tostring(Token.uid())
|
||||
concept.name = uid
|
||||
concept.debug_name = uid
|
||||
concept.properties.name = uid
|
||||
|
||||
-- Remove all event handlers that were copied
|
||||
concept.events = {}
|
||||
for event_name,_ in pairs(self.events) do
|
||||
concept.events[event_name] = {}
|
||||
end
|
||||
|
||||
-- Remakes even handlers for factorio
|
||||
for _,factorio_event in pairs(concept.factorio_events) do
|
||||
Factorio_Events[factorio_event][concept.name] = concept
|
||||
end
|
||||
|
||||
-- Remove all refrences to an instance store
|
||||
if concept.instance_store then
|
||||
concept.instance_store = nil
|
||||
concept.get_instances = nil
|
||||
concept.add_instance = nil
|
||||
concept.update_instances = nil
|
||||
end
|
||||
|
||||
-- Remove all refrences to a data store
|
||||
if concept.data_store then
|
||||
concept.data_store = nil
|
||||
concept.get_data = nil
|
||||
concept.set_data = nil
|
||||
concept.clear_data = nil
|
||||
concept.update_data = nil
|
||||
concept.on_data_store_update = nil
|
||||
concept.events.on_data_store_update = nil
|
||||
end
|
||||
|
||||
-- Remove all refrences to a combined store
|
||||
if concept.sync_instance then
|
||||
concept.sync_instance = nil
|
||||
concept.set_store_from_instance = nil
|
||||
end
|
||||
|
||||
-- Loop over all the clone defines, element is updated when a value is returned
|
||||
for _,clone_callback in pairs(concept.clone_callbacks) do
|
||||
local success, rtn = pcall(clone_callback,concept)
|
||||
if not success then
|
||||
error('Gui clone handler error with '..concept.debug_name..':\n\t'..rtn)
|
||||
end
|
||||
end
|
||||
|
||||
return concept
|
||||
end
|
||||
|
||||
--[[-- Use to add your own callbacks to the clone function, for example adding to a local table
|
||||
@tparam function clone_callback the function which is called with the concept to have something done to it
|
||||
@treturn table self to allow chaining
|
||||
@usage-- Adding concept to a local table
|
||||
local buttons = {}
|
||||
local button =
|
||||
Gui.get_concept('Button')
|
||||
:define_clone(function(concept)
|
||||
buttons[concept.name] = concept
|
||||
end)
|
||||
]]
|
||||
function Prototype:define_clone(clone_callback)
|
||||
-- Check that it is a function that is being added
|
||||
if type(clone_callback) ~= 'function' then
|
||||
error('Draw define must be a function',2)
|
||||
end
|
||||
|
||||
-- Add the draw function
|
||||
self.clone_callbacks[#self.clone_callbacks+1] = clone_callback
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Used to save the concept to the main gui module to allow access from other files
|
||||
@function Prototype:save_as
|
||||
@tparam string save_name the new name of the concept
|
||||
@usage-- Save a concept to allow access in another file
|
||||
button:save_as('button')
|
||||
@usage-- Access concept after being saved
|
||||
Gui.concepts.button
|
||||
Gui.get_concept('button')
|
||||
]]
|
||||
function Prototype:save_as(save_name)
|
||||
-- over writen in core file
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Sets a debug name that can be used with error handlers
|
||||
@tparam string name the name that will be used in error messages
|
||||
@treturn self to allow chaining
|
||||
@usage-- Set the debug name
|
||||
unsaved_concept:debug('Example button')
|
||||
]]
|
||||
function Prototype:debug(name)
|
||||
self.debug_name = name
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Adds a new event trigger to the concept which can be linked to a factorio event
|
||||
@tparam string event_name the name of the event to add, must be unique, recomented to start with "on_"
|
||||
@tparam[opt] defines.events factorio_event when given will fire the custom event when the factorio event is raised
|
||||
@tparam[opt] function event_condition used to filter when a factorio event triggers the custom event; if the event contains a reference to an element then names are automatically filtered
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:new_event(event_name,factorio_event,event_condition)
|
||||
-- Check the event does not already exist
|
||||
if self.events[event_name] then
|
||||
error('Event is already defined',2)
|
||||
end
|
||||
|
||||
--[[-- Adds a custom event handler, replace with the name of the event
|
||||
@function Prototype:on_custom_event
|
||||
@tparam function handler the function which will recive the event
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
|
||||
-- Adds a handler table and the event handler adder, comment above not indented to look better in docs
|
||||
self.events[event_name] = {}
|
||||
self[event_name] = function(concept,handler)
|
||||
if type(handler) ~= 'function' then
|
||||
error('Event handler must be a function',2)
|
||||
end
|
||||
|
||||
local handlers = concept.events[event_name]
|
||||
handlers[#handlers+1] = handler
|
||||
|
||||
return concept
|
||||
end
|
||||
|
||||
-- Adds the factorio event handler if this event is linked to one
|
||||
if factorio_event then
|
||||
self.factorio_events[event_name] = factorio_event
|
||||
self.events[event_name].factorio_event_condition = event_condition
|
||||
|
||||
local factorio_event_concepts = Factorio_Events[factorio_event]
|
||||
if not factorio_event_concepts then
|
||||
factorio_event_concepts = {}
|
||||
Factorio_Events[factorio_event] = factorio_event_concepts
|
||||
Event.add(factorio_event,factorio_event_handler)
|
||||
end
|
||||
|
||||
if not factorio_event_concepts[self.name] then
|
||||
factorio_event_concepts[self.name] = self
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Raises a custom event, folowing keys included automaticlly: concept, event name, game tick, player from player_index, element if valid
|
||||
@tparam string event_name the name of the event that you want to raise
|
||||
@tparam[opt={}] table event table containg data you want to send with the event, some keys already included
|
||||
@tparam[opt=false] boolean from_factorio internal use, if the raise came from the factorio event handler
|
||||
@usage-- 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
|
||||
})
|
||||
]]
|
||||
function Prototype:raise_event(event_name,event,from_factorio)
|
||||
-- Check that the event exists
|
||||
if not self.events[event_name] then
|
||||
error('Event is not defined',2)
|
||||
end
|
||||
|
||||
-- Setup the event table with automatic keys
|
||||
event = event or {}
|
||||
event.concept = self
|
||||
event.name = event.name or event_name
|
||||
event.tick = event.tick or game.tick
|
||||
event.player = event.player_index and Game.get_player_by_index(event.player_index) or nil
|
||||
if event.element and not event.element.valid then return end
|
||||
|
||||
-- Get the event handlers
|
||||
local handlers = self.events[event_name]
|
||||
|
||||
-- If it is from factorio and the filter fails
|
||||
if from_factorio and handlers.factorio_event_condition and not handlers.factorio_event_condition(event) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Trigger every handler
|
||||
for _,handler in ipairs(handlers) do
|
||||
local success, err = pcall(handler,event)
|
||||
if not success then
|
||||
error('Gui event handler error with '..self.debug_name..'/'..event_name..':\n\t'..err)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Adds a new property to the concept, such as caption, tooltip, or some custom property you want to control
|
||||
@tparam string property_name the name of the new property, must be unique
|
||||
@tparam[opt] function setter_callback this function is called when set is called, if not provided then key in concept.properties is updated to new value
|
||||
@tparam[opt] any default use this as the default value, will call the setter callback if defined
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:new_property(property_name,setter_callback,default,...)
|
||||
-- Check that the property does not already exist
|
||||
if self.properties[property_name] then
|
||||
error('Property is already defined',2)
|
||||
end
|
||||
|
||||
-- Check that setter is a function if present
|
||||
if setter_callback and not type(setter_callback) == 'function' then
|
||||
error('Setter callback must be a function')
|
||||
end
|
||||
|
||||
--[[-- Sets a new value for a property, triggers setter method if provided, replace with property name
|
||||
@function Prototype:set_custom_property
|
||||
@tparam any value the value that you want to set for this property
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- Setting the caption on the base button concept after a cloning
|
||||
local custom_button =
|
||||
Gui.get_concept('Button')
|
||||
:set_caption('Default Button')
|
||||
@usage-- 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')
|
||||
]]
|
||||
|
||||
self['set_'..property_name] = function(concept,value,...)
|
||||
if setter_callback then
|
||||
-- Call the setter method to update values if present
|
||||
local success, err = pcall(setter_callback,concept.properties,value,...)
|
||||
if not success then
|
||||
error('Gui property handler error with '..concept.debug_name..'/'..property_name..':\n\t'..err)
|
||||
end
|
||||
--- Extents a prototype with the base functions of all gui prototypes, no metatables
|
||||
-- @tparam table new_prototype the prototype that you want to add the functions to
|
||||
-- @treturn table the same prototype but with the new functions added
|
||||
function Constructor.extend(new_prototype)
|
||||
for key,value in pairs(Prototype) do
|
||||
if type(value) == 'table' then
|
||||
new_prototype[key] = table.deepcopy(value)
|
||||
else
|
||||
-- Otherwise just update the key
|
||||
concept.properties[property_name] = value
|
||||
end
|
||||
|
||||
return concept
|
||||
end
|
||||
|
||||
-- If a default value if given then set the default value
|
||||
if default ~= nil then
|
||||
self['set_'..property_name](self,default,...)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Used to define how the concept is turned into an ingame element or "instance" as we may refer to them
|
||||
@tparam function draw_callback the function that will be called to draw/update the instance; this function must return the instance or the new acting instance
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:define_draw(draw_callback)
|
||||
-- Check that it is a function that is being added
|
||||
if type(draw_callback) ~= 'function' then
|
||||
error('Draw define must be a function',2)
|
||||
end
|
||||
|
||||
-- Add the draw function
|
||||
self.draw_callbacks[#self.draw_callbacks+1] = draw_callback
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[ Used to define a draw callback that is ran before any other draw callbacks, see define_draw
|
||||
@tparam function draw_callback the function that will be called to draw/update the instance; this function must return the instance or the new acting instance
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- Placing a button into a flow
|
||||
local button =
|
||||
Gui.get_concept('Button')
|
||||
:define_pre_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
|
||||
parent = parent.add{
|
||||
type = 'flow'
|
||||
}
|
||||
|
||||
-- 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)
|
||||
]]
|
||||
function Prototype:define_pre_draw(draw_callback)
|
||||
-- Check that it is a function that is being added
|
||||
if type(draw_callback) ~= 'function' then
|
||||
error('Draw define must be a function',2)
|
||||
end
|
||||
|
||||
-- Add the draw function
|
||||
table.insert(self.draw_callbacks,1,draw_callback)
|
||||
|
||||
return self
|
||||
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
|
||||
@tparam LuaGuiElement parent_element the element that the concept will use as a base
|
||||
@tparam[opt] string override_name when given this will be the name of the element rather than the concept id
|
||||
@treturn LuaGuiElement the element that was created and then passed though and returned by the draw functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:draw(parent_element,override_name,...)
|
||||
local old_name = self.properties.name
|
||||
local parent = parent_element
|
||||
local element
|
||||
|
||||
if override_name then self.properties.name = override_name end
|
||||
-- Loop over all the draw defines, element is updated when a value is returned
|
||||
for _,draw_callback in pairs(self.draw_callbacks) do
|
||||
local success, _element, _parent = pcall(draw_callback,self.properties,parent,element,...)
|
||||
if success then
|
||||
if _element then element = _element end
|
||||
if _parent then parent = _parent end
|
||||
elseif not success then
|
||||
self.properties.name = old_name
|
||||
error('Gui draw handler error with '..self.debug_name..':\n\t'.._element)
|
||||
new_prototype[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
-- Return the name back to its previous value
|
||||
self.properties.name = old_name
|
||||
|
||||
-- Adds the instance if instance store is used
|
||||
if self.add_instance then
|
||||
self.add_instance(element)
|
||||
end
|
||||
|
||||
-- Syncs the instance if there is a combined store
|
||||
if self.sync_instance then
|
||||
self.sync_instance(element)
|
||||
end
|
||||
|
||||
return element
|
||||
end
|
||||
|
||||
--- Concept Instances.
|
||||
-- Functions that are used to make store concept instances
|
||||
-- @section concept-instances
|
||||
|
||||
--[[-- Adds an instance store to the concept; when a new instance is made it is stored so you can access it later
|
||||
@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:define_instance_store(category_callback)
|
||||
self.instance_store = Store.register('gui_instances_'..self.name)
|
||||
|
||||
local valid_category = category_callback and type(category_callback) == 'function'
|
||||
local function get_category(category)
|
||||
if type(category) == 'table' and type(category.__self) == 'userdata' then
|
||||
return valid_category and category_callback(category) or nil
|
||||
else
|
||||
return category
|
||||
for key,value in pairs(new_prototype) do
|
||||
if value == Constructor.event then
|
||||
new_prototype[key] = Constructor.event(key)
|
||||
end
|
||||
end
|
||||
return new_prototype
|
||||
end
|
||||
|
||||
--[[-- Gets all insatnces in a category, category may be nil to return all
|
||||
@function Prototype.get_instances
|
||||
@tparam[opt] ?string|LuaGuiElement category the category to get, can only be nil if categories are not used
|
||||
@treturn table a table which contains all the instances
|
||||
@usage-- Getting all the instances of the player with index 1
|
||||
local custom_button =
|
||||
Gui.get_concept('CustomButton')
|
||||
--- Creates a new function which adds a store to a gui define
|
||||
-- @tparam boolean sync if the function should create a synced store
|
||||
-- @tparam function callback the function called when needing to update the value of an element
|
||||
-- @treturn function the function that will add a store for this define
|
||||
function Constructor.store(sync,callback)
|
||||
--- Adds a store for the define that is shared between all instances of the define in the same category, categorize is a function that returns a string
|
||||
-- @tparam self table the gui define being acted on
|
||||
-- @tparam[opt] string location a unique location identifier, when omitted a uid location will be used, use when sync is set to true
|
||||
-- @tparam[opt] function categorize function used to determine the category of a LuaGuiElement, when omitted all share one single category
|
||||
-- categorize param - LuaGuiElement element - the element that needs to be converted
|
||||
-- categorize return - string - a deterministic string that references to a category such as player name or force name
|
||||
-- @treturn self the element define to allow chaining
|
||||
return function(self,location,categorize)
|
||||
if self.store then return end
|
||||
|
||||
custom_button.get_instances(1) -- player index 1
|
||||
]]
|
||||
function self.get_instances(category)
|
||||
return Store.get(self.instance_store,get_category(category))
|
||||
end
|
||||
if not sync then
|
||||
categorize = location
|
||||
location = Store.uid_location()
|
||||
end
|
||||
|
||||
--[[-- Adds an instance to this concept, used automatically during concept:draw
|
||||
@function Prototype.add_instance
|
||||
@tparam LuaGuiElement element the element that will be added as an instance
|
||||
@tparam[opt] string category the category to add this element under, if nil the category callback is used to assign one
|
||||
@usage-- Adding an element as a instance for this concept, mostly for internal use
|
||||
local custom_button =
|
||||
Gui.get_concept('CustomButton')
|
||||
if Store.is_registered(location) then
|
||||
return error('Location for store is already registered: '..location,2)
|
||||
end
|
||||
|
||||
custom_button.add_instance(element) -- normally not needed due to use in concept:draw
|
||||
]]
|
||||
function self.add_instance(element,category)
|
||||
category = category or get_category(element)
|
||||
if not valid_category then category = nil end
|
||||
return Store.update(self.instance_store,category,function(tbl)
|
||||
if type(tbl) ~= 'table' then
|
||||
return {element}
|
||||
else
|
||||
table.insert(tbl,element)
|
||||
self.store = location
|
||||
self.categorize = categorize
|
||||
|
||||
Instances.register(self.name,self.categorize)
|
||||
|
||||
Store.register(self.store,sync,function(value,category)
|
||||
self:raise_event('on_store_update',value,category)
|
||||
|
||||
if Instances.is_registered(self.name) then
|
||||
Instances.apply_to_elements(self.name,category,function(element)
|
||||
callback(self,element,value)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[-- Applies an update function to all instances, simialr use to what table.forEach would be
|
||||
@function Prototype.update_instances
|
||||
@tparam[opt] ?string|LuaGuiElement category the category to get, can only be nil if categories are not used
|
||||
@tparam function update_callback the function which is called on each instance, recives other args passed to update_instances
|
||||
@usage-- 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)
|
||||
]]
|
||||
function self.update_instances(category,update_callback,...)
|
||||
local args
|
||||
if type(category) == 'function' then
|
||||
args = {update_callback,...}
|
||||
update_callback = category
|
||||
category = nil
|
||||
end
|
||||
|
||||
local instances = Store.get(self.instance_store,get_category(category)) or {}
|
||||
for key,instance in pairs(instances) do
|
||||
if not instance or not instance.valid then
|
||||
instances[key] = nil
|
||||
|
||||
else
|
||||
if args then
|
||||
update_callback(instance,unpack(args))
|
||||
else
|
||||
update_callback(instance,...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Concept Data.
|
||||
-- Functions that are used to store concept data
|
||||
-- @section concept-data
|
||||
--- Creates a setter function that checks the type when a value is set
|
||||
-- @tparam string value_type the type that the value should be when it is set
|
||||
-- @tparam string key the key of the define that will be set
|
||||
-- @tparam[opt] string second_key allows for setting of a key in a sub table
|
||||
-- @treturn function the function that will check the type and set the value
|
||||
function Constructor.setter(value_type,key,second_key)
|
||||
local display_message = 'Gui define '..key..' must be of type '..value_type
|
||||
if second_key then
|
||||
display_message = 'Gui define '..second_key..' must be of type '..value_type
|
||||
end
|
||||
|
||||
--[[-- Adds a data store to this concept which allows you to store synced/percistent data between instances
|
||||
@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:define_data_store(category_callback)
|
||||
self:new_event('on_data_store_update')
|
||||
self.data_store = Store.register('gui_data_'..self.name,function(value,key)
|
||||
self:raise_event('on_data_store_update',{
|
||||
category = key,
|
||||
value = value
|
||||
})
|
||||
end)
|
||||
local locale = false
|
||||
if value_type == 'locale-string' then
|
||||
locale = true
|
||||
value_type = 'table'
|
||||
end
|
||||
|
||||
local valid_category = category_callback and type(category_callback) == 'function'
|
||||
local function get_category(category)
|
||||
if type(category) == 'table' and type(category.__self) == 'userdata' then
|
||||
return valid_category and category_callback(category) or nil
|
||||
return function(self,value)
|
||||
local v_type = type(value)
|
||||
if v_type ~= value_type and (not locale or v_type ~= 'string') then
|
||||
error(display_message,2)
|
||||
end
|
||||
|
||||
if second_key then
|
||||
self[key][second_key] = value
|
||||
else
|
||||
return category
|
||||
self[key] = value
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
--- Gets the uid for the element define
|
||||
-- @treturn string the uid of this element define
|
||||
function Prototype:uid()
|
||||
return self.name
|
||||
end
|
||||
|
||||
--- Sets a debug alias for the define
|
||||
-- @tparam string name the debug name for the element define that can be used to get this element define
|
||||
-- @treturn self the element define to allow chaining
|
||||
Prototype.debug_name = Constructor.setter('string','debug_name')
|
||||
|
||||
--- Sets the caption for the element define
|
||||
-- @tparam string caption the caption that will be drawn with the element
|
||||
-- @treturn self the element define to allow chaining
|
||||
Prototype.set_caption = Constructor.setter('locale-string','draw_data','caption')
|
||||
|
||||
--- Sets the tooltip for the element define
|
||||
-- @tparam string tooltip the tooltip that will be displayed for this element when drawn
|
||||
-- @treturn self the element define to allow chaining
|
||||
Prototype.set_tooltip = Constructor.setter('locale-string','draw_data','tooltip')
|
||||
|
||||
--- Sets an authenticator that blocks the draw function if check fails
|
||||
-- @tparam function callback the function that will be ran to test if the element should be drawn or not
|
||||
-- callback param - LuaPlayer player - the player that the element is being drawn to
|
||||
-- callback param - string define_name - the name of the define that is being drawn
|
||||
-- callback return - boolean - false will stop the element from being drawn
|
||||
-- @treturn self the element define to allow chaining
|
||||
Prototype.set_pre_authenticator = Constructor.setter('function','pre_authenticator')
|
||||
|
||||
--- Sets an authenticator that disables the element if check fails
|
||||
-- @tparam function callback the function that will be ran to test if the element should be enabled or not
|
||||
-- callback param - LuaPlayer player - the player that the element is being drawn to
|
||||
-- callback param - string define_name - the name of the define that is being drawn
|
||||
-- callback return - boolean - false will disable the element
|
||||
-- @treturn self the element define to allow chaining
|
||||
Prototype.set_post_authenticator = Constructor.setter('function','post_authenticator')
|
||||
|
||||
--- Registers a callback to the on_draw event
|
||||
-- @tparam function callback
|
||||
-- callback param - LuaPlayer player - the player that the element was drawn to
|
||||
-- callback param - LuaGuiElement element - the element that was drawn
|
||||
-- callback param - any ... - any other params passed by the draw_to function
|
||||
Prototype.on_draw = Constructor.event('on_draw')
|
||||
|
||||
--- Registers a callback to the on_style_update event
|
||||
-- @tparam function callback
|
||||
-- callback param - LuaStyle style - the style that was changed and/or needs changing
|
||||
Prototype.on_style_update = Constructor.event('on_style_update')
|
||||
|
||||
--- Sets the style for the element define
|
||||
-- @tparam string style the style that will be used for this element when drawn
|
||||
-- @tparam[opt] function callback function is called when element is drawn to alter its style
|
||||
-- @treturn self the element define to allow chaining
|
||||
function Prototype:set_style(style,callback)
|
||||
self.draw_data.style = style
|
||||
if callback then
|
||||
self:on_style_update(callback)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the element to be drawn inside a nameless flow, can be given a name using a function
|
||||
-- @tparam ?boolean|function state when true a padless flow is created to contain the element
|
||||
-- @treturn self the element define to allow chaining
|
||||
function Prototype:set_embedded_flow(state)
|
||||
if state == false or type(state) == 'function' then
|
||||
self.embedded_flow = state
|
||||
else
|
||||
self.embedded_flow = true
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
--- Raises a custom event for this define, any number of params can be given
|
||||
-- @tparam string event_name the name of the event that you want to raise
|
||||
-- @tparam any ... any params that you want to pass to the event
|
||||
-- @treturn number the number of handlers that were registered
|
||||
function Prototype:raise_event(event_name,...)
|
||||
local handlers = self.events[event_name]
|
||||
if handlers then
|
||||
for _,handler in pairs(handlers) do
|
||||
handler(...)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Gets the data that is stored for this category
|
||||
@function Prototype.get_data
|
||||
@tparam[opt] ?string|LuaGuiElement category the category to get, can only be nil if categories are not used
|
||||
@treturn any the data that you had stored in this location
|
||||
@usage-- Getting the stored data for player 1
|
||||
local custom_button =
|
||||
Gui.get_concept('CustomButton')
|
||||
|
||||
custom_button.get_data(1) -- player index 1
|
||||
]]
|
||||
function self.get_data(category)
|
||||
return Store.get(self.data_store,get_category(category))
|
||||
end
|
||||
|
||||
--[[-- Sets the data that is stored for this category
|
||||
@function Prototype.set_data
|
||||
@tparam[opt] ?string|LuaGuiElement category the category to set, can only be nil if categories are not used
|
||||
@tparam any value the data that you want to stored in this location
|
||||
@usage-- 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
|
||||
]]
|
||||
function self.set_data(category,value)
|
||||
return Store.set(self.data_store,get_category(category),value)
|
||||
end
|
||||
|
||||
--[[-- Clears the data that is stored for this category
|
||||
@function Prototype.clear_data
|
||||
@tparam[opt] ?string|LuaGuiElement category the category to clear, can only be nil if categories are not used
|
||||
@usage-- Clearing the data for player 1
|
||||
local custom_button =
|
||||
Gui.get_concept('CustomButton')
|
||||
|
||||
custom_button.clear_data(1) -- player index 1
|
||||
]]
|
||||
function self.clear_data(category)
|
||||
return Store.clear(self.data_store,get_category(category))
|
||||
end
|
||||
|
||||
--[[-- Updates the data that is stored for this category
|
||||
@function Prototype.update_data
|
||||
@tparam[opt] ?string|LuaGuiElement category the category to clear, can only be nil if categories are not used
|
||||
@tparam function update_callback the function which is called to update the data
|
||||
@usage-- 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
|
||||
|
||||
@usage-- 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
|
||||
]]
|
||||
function self.update_data(category,update_callback,...)
|
||||
return Store.update(self.data_store,get_category(category),update_callback,...)
|
||||
end
|
||||
|
||||
return self
|
||||
return handlers and #handlers or 0
|
||||
end
|
||||
|
||||
--- Concept Combined Instances.
|
||||
-- Functions that are used to make store concept instances and data
|
||||
-- @section concept-instances
|
||||
--- The main function for defines, when called will draw an instance of this define to the given element
|
||||
-- what is drawn is based on the data in draw_data which is set using other functions
|
||||
-- @tparam LuaGuiElement element the element that the define will draw a instance of its self onto
|
||||
-- @treturn LuaGuiElement the new element that was drawn
|
||||
function Prototype:draw_to(element,...)
|
||||
local name = self.name
|
||||
if element[name] then return end
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
--[[-- 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
|
||||
@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap
|
||||
@tparam function sync_callback the function which is called to update an instance to match the store, this is called on all instances when concept.set_data or update_data is used
|
||||
@treturn GuiConcept to allow chaining of functions
|
||||
@usage-- 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)
|
||||
]]
|
||||
function Prototype:define_combined_store(category_callback,sync_callback)
|
||||
if sync_callback == nil then
|
||||
sync_callback = category_callback
|
||||
category_callback = nil
|
||||
if self.pre_authenticator then
|
||||
if not self.pre_authenticator(player,self.name) then return end
|
||||
end
|
||||
|
||||
self:define_data_store(category_callback)
|
||||
self:define_instance_store(category_callback)
|
||||
|
||||
-- Will update all instances when the data store updates
|
||||
self:on_data_store_update(function(event)
|
||||
self.update_instances(event.category,sync_callback,event.value)
|
||||
end)
|
||||
|
||||
--[[-- Will sync an instance to match the stored value based on the given sync callback
|
||||
@function Prototype.sync_instance
|
||||
@tparam LuaGuiElement element the element that you want to have update
|
||||
@usage-- 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)
|
||||
]]
|
||||
local properties = self.properties
|
||||
function self.sync_instance(element)
|
||||
local default = properties.default
|
||||
local value = self.get_data(element) or type(default) == 'function' and default(element) or default
|
||||
sync_callback(element,value)
|
||||
if self.embedded_flow then
|
||||
local embedded_name
|
||||
if type(self.embedded_flow) == 'function' then
|
||||
embedded_name = self.embedded_flow(element,...)
|
||||
end
|
||||
element = element.add{type='flow',name=embedded_name}
|
||||
element.style.padding = 0
|
||||
end
|
||||
|
||||
return self
|
||||
local new_element = element.add(self.draw_data)
|
||||
|
||||
self:raise_event('on_style_update',new_element.style)
|
||||
|
||||
if self.post_authenticator then
|
||||
new_element.enabled = self.post_authenticator(player,self.name)
|
||||
end
|
||||
|
||||
if Instances.is_registered(self.name) then
|
||||
Instances.add_element(self.name,new_element)
|
||||
end
|
||||
|
||||
self:raise_event('on_draw',player,new_element)
|
||||
|
||||
return new_element
|
||||
end
|
||||
|
||||
return Prototype
|
||||
--- Gets the value in this elements store, category needed if categorize function used
|
||||
-- @tparam string category[opt] the category to get such as player name or force name
|
||||
-- @treturn any the value that is stored for this define
|
||||
function Prototype:get_store(category)
|
||||
if not self.store then return end
|
||||
return Store.get(self.store,category)
|
||||
end
|
||||
|
||||
--- Sets the value in this elements store, category needed if categorize function used
|
||||
-- @tparam string category[opt] the category to get such as player name or force name
|
||||
-- @tparam any value the value to set for this define, must be valid for its type ie for checkbox etc
|
||||
-- @treturn boolean true if the value was set
|
||||
function Prototype:set_store(category,value)
|
||||
if not self.store then return end
|
||||
return Store.set(self.store,category,value)
|
||||
end
|
||||
|
||||
--- Sets the value in this elements store to nil, category needed if categorize function used
|
||||
-- @tparam[opt] string category the category to get such as player name or force name
|
||||
-- @treturn boolean true if the value was set
|
||||
function Prototype:clear_store(category)
|
||||
if not self.store then return end
|
||||
return Store.clear(self.store,category)
|
||||
end
|
||||
|
||||
return Constructor
|
||||
@@ -1,49 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@core ExpStyle
|
||||
@alias expstyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'flow' -- @dep gui.concept.flow
|
||||
|
||||
--[[-- A flow which can be used to align text and other elements
|
||||
@see Gui.flow
|
||||
@element alignment
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [alignment] - the alignment area
|
||||
Gui.new_concept('alignment')
|
||||
:set_horizontal_align('center')
|
||||
]]
|
||||
|
||||
Gui.new_concept('flow')
|
||||
:save_as('alignment')
|
||||
|
||||
:new_property('horizontal_align',nil,'right')
|
||||
:new_property('vertical_align',nil,'center')
|
||||
:new_property('width')
|
||||
:new_property('height')
|
||||
|
||||
:define_draw(function(properties,parent,element)
|
||||
local style = element.style
|
||||
Gui.set_padding(element,1,1,2,2)
|
||||
|
||||
-- Set the alignment of the flow
|
||||
style.horizontal_align = properties.horizontal_align
|
||||
style.vertical_align = properties.vertical_align
|
||||
|
||||
-- Set the stretchablity based on the alignment
|
||||
style.horizontally_stretchable = style.horizontal_align ~= 'center'
|
||||
style.vertically_stretchable = style.vertical_align ~= 'center'
|
||||
|
||||
-- Set the width if given
|
||||
local width = properties.width
|
||||
if width then style.width = width end
|
||||
|
||||
-- Set the hieght if given
|
||||
local height = properties.height
|
||||
if height then style.height = height end
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,37 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'frame' -- @dep gui.concept.frame
|
||||
|
||||
--[[-- A container frame that can be used to add a boader around your content
|
||||
@see Gui.frame
|
||||
@element container
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [container] - the outer frame
|
||||
-->> container - the content area
|
||||
Gui.new_concept('container')
|
||||
]]
|
||||
|
||||
Gui.new_concept('frame')
|
||||
:save_as('container')
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the outter frame padding
|
||||
element.style.padding = 2
|
||||
|
||||
-- Add the inner frame
|
||||
element = element.add{
|
||||
name = 'container',
|
||||
type = 'frame',
|
||||
direction = properties.direction,
|
||||
style = 'window_content_frame_packed'
|
||||
}
|
||||
|
||||
-- Update the inner frame padding
|
||||
element.style.padding = 0
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,101 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'label' -- @dep gui.concept.frame
|
||||
|
||||
local right_align =
|
||||
Gui.new_concept('alignment')
|
||||
|
||||
--[[-- A label pair which has a static label and a data label which can be changed
|
||||
@see Gui.label
|
||||
@element data_label
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [data_label] - the static label
|
||||
--> [properties.data_name] - the data label which can be updated
|
||||
Gui.new_concept('data_label')
|
||||
:set_data_label_name('game_ticks')
|
||||
:set_data_caption('0')
|
||||
:set_data_format(function(concept,element,data,...)
|
||||
-- This is used with update_data_element and update_from_parent
|
||||
local caption = tostirng('data')
|
||||
local tooltip = 'This game has beeing running for: '..caption..' ticks'
|
||||
return caption, tooltip
|
||||
end)
|
||||
]]
|
||||
|
||||
local data_label =
|
||||
Gui.new_concept('label')
|
||||
:save_as('data_label')
|
||||
:new_property('data_label_name')
|
||||
:new_property('data_caption')
|
||||
:new_property('data_tooltip')
|
||||
:new_property('data_format',nil,function(concept,element,data,...)
|
||||
return tostring(data)
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Make the label right aligned
|
||||
local data_name = properties.data_label_name or properties.name..'_data'
|
||||
local right_align_element = right_align:draw(parent,data_name)
|
||||
|
||||
-- Add a new label
|
||||
local data_label_element =
|
||||
right_align_element.add{
|
||||
name = 'data_label'
|
||||
}
|
||||
|
||||
-- Get the data caption
|
||||
local caption = Gui.resolve_property(properties.data_caption,element)
|
||||
if caption then
|
||||
data_label_element.caption = caption
|
||||
end
|
||||
|
||||
-- Get the data tooltip
|
||||
local tooltip = Gui.resolve_property(properties.data_tooltip,element)
|
||||
if tooltip then
|
||||
data_label_element.tooltip = tooltip
|
||||
end
|
||||
|
||||
return data_label_element
|
||||
end)
|
||||
|
||||
--[[-- Updates the caption and tooltip of the data label using the data format function
|
||||
@tparam LuaGuiElement element the data label element that you want to update
|
||||
@tparam any data the data that you want to pass to the format function
|
||||
@usage-- Updating the data to the current game tick
|
||||
data_label:update_data_element(element,game.tick)
|
||||
]]
|
||||
function data_label:update_data_element(element,data,...)
|
||||
local caption, tooltip = self.properties.data_format(self,element,data,...)
|
||||
if caption then
|
||||
element.caption = caption
|
||||
end
|
||||
if tooltip then
|
||||
element.tooltip = tooltip
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Updates the caption and tooltip of the data label using the data format function, given the parent of the data label
|
||||
@tparam LuaGuiElement parent the parent element to the data label element that you want to update
|
||||
@tparam any data the data that you want to pass to the format function
|
||||
@usage-- Updating the data to the current game tick
|
||||
data_label:update_from_parent(parent,game.tick)
|
||||
]]
|
||||
function data_label:update_from_parent(parent,data,...)
|
||||
local properties = self.properties
|
||||
local data_name = properties.data_label_name or properties.name..'_data'
|
||||
local element = parent[data_name] and parent[data_name].data_label or error('Data label is not a child of this element element',2)
|
||||
|
||||
local caption, tooltip = properties.data_format(self,element,data,...)
|
||||
if caption then
|
||||
element.caption = caption
|
||||
end
|
||||
if tooltip then
|
||||
element.tooltip = tooltip
|
||||
end
|
||||
end
|
||||
@@ -1,54 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'frame' -- @dep gui.concept.table
|
||||
|
||||
local right_align =
|
||||
Gui.new_concept('alignment')
|
||||
|
||||
--[[-- A frame that acts as a footer to a section of content
|
||||
@see Gui.frame
|
||||
@element footer
|
||||
@tparam string tooltip the tooltip to show on the title
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [footer] - the footer frame
|
||||
-->> footer_caption - the lable with the title in it
|
||||
-->> footer_content - the area to contain butons
|
||||
Gui.new_concept('footer')
|
||||
:set_title('Example Footer')
|
||||
]]
|
||||
|
||||
Gui.new_concept('frame')
|
||||
:save_as('footer')
|
||||
:new_property('tooltip')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the table style
|
||||
Gui.set_padding(element,2,2,4,4)
|
||||
element.style = 'subfooter_frame'
|
||||
element.caption = ''
|
||||
|
||||
local style = element.style
|
||||
style.horizontally_stretchable = true
|
||||
style.use_header_filler = false
|
||||
|
||||
-- Add the caption to the frame
|
||||
if properties.title then
|
||||
element.add{
|
||||
type = 'label',
|
||||
name = 'footer_caption',
|
||||
caption = properties.title,
|
||||
tooltip = properties.tooltip
|
||||
}
|
||||
end
|
||||
|
||||
-- Add the right align area
|
||||
local align = right_align:draw(element,'footer_content')
|
||||
|
||||
return align
|
||||
end)
|
||||
@@ -1,52 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'frame' -- @dep gui.concept.table
|
||||
|
||||
local right_align =
|
||||
Gui.new_concept('alignment')
|
||||
|
||||
--[[-- A frame that acts as a header to a section of content
|
||||
@see Gui.frame
|
||||
@element header
|
||||
@tparam string tooltip the tooltip to show on the title
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [header] - the header frame
|
||||
-->> header_caption - the lable with the title in it
|
||||
-->> header_content - the area to contain butons
|
||||
Gui.new_concept('header')
|
||||
:set_title('Example Header')
|
||||
]]
|
||||
|
||||
Gui.new_concept('frame')
|
||||
:save_as('header')
|
||||
:new_property('tooltip')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the table style
|
||||
Gui.set_padding(element,2,2,4,4)
|
||||
element.style = 'subheader_frame'
|
||||
element.caption = nil
|
||||
|
||||
local style = element.style
|
||||
style.horizontally_stretchable = true
|
||||
style.use_header_filler = false
|
||||
|
||||
-- Add the caption to the frame
|
||||
element.add{
|
||||
type = 'label',
|
||||
name = 'header_caption',
|
||||
caption = properties.title,
|
||||
tooltip = properties.tooltip
|
||||
}
|
||||
|
||||
-- Add the right align area
|
||||
local align = right_align:draw(element,'header_content')
|
||||
|
||||
return align
|
||||
end)
|
||||
@@ -1,28 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
@alias expstyle
|
||||
]]
|
||||
|
||||
--- @dep expcore.gui
|
||||
|
||||
--- @dep gui.concept.frame
|
||||
|
||||
--- @dep gui.concept.flow
|
||||
|
||||
--- @dep gui.concept.table
|
||||
|
||||
--- @dep gui.concept.scroll
|
||||
|
||||
local function r(name)
|
||||
require('expcore.gui.styles.expstyle.'..name)
|
||||
end
|
||||
|
||||
r 'container'
|
||||
r 'alignment'
|
||||
r 'header'
|
||||
r 'footer'
|
||||
r 'scroll_table'
|
||||
r 'time_label'
|
||||
r 'data_label'
|
||||
r 'unit_label'
|
||||
r 'toggle_button'
|
||||
@@ -1,60 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'table' -- @dep gui.concept.table
|
||||
Gui.require_concept 'scroll' -- @dep gui.concept.scroll
|
||||
|
||||
local scroll_area =
|
||||
Gui.new_concept('scroll')
|
||||
:set_vertical_scroll('auto-and-reserve-space')
|
||||
:set_horizontal_scroll('never')
|
||||
|
||||
--[[-- A table that is inside a vertical scroll area
|
||||
@see Gui.table
|
||||
@element scroll_table
|
||||
@tparam number hight the max hight of the scroll area
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [scroll_table] - the scroll area
|
||||
-->> table - the table area
|
||||
Gui.new_concept('scroll_table')
|
||||
:set_height(200)
|
||||
:set_column_count(2)
|
||||
]]
|
||||
|
||||
Gui.new_concept('table')
|
||||
:save_as('scroll_table')
|
||||
:new_property('height',nil,100)
|
||||
|
||||
-- Add a scroll before the table is drawn
|
||||
:define_pre_draw(function(properties,parent,element)
|
||||
local scroll = scroll_area:draw(parent,properties.name)
|
||||
|
||||
-- Set the scroll style
|
||||
Gui.set_padding(scroll,1,1,2,2)
|
||||
scroll.style.horizontally_stretchable = true
|
||||
scroll.style.maximal_height = properties.height
|
||||
|
||||
-- Change the name of the element to table before it is drawn
|
||||
properties.name = 'table'
|
||||
|
||||
return element, scroll
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the table style
|
||||
local style = element.style
|
||||
style.padding = 0
|
||||
style.horizontally_stretchable = true
|
||||
style.vertical_align = 'center'
|
||||
style.cell_padding = 0
|
||||
|
||||
-- Change the stored name back to the actual name
|
||||
properties.name = element.parent.name
|
||||
|
||||
return element
|
||||
end)
|
||||
@@ -1,92 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common
|
||||
|
||||
--- Converts a tick into string format with workds and symbols
|
||||
local function get_format(properties,time)
|
||||
local caption, tooltip
|
||||
|
||||
-- Check if a custom format is wanted
|
||||
if properties.time_format then
|
||||
-- Get the caption
|
||||
local format = table.deep_copy(properties.time_format)
|
||||
caption = format_time(time,format)
|
||||
|
||||
-- Get the tooltip, always long format
|
||||
format.long = true
|
||||
tooltip = format_time(time,format)
|
||||
|
||||
else
|
||||
-- Get the caption
|
||||
caption = format_time(time,{
|
||||
hours = properties.use_hours,
|
||||
minutes = true,
|
||||
seconds = true
|
||||
})
|
||||
|
||||
-- Get the tooltip, same as the caption but long format
|
||||
tooltip = format_time(time,{
|
||||
hours = properties.use_hours,
|
||||
minutes = true,
|
||||
seconds = true,
|
||||
long = true
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
return caption, tooltip
|
||||
end
|
||||
|
||||
--[[-- A label that show time in a nice, user friendly way
|
||||
@element time_label
|
||||
@tparam number time the time to display in tick
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [time_label] - the label with the time
|
||||
local time_label =
|
||||
Gui.new_concept('time_label')
|
||||
:set_use_hours(true)
|
||||
:set_time(game.tick)
|
||||
|
||||
time_label:update_time(element,game.tick)
|
||||
]]
|
||||
|
||||
local time_label =
|
||||
Gui.new_concept()
|
||||
:save_as('time_label')
|
||||
|
||||
-- Properties
|
||||
:new_property('time')
|
||||
:new_property('use_hours',nil,false)
|
||||
:new_property('time_format')
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element,time)
|
||||
-- Get the caption and tooltip
|
||||
local caption, tooltip = get_format(properties,time or properties.time)
|
||||
|
||||
-- Draw a label
|
||||
element = parent.add{
|
||||
name = properties.name,
|
||||
type = 'label',
|
||||
caption = caption,
|
||||
tooltip = tooltip
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
|
||||
--[[-- Updates the time that is on a label
|
||||
@tparam LuaGuiElement element the label that you want to update
|
||||
@tparam number time the number of tick you want it to show
|
||||
@usage-- Update the time to show game time
|
||||
time_label:update_time(element,game.time)
|
||||
]]
|
||||
function time_label:update_time(element,time)
|
||||
local caption, tooltip = get_format(self.properties,time)
|
||||
element.caption = caption
|
||||
element.tooltip = tooltip
|
||||
end
|
||||
@@ -1,49 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
Gui.require_concept 'button' -- @dep gui.concept.table
|
||||
|
||||
--[[-- A button that will toggle its caption each time it is pressed
|
||||
@see Gui.button
|
||||
@element toggle_button
|
||||
@tparam string alt_caption the caption to show on the button in its true state
|
||||
@tparam string alt_tooltip the tooltip to show on the button in its true state
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [toggle_button] - the header button
|
||||
Gui.new_concept('toggle_button')
|
||||
:set_caption('<')
|
||||
:set_tooltip('Press to close.')
|
||||
:set_alt_caption('>')
|
||||
:set_alt_tooltip('Press to open.')
|
||||
:on_click(function(event)
|
||||
local state = event.state and 'close' or 'open'
|
||||
event.player.print('Toggle button is now: '..state)
|
||||
end)
|
||||
]]
|
||||
|
||||
Gui.new_concept('button')
|
||||
:save_as('toggle_button')
|
||||
:new_property('alt_caption')
|
||||
:new_property('alt_tooltip')
|
||||
|
||||
-- Events
|
||||
:on_click(function(event)
|
||||
local concept = event.concept
|
||||
local properties = concept.properties
|
||||
local element = event.element
|
||||
if element.caption == properties.caption then
|
||||
element.caption = properties.alt_caption
|
||||
element.tooltip = properties.alt_tooltip or properties.tooltip
|
||||
event.state = true
|
||||
|
||||
else
|
||||
element.caption = properties.caption
|
||||
element.tooltip = properties.tooltip or properties.alt_tooltip
|
||||
event.state = false
|
||||
|
||||
end
|
||||
end)
|
||||
@@ -1,100 +0,0 @@
|
||||
--[[-- Core Module - ExpStyle
|
||||
@module ExpStyle
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' -- @dep expcore.gui
|
||||
|
||||
--[[-- A label triplet which has a static label, a data label which can be changed, and a unit label
|
||||
@see Gui.label
|
||||
@see data_label
|
||||
@element unit_label
|
||||
@usage-- Concept Structure
|
||||
-- Root
|
||||
--> [unit_label] - the static label
|
||||
--> [properties.data_name] - the data label which can be updated
|
||||
--> [properties.data_name..'_unit'] - the data label unit which can be updated
|
||||
Gui.new_concept('unit_label')
|
||||
:set_data_label_name('game_ticks')
|
||||
:set_data_caption('0')
|
||||
:set_data_unit('ticks')
|
||||
:set_data_format(function(concept,element,data,...)
|
||||
-- This is used with update_data_element and update_from_parent
|
||||
local caption = tostirng(data)
|
||||
local unit = data > 1 and 'ticks' or 'tick'
|
||||
local tooltip = 'This game has beeing running for: '..caption..' ticks'
|
||||
return caption, unit, tooltip
|
||||
end)
|
||||
]]
|
||||
|
||||
local unit_label =
|
||||
Gui.new_concept('data_label')
|
||||
:save_as('unit_label')
|
||||
:new_property('data_unit')
|
||||
:set_data_format(function(concept,element,data,...)
|
||||
local base_unit = concept.properties.data_unit
|
||||
local caption = tostring(data)
|
||||
local unit = data == 1 and base_unit or base_unit..'s'
|
||||
return caption, unit
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Get the unit data
|
||||
local unit = Gui.resolve_property(properties.data_unit,element)
|
||||
|
||||
-- Add the unit label
|
||||
parent.add{
|
||||
name = element.name..'_unit',
|
||||
type='label',
|
||||
caption = unit or '',
|
||||
tooltip = element.tooltip
|
||||
}
|
||||
|
||||
return element
|
||||
end)
|
||||
|
||||
--[[-- Updates the caption and tooltip and unit of the data label using the data format function
|
||||
@tparam LuaGuiElement element the unit label element that you want to update
|
||||
@tparam any data the data that you want to pass to the format function
|
||||
@usage-- Updating the data to the current game tick
|
||||
unit_label:update_data_element(element,game.tick)
|
||||
]]
|
||||
function unit_label:update_data_element(element,data,...)
|
||||
local caption, unit, tooltip = self.properties.data_format(self,element,data,...)
|
||||
local unit_element = element.parent.parent[element.name..'_unit']
|
||||
if caption then
|
||||
element.caption = caption
|
||||
end
|
||||
if tooltip then
|
||||
element.tooltip = tooltip
|
||||
unit_element.tooltip = tooltip
|
||||
end
|
||||
if unit then
|
||||
unit_element.caption = unit
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Updates the caption and tooltip and unit of the unit label using the data format function, given the parent of the unit label
|
||||
@tparam LuaGuiElement parent the parent element to the unit label element that you want to update
|
||||
@tparam any data the data that you want to pass to the format function
|
||||
@usage-- Updating the data to the current game tick
|
||||
unit_label:update_from_parent(parent,game.tick)
|
||||
]]
|
||||
function unit_label:update_from_parent(parent,data,...)
|
||||
local properties = self.properties
|
||||
local data_name = properties.data_label_name or properties.name..'_data'
|
||||
local element = parent[data_name] and parent[data_name].data_label or error('Data label is not a child of this element element',2)
|
||||
local unit_element = parent[data_name..'_unit']
|
||||
|
||||
local caption, unit, tooltip = properties.data_format(self,element,data,...)
|
||||
if caption then
|
||||
element.caption = caption
|
||||
end
|
||||
if tooltip then
|
||||
element.tooltip = tooltip
|
||||
unit_element.tooltip = tooltip
|
||||
end
|
||||
if unit then
|
||||
unit_element.caption = unit
|
||||
end
|
||||
end
|
||||
1158
expcore/gui/test.lua
1158
expcore/gui/test.lua
File diff suppressed because it is too large
Load Diff
@@ -1,493 +0,0 @@
|
||||
--[[-- Core Module - Toolbar
|
||||
@core Toolbar
|
||||
@alias Toolbar
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui' --- @dep expcore.gui
|
||||
local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
|
||||
Gui.require_concept('button') --- @dep Gui.concept.button
|
||||
|
||||
local toolbar_toggle_concept
|
||||
local toolbar_hide_concept
|
||||
local toolbar_concept
|
||||
local Toolbar = {
|
||||
button_concepts = {},
|
||||
frame_concepts = {},
|
||||
permissions = {}
|
||||
}
|
||||
|
||||
Gui.Toolbar = Toolbar
|
||||
|
||||
--- Permissions.
|
||||
-- Functions to do with deciding which player can do what
|
||||
-- @section permissions
|
||||
|
||||
--[[-- Used to test if a player is allowed to use a button on the toolbar, if you are not using expcore.roles then change this function
|
||||
@tparam LuaPlayer player the player you want ot test is allowed to use this button
|
||||
@tparam string concept_name the name of the button concept that you want to see if the player is allowed to use
|
||||
@treturn boolean true if the player is allowed to use it
|
||||
@usage-- Test if a player can use 'test-player-list'
|
||||
local allowed = Toolbar.allowed(game.player,'test-player-list')
|
||||
]]
|
||||
function Toolbar.allowed(player,concept_name)
|
||||
local permission = Toolbar.permissions[concept_name] or concept_name
|
||||
return Roles.player_allowed(player,permission)
|
||||
end
|
||||
|
||||
--[[-- Use to add an alias for the allowed test, alias is what is tested for rather than the concept name
|
||||
@tparam string concept_name the name of the concept that will point to this alias
|
||||
@tparam string alias the permission string that will be tested when this concept is used with Toolbar.allowed
|
||||
@usage-- Adding an alias for the 'test-player-list' concept
|
||||
Toolbar.set_permission_alias('test-player-list','gui/player-list')
|
||||
]]
|
||||
function Toolbar.set_permission_alias(concept_name,alias)
|
||||
Toolbar.permissions[concept_name] = alias
|
||||
end
|
||||
|
||||
--- Buttons.
|
||||
-- All function to do with the toolbar buttons
|
||||
-- @section buttons
|
||||
|
||||
--[[-- Adds a concept to be drawn to the button area and allows it to be toggled with the toggle toolbar button
|
||||
@tparam table concept the gui concept that you want to add to the button area
|
||||
@usage-- Adding a basic button to the toolbar
|
||||
local new_button =
|
||||
Gui.new_concept('button')
|
||||
:set_caption('Click Me')
|
||||
:on_click(function(event)
|
||||
event.player.print('You Clicked Me!!')
|
||||
end)
|
||||
|
||||
Toolbar.add_button_concept(new_button)
|
||||
]]
|
||||
function Toolbar.add_button_concept(concept)
|
||||
local concepts = Toolbar.button_concepts
|
||||
concepts[#concepts+1] = concept
|
||||
end
|
||||
|
||||
--[[-- Updates all the buttons for a player, this means hide and show buttons based on permissions
|
||||
@tparam LuaPlayer player the player to update the toolbar buttons for
|
||||
@usage-- Updating your toolbar
|
||||
Toolbar.update_buttons(player)
|
||||
]]
|
||||
function Toolbar.update_buttons(player)
|
||||
toolbar_concept:raise_event('on_button_update',{
|
||||
player_index = player.index
|
||||
})
|
||||
end
|
||||
|
||||
--[[-- Returns an array of buttons names that the given player is able to see, returns none if toolbar hidden
|
||||
@tparam LuaPlayer player the player you want to get the visible buttons of
|
||||
@treturn table an array of names of the visible buttons
|
||||
@usage-- Get a list of all your visible buttons
|
||||
Toolbar.get_visible_buttons(game.player)
|
||||
]]
|
||||
function Toolbar.get_visible_buttons(player)
|
||||
local rtn = {}
|
||||
local top_flow = mod_gui.get_button_flow(player)
|
||||
|
||||
for _,concept in pairs(Toolbar.button_concepts) do
|
||||
local element = top_flow[concept.name]
|
||||
if element.visible then
|
||||
rtn[#rtn+1] = element.name
|
||||
end
|
||||
end
|
||||
|
||||
return rtn
|
||||
end
|
||||
|
||||
--[[-- The base element to be used with the toolbar, others can be used but this is recomented
|
||||
@element toolbar-button
|
||||
|
||||
@tparam string permission_alias the alias used with Toolbar.allowed
|
||||
|
||||
@usage-- Adding a basic button to the toolbar, note no need to call Toolbar.add_button_concept
|
||||
Gui.new_concept('toolbar-button')
|
||||
:set_caption('Click Me')
|
||||
:on_click(function(event)
|
||||
event.player.print('You Clicked Me!!')
|
||||
end)
|
||||
|
||||
]]
|
||||
Toolbar.button =
|
||||
Gui.new_concept('button')
|
||||
:save_as('toolbar-button')
|
||||
|
||||
:new_property('permission_alias',nil,function(properties,value)
|
||||
Toolbar.set_permission_alias(properties.name,value)
|
||||
end)
|
||||
|
||||
:define_clone(Toolbar.add_button_concept)
|
||||
:define_draw(function(properties,parent,element)
|
||||
element.style = mod_gui.button_style
|
||||
end)
|
||||
|
||||
--- Frames.
|
||||
-- Functions to do with the toolbar frames
|
||||
-- @section frames
|
||||
|
||||
--[[-- Adds a frame concept to the toolbar frame area, this will not add a button to the toolbar
|
||||
@tparam table concept the gui concept that you want to add to the toolbar frame area
|
||||
@usage-- Adding a basic frame to the frame area
|
||||
local new_frame =
|
||||
Gui.new_concept('frame')
|
||||
:set_title('Test')
|
||||
|
||||
Toolbar.add_frame_concept(new_frame)
|
||||
]]
|
||||
function Toolbar.add_frame_concept(concept)
|
||||
local concepts = Toolbar.frame_concepts
|
||||
concepts[#concepts+1] = concept
|
||||
end
|
||||
|
||||
--[[-- Hides all the frames for a player
|
||||
@tparam LuaPlayer player the player to hide the frames for
|
||||
@usage-- Hiding all your frames
|
||||
Toolbar.hide_frames(game.player)
|
||||
]]
|
||||
function Toolbar.hide_frames(player)
|
||||
toolbar_concept:raise_event('on_hide_frames',{
|
||||
player_index = player.index
|
||||
})
|
||||
end
|
||||
|
||||
--[[-- Gets an array of the names of all the visible frames for a player
|
||||
@tparam LuaPlayer player the player that you want to get the visible frames of
|
||||
@treturn table an array of names of the visible frames for the given player
|
||||
@usage-- Get all your visible frames
|
||||
Toolbar.get_visible_frames(game.player)
|
||||
]]
|
||||
function Toolbar.get_visible_frames(player)
|
||||
local rtn = {}
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
|
||||
for _,concept in pairs(Toolbar.frame_concepts) do
|
||||
local element = left_flow[concept.name..'-frame']
|
||||
if element.visible then
|
||||
rtn[#rtn+1] = element.name
|
||||
end
|
||||
end
|
||||
|
||||
left_flow[toolbar_hide_concept.name].visible = #rtn > 0
|
||||
|
||||
return rtn
|
||||
end
|
||||
|
||||
--[[-- The base toolbar frame, others can be used but this is recomented
|
||||
@element toolbar-frame
|
||||
|
||||
@param on_update fired when the frame is to have its content updated
|
||||
|
||||
@tparam boolean open_by_default weather the frame should be open when a player first joins
|
||||
@tparam boolean use_container true by default and will place a container inside the frame for content
|
||||
@tparam string direction the direction that the items in the frame are added
|
||||
|
||||
@usage-- Adding a basic player list
|
||||
local player_list =
|
||||
Gui.new_concept('toolbar-frame')
|
||||
:set_permission_alias('player_list')
|
||||
:set_caption('Player List')
|
||||
:toggle_with_click()
|
||||
|
||||
:define_draw(function(properties,parent,element)
|
||||
local list_area =
|
||||
element.add{
|
||||
name = 'scroll',
|
||||
type = 'scroll-pane',
|
||||
direction = 'vertical',
|
||||
horizontal_scroll_policy = 'never',
|
||||
vertical_scroll_policy = 'auto-and-reserve-space'
|
||||
}
|
||||
Gui.set_padding(list_area,1,1,2,2)
|
||||
list_area.style.horizontally_stretchable = true
|
||||
list_area.style.maximal_height = 200
|
||||
|
||||
for _,player in pairs(game.connected_players) do
|
||||
list_area.add{
|
||||
type='label',
|
||||
caption=player.name
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
:on_update(function(event)
|
||||
local list_area = event.element.scroll
|
||||
list_area.clear()
|
||||
|
||||
for _,player in pairs(game.connected_players) do
|
||||
list_area.add{
|
||||
type='label',
|
||||
caption=player.name
|
||||
}
|
||||
end
|
||||
end)
|
||||
|
||||
]]
|
||||
Toolbar.frame =
|
||||
Gui.new_concept('toolbar-button')
|
||||
:save_as('toolbar-frame')
|
||||
|
||||
-- Properties
|
||||
:new_property('open_by_default',nil,false)
|
||||
:new_property('use_container',nil,true)
|
||||
:new_property('direction',nil,'horizontal')
|
||||
:new_event('on_update')
|
||||
|
||||
-- Clone
|
||||
:define_clone(function(concept)
|
||||
Toolbar.add_frame_concept(concept)
|
||||
concept:on_click(function(event)
|
||||
event.concept:toggle_visible_state(event.player)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- Draw
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Add the base frame element, the button is already drawn to parent
|
||||
local player = Gui.get_player_from_element(element)
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
local frame = left_flow.add{
|
||||
name = properties.name..'-frame',
|
||||
type = 'frame',
|
||||
direction = properties.direction
|
||||
}
|
||||
|
||||
frame.style.padding = 2
|
||||
|
||||
if properties.use_container then
|
||||
local container =
|
||||
frame.add{
|
||||
name = 'container',
|
||||
type = 'frame',
|
||||
direction = properties.direction,
|
||||
style = 'window_content_frame_packed'
|
||||
}
|
||||
Gui.set_padding(container)
|
||||
|
||||
return container
|
||||
end
|
||||
|
||||
return frame
|
||||
end)
|
||||
|
||||
--[[-- Gets the content area of the frame concept for this player, each player only has one area
|
||||
@tparam LuaPlayer player the player that you want to get the frame content for
|
||||
@treturn LuaGuiElement the content area of this concept for this player
|
||||
@usage-- Get the content area of a concept
|
||||
local frame = player_list:get_content(game.player)
|
||||
]]
|
||||
function Toolbar.frame:get_content(player)
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
local frame = left_flow[self.name..'-frame']
|
||||
return frame.container or frame
|
||||
end
|
||||
|
||||
--[[-- Toggles the visibilty of this concept for the given player
|
||||
@tparam LuaPlayer player the player that you want to toggle the frame for
|
||||
@treturn boolean the new state of the visibilty of this concept for the player
|
||||
@usage-- Toggle the frame for your self
|
||||
player_list:toggle_visible_state(game.player)
|
||||
]]
|
||||
function Toolbar.frame:toggle_visible_state(player)
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
local frame = left_flow[self.name..'-frame']
|
||||
if frame.visible then
|
||||
frame.visible = false
|
||||
Toolbar.get_visible_frames(player)
|
||||
return false
|
||||
else
|
||||
frame.visible = true
|
||||
Toolbar.get_visible_frames(player)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Gets the current visibilty state of this conept for this player
|
||||
@tparam LuaPlayer player the player that you want the visibilty state for
|
||||
@treturn boolean the current visiblity state of this concept to the player
|
||||
@usage-- Getting the current visiblity state
|
||||
player_list:get_visible_state(player)]]
|
||||
function Toolbar.frame:get_visible_state(player)
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
return left_flow[self.name..'-frame'].visible
|
||||
end
|
||||
|
||||
--[[-- Triggers an update of the content within the concept for this player, uses on_update handlers
|
||||
@tparam LuaPlayer player the player to update the concept content for
|
||||
@tparam[opt] table event the event data that you want to pass to the update handlers
|
||||
@usage-- Updating the frame for your player
|
||||
player_list:update(game.player)
|
||||
]]
|
||||
function Toolbar.frame:update(player,event)
|
||||
event = event or {}
|
||||
event.player_index = player.index
|
||||
event.element = self:get_content(player)
|
||||
self:raise_event('on_update',event)
|
||||
end
|
||||
|
||||
--[[-- Triggers an update of the content with in this frame for all players
|
||||
@tparam[opt] table event the event data that you want to pass to the update handlers
|
||||
@usage-- Update the grame for all players
|
||||
player_list:update_all()
|
||||
]]
|
||||
function Toolbar.frame:update_all(event)
|
||||
local players = event.update_offline == true and game.players or game.connected_players
|
||||
for _,player in pairs(players) do
|
||||
self:update(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Other Elements.
|
||||
-- All the other elements that are used to make this work
|
||||
-- @section elements
|
||||
|
||||
--[[-- The main toolbar element, draws, updates, and controls the other concepts
|
||||
@element toolbar
|
||||
@param on_button_update fired when the buttons are updated for a player
|
||||
@param on_hide_frames fired when the frames are hidden for a player
|
||||
]]
|
||||
toolbar_concept =
|
||||
Gui.new_concept()
|
||||
:debug('toolbar')
|
||||
:define_draw(function(properties,player)
|
||||
-- Get the main flows
|
||||
local top_flow = mod_gui.get_button_flow(player)
|
||||
if not top_flow then return end
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
if not left_flow then return end
|
||||
|
||||
-- Draw toggle buttons first
|
||||
toolbar_toggle_concept:draw(top_flow)
|
||||
toolbar_hide_concept:draw(left_flow)
|
||||
|
||||
-- Draw all the buttons and frames
|
||||
local done = {}
|
||||
for _,concept in pairs(Toolbar.button_concepts) do
|
||||
done[concept.name] = true
|
||||
concept:draw(top_flow)
|
||||
top_flow[concept.name].visible = Toolbar.allowed(player,concept.name)
|
||||
|
||||
local frame = left_flow[concept.name..'-frame']
|
||||
if frame then
|
||||
frame.visible = Gui.resolve_property(concept.properties.open_by_default,frame)
|
||||
end
|
||||
end
|
||||
|
||||
-- Draws frames that did not have buttons
|
||||
for _,concept in pairs(Toolbar.frame_concepts) do
|
||||
if not done[concept.name] then
|
||||
concept:draw(left_flow)
|
||||
local frame = left_flow[concept.name..'-frame']
|
||||
if frame then
|
||||
frame.visible = Gui.resolve_property(concept.properties.open_by_default,frame)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Toggle the clear toobar if needed
|
||||
Toolbar.get_visible_frames(player)
|
||||
|
||||
end)
|
||||
|
||||
-- When the buttons are updated
|
||||
:new_event('on_button_update')
|
||||
:on_button_update(function(event)
|
||||
-- Get the top flow
|
||||
local player = event.player
|
||||
local top_flow = mod_gui.get_button_flow(player)
|
||||
if not top_flow then return end
|
||||
|
||||
-- Set the visiblity of the elements
|
||||
local visible = top_flow[toolbar_toggle_concept.name].caption == '<'
|
||||
for _,concept in pairs(Toolbar.button_concepts) do
|
||||
local element = top_flow[concept.name]
|
||||
if Gui.valid(element) then
|
||||
element.visible = visible and Toolbar.allowed(player,concept.name)
|
||||
end
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
-- When frames are hidden
|
||||
:new_event('on_hide_frames')
|
||||
:on_hide_frames(function(event)
|
||||
-- Get the left flow
|
||||
local player = event.player
|
||||
local left_flow = mod_gui.get_frame_flow(player)
|
||||
if not left_flow then return end
|
||||
|
||||
-- Set the visiblity of the elements
|
||||
left_flow[toolbar_hide_concept.name].visible = false
|
||||
for _,concept in pairs(Toolbar.frame_concepts) do
|
||||
local element = left_flow[concept.name..'-frame']
|
||||
if Gui.valid(element) then element.visible = false end
|
||||
end
|
||||
end)
|
||||
|
||||
--- Used so toggle and hide can have the same look as each other
|
||||
local function toolbar_button_draw(properties,parent,element)
|
||||
element.style = mod_gui.button_style
|
||||
local style = element.style
|
||||
style.width = 18
|
||||
style.height = 36
|
||||
style.padding = 0
|
||||
style.left_padding = 1
|
||||
style.font = 'default-small-bold'
|
||||
end
|
||||
|
||||
--[[-- Button which toggles the the visible state of all toolbar buttons, triggers on_button_update
|
||||
@element toolbar-toggle
|
||||
]]
|
||||
toolbar_toggle_concept =
|
||||
Gui.new_concept('button')
|
||||
:set_caption('<')
|
||||
:set_tooltip{'gui_util.button_tooltip'}
|
||||
:define_draw(toolbar_button_draw)
|
||||
:on_click(function(event)
|
||||
local element = event.element
|
||||
element.caption = element.caption == '<' and '>' or '<'
|
||||
toolbar_concept:raise_event('on_button_update',{
|
||||
player_index = event.player_index
|
||||
})
|
||||
end)
|
||||
|
||||
--[[-- Button which hides all visible toolbar frames, triggers on_hide_frames
|
||||
@element toolbar-clear
|
||||
]]
|
||||
toolbar_hide_concept =
|
||||
Gui.new_concept('button')
|
||||
:set_caption('<')
|
||||
:set_tooltip{'expcore-gui.left-button-tooltip'}
|
||||
:define_draw(toolbar_button_draw)
|
||||
:on_click(function(event)
|
||||
event.element.visible = false
|
||||
toolbar_concept:raise_event('on_hide_frames',{
|
||||
player_index = event.player_index
|
||||
})
|
||||
end)
|
||||
|
||||
--- When there is a new player they will have the toolbar update
|
||||
Event.add(defines.events.on_player_created,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
toolbar_concept:draw(player)
|
||||
end)
|
||||
|
||||
--- When a player gets a new role they will have the toolbar updated
|
||||
Event.add(Roles.events.on_role_assigned,function(event)
|
||||
toolbar_concept:raise_event('on_button_update',{
|
||||
player_index = event.player_index
|
||||
})
|
||||
end)
|
||||
|
||||
--- When a player loses a role they will have the toolbar updated
|
||||
Event.add(Roles.events.on_role_unassigned,function(event)
|
||||
toolbar_concept:raise_event('on_button_update',{
|
||||
player_index = event.player_index
|
||||
})
|
||||
end)
|
||||
|
||||
return Toolbar
|
||||
@@ -9,25 +9,16 @@ local Roles = require 'expcore.roles' --- @dep expcore.roles
|
||||
local Store = require 'expcore.store' --- @dep expcore.store
|
||||
local Game = require 'utils.game' --- @dep utils.game
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common
|
||||
local config = require 'config.action_buttons' --- @dep config.action_buttons
|
||||
local Colors = require 'resources.color_presets' --- @dep resources.color_presets
|
||||
require 'expcore.toolbar' --- @dep expcore.toolbar
|
||||
|
||||
Gui.require_concept('label')
|
||||
Gui.require_concept('button')
|
||||
Gui.require_concept('text_field')
|
||||
Gui.require_concept('frame')
|
||||
Gui.require_style('expstyle')
|
||||
|
||||
local action_player_store = 'gui.left.player-list.action-player'
|
||||
local action_name_store = 'gui.left.player-list.action-name'
|
||||
|
||||
--- Name label that alows zoom to map
|
||||
-- @element zoom_to_map
|
||||
local zoom_to_map =
|
||||
Gui.new_concept('label')
|
||||
:new_event('on_click',defines.events.on_gui_click)
|
||||
:on_click(function(event)
|
||||
--- used on player name label to allow zoom to map
|
||||
local zoom_to_map_name = Gui.uid_name()
|
||||
Gui.on_click(zoom_to_map_name,function(event)
|
||||
local action_player_name = event.element.caption
|
||||
local action_player = Game.get_player_from_any(action_player_name)
|
||||
if event.button == defines.mouse_button_type.left then
|
||||
@@ -45,130 +36,136 @@ Gui.new_concept('label')
|
||||
end
|
||||
end
|
||||
end)
|
||||
:define_pre_draw(function(properties,parent,element)
|
||||
-- Place the button into a flow
|
||||
local flow =
|
||||
parent.add{
|
||||
type = 'flow',
|
||||
}
|
||||
|
||||
return element, flow
|
||||
end)
|
||||
:define_draw(function(properties,parent,element,player,role_name)
|
||||
local player_name = player.name
|
||||
element.caption = player_name
|
||||
element.tooltip = {'player-list.open-map',player_name,player.tag,role_name}
|
||||
|
||||
Gui.set_padding(element,0,0,0,2)
|
||||
element.style.font_color = player.chat_color
|
||||
end)
|
||||
|
||||
--- Right align for the time label
|
||||
-- @element right_align
|
||||
local right_align =
|
||||
Gui.new_concept('alignment')
|
||||
|
||||
--- Shows the players online time
|
||||
-- @element time_label
|
||||
local time =
|
||||
Gui.new_concept('time_label')
|
||||
:set_time_format{minutes = true}
|
||||
:set_time(0)
|
||||
:define_draw(function(properties,parent,element)
|
||||
Gui.set_padding(element)
|
||||
end)
|
||||
|
||||
--- Button used to open the action bar
|
||||
-- @element open_action_bar
|
||||
local open_action_bar =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/expand_dots_white')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/expand_dots_white')
|
||||
:set_tooltip{'player-list.open-action-bar'}
|
||||
:define_pre_draw(function(properties,parent,element,action_player_name)
|
||||
-- Place the button into a flow
|
||||
local flow =
|
||||
parent.add{
|
||||
type = 'flow',
|
||||
name = action_player_name
|
||||
}
|
||||
|
||||
return element, flow
|
||||
:set_embedded_flow(function(element,action_player_name)
|
||||
return action_player_name
|
||||
end)
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the style of the element
|
||||
element.style = 'frame_button'
|
||||
local style = element.style
|
||||
style.padding = -2
|
||||
:set_style('frame_button',function(style)
|
||||
Gui.set_padding_style(style,-2,-2,-2,-2)
|
||||
style.width = 8
|
||||
style.height = 14
|
||||
end)
|
||||
:on_click(function(event)
|
||||
-- Open the action bar when pressed
|
||||
local element = event.element
|
||||
local player_name = event.player.name
|
||||
:on_click(function(player,element)
|
||||
local new_action_player_name = element.parent.name
|
||||
local action_player_name = Store.get(action_player_store,player_name)
|
||||
local action_player_name = Store.get(action_player_store,player.name)
|
||||
if action_player_name == new_action_player_name then
|
||||
Store.clear(action_player_store,player_name) -- will close if already open
|
||||
Store.clear(action_player_store,player.name) -- will close if already open
|
||||
else
|
||||
Store.set(action_player_store,player_name,new_action_player_name)
|
||||
Store.set(action_player_store,player.name,new_action_player_name)
|
||||
end
|
||||
end)
|
||||
|
||||
--- Button used to close the action bar
|
||||
-- @element close_action_bar
|
||||
local close_action_bar =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/close_black','utility/close_white')
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/close_black','utility/close_white')
|
||||
:set_tooltip{'player-list.close-action-bar'}
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the style of the element
|
||||
element.style = 'tool_button'
|
||||
local style = element.style
|
||||
style.padding = -1
|
||||
:set_style('tool_button',function(style)
|
||||
Gui.set_padding_style(style,-1,-1,-1,-1)
|
||||
style.height = 28
|
||||
style.width = 28
|
||||
end)
|
||||
:on_click(function(event)
|
||||
-- Close the action bar
|
||||
local player_name = event.player.name
|
||||
Store.clear(action_player_store,player_name)
|
||||
Store.clear(action_name_store,player_name)
|
||||
:on_click(function(player,element)
|
||||
Store.clear(action_player_store,player.name)
|
||||
Store.clear(action_name_store,player.name)
|
||||
end)
|
||||
|
||||
--- Adds all the player info into the content table
|
||||
-- @element player_info
|
||||
local player_info =
|
||||
Gui.new_concept()
|
||||
:define_draw(function(properties,parent,element,player,role_name)
|
||||
local player_name = player.name
|
||||
open_action_bar:draw(parent,nil,player_name)
|
||||
zoom_to_map:draw(parent,nil,player,role_name)
|
||||
time:update_time(time:draw(right_align:draw(parent,time.name..player_name)),player.online_time)
|
||||
--- Button used to confirm a reason
|
||||
-- @element reason_confirm
|
||||
local reason_confirm =
|
||||
Gui.new_button()
|
||||
:set_sprites('utility/confirm_slot')
|
||||
:set_tooltip{'player-list.reason-confirm'}
|
||||
:set_style('tool_button',function(style)
|
||||
Gui.set_padding_style(style,-1,-1,-1,-1)
|
||||
style.height = 28
|
||||
style.width = 28
|
||||
end)
|
||||
:on_click(function(player,element)
|
||||
local reason = element.parent.entry.text or 'Non Given'
|
||||
local action_name = Store.get(action_name_store,player.name)
|
||||
local reason_callback = config[action_name].reason_callback
|
||||
reason_callback(player,reason)
|
||||
Store.clear(action_player_store,player.name)
|
||||
Store.clear(action_name_store,player.name)
|
||||
element.parent.entry.text = ''
|
||||
end)
|
||||
|
||||
--- Stores all the online players
|
||||
-- @element content_table
|
||||
local content_table =
|
||||
Gui.new_concept('scroll_table')
|
||||
:set_height(188)
|
||||
:set_column_count(3)
|
||||
--[[ Creates the main gui areas for the player list
|
||||
element
|
||||
> container
|
||||
>> scroll
|
||||
>>> table
|
||||
>> action_bar
|
||||
]]
|
||||
local function generate_container(player,element)
|
||||
Gui.set_padding(element,2,2,2,2)
|
||||
element.style.minimal_width = 200
|
||||
|
||||
--- Stores all the action buttons
|
||||
-- @element action_bar
|
||||
local action_bar =
|
||||
Gui.new_concept('frame')
|
||||
:define_draw(function(properties,parent,element)
|
||||
element.style = 'subfooter_frame'
|
||||
Gui.set_padding(element,1,1,3,3)
|
||||
-- main container which contains the other elements
|
||||
local container =
|
||||
element.add{
|
||||
name='container',
|
||||
type='frame',
|
||||
direction='vertical',
|
||||
style='window_content_frame_packed'
|
||||
}
|
||||
Gui.set_padding(container)
|
||||
|
||||
local style = element.style
|
||||
style.horizontally_stretchable = true
|
||||
style.height = 35
|
||||
-- 3 wide table to contain: action button, player name, and play time
|
||||
local list_table = Gui.create_scroll_table(container,3,188)
|
||||
|
||||
close_action_bar:draw(element)
|
||||
-- action bar which contains the different action buttons
|
||||
local action_bar =
|
||||
container.add{
|
||||
name='action_bar',
|
||||
type='frame',
|
||||
style='subfooter_frame'
|
||||
}
|
||||
Gui.set_padding(action_bar,1,1,3,3)
|
||||
action_bar.style.horizontally_stretchable = true
|
||||
action_bar.style.height = 35
|
||||
|
||||
local player = Gui.get_player_from_element(element)
|
||||
-- reason bar which contains the reason text field and confirm button
|
||||
local reason_bar =
|
||||
container.add{
|
||||
name='reason_bar',
|
||||
type='frame',
|
||||
style='subfooter_frame'
|
||||
}
|
||||
Gui.set_padding(reason_bar,-1,-1,3,3)
|
||||
reason_bar.style.horizontally_stretchable = true
|
||||
reason_bar.style.height = 35
|
||||
local action_name = Store.get(action_name_store,player.name)
|
||||
reason_bar.visible = action_name ~= nil
|
||||
|
||||
-- text entry for the reason bar
|
||||
local reason_field =
|
||||
reason_bar.add{
|
||||
name='entry',
|
||||
type='textfield',
|
||||
style='stretchable_textfield',
|
||||
tooltip={'player-list.reason-entry'}
|
||||
}
|
||||
Gui.set_padding(reason_field)
|
||||
reason_field.style.height = 28
|
||||
reason_field.style.minimal_width = 160
|
||||
|
||||
reason_confirm(reason_bar)
|
||||
|
||||
return list_table, action_bar
|
||||
end
|
||||
|
||||
--- Adds buttons and permission flows to the action bar
|
||||
local function generate_action_bar(player,element)
|
||||
close_action_bar(element)
|
||||
local action_player = Store.get(action_player_store,player.name)
|
||||
|
||||
for action_name,buttons in pairs(config) do
|
||||
@@ -179,7 +176,7 @@ Gui.new_concept('frame')
|
||||
}
|
||||
|
||||
for _,button in ipairs(buttons) do
|
||||
button:draw(permission_flow)
|
||||
button(permission_flow)
|
||||
end
|
||||
|
||||
if not Roles.player_allowed(player,action_name) then
|
||||
@@ -189,79 +186,18 @@ Gui.new_concept('frame')
|
||||
if buttons.auth and action_player and not buttons.auth(player,action_player) then
|
||||
permission_flow.visible = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if not action_player then
|
||||
element.visible = false
|
||||
end
|
||||
end)
|
||||
|
||||
--- Text entry for reason
|
||||
-- @element reason_field
|
||||
local reason_field =
|
||||
Gui.new_concept('text_field')
|
||||
:set_tooltip{'player-list.reason-entry'}
|
||||
:define_draw(function(properties,parent,element)
|
||||
element.style = 'stretchable_textfield'
|
||||
local style = element.style
|
||||
style.padding = 0
|
||||
style.minimal_width = 160
|
||||
style.height = 28
|
||||
end)
|
||||
|
||||
--- Button used to confirm a reason
|
||||
-- @element reason_confirm
|
||||
local reason_confirm =
|
||||
Gui.new_concept('button')
|
||||
:set_sprite('utility/confirm_slot')
|
||||
:set_tooltip{'player-list.reason-confirm'}
|
||||
:define_draw(function(properties,parent,element)
|
||||
-- Update the style of the element
|
||||
element.style = 'tool_button'
|
||||
local style = element.style
|
||||
style.padding = -1
|
||||
style.height = 28
|
||||
style.width = 28
|
||||
end)
|
||||
:on_click(function(event)
|
||||
-- Confirm the reason given
|
||||
local element = event.element
|
||||
local player_name = event.player.name
|
||||
local reason = element.parent.entry.text or 'Non Given'
|
||||
local action_name = Store.get(action_name_store,player_name)
|
||||
local reason_callback = config[action_name].reason_callback
|
||||
reason_callback(event.player,reason)
|
||||
Store.clear(action_player_store,player_name)
|
||||
Store.clear(action_name_store,player_name)
|
||||
element.parent.entry.text = ''
|
||||
end)
|
||||
|
||||
--- Stores the reason entry and confirmation button
|
||||
-- @element reason_bar
|
||||
local reason_bar =
|
||||
Gui.new_concept('frame')
|
||||
:define_draw(function(properties,parent,element)
|
||||
element.style = 'subfooter_frame'
|
||||
Gui.set_padding(element,-1,-1,3,3)
|
||||
|
||||
local style = element.style
|
||||
style.horizontally_stretchable = true
|
||||
style.height = 35
|
||||
|
||||
local player = Gui.get_player_from_element(element)
|
||||
local action_name = Store.get(action_name_store,player.name)
|
||||
element.visible = action_name ~= nil
|
||||
|
||||
reason_field:draw(element)
|
||||
reason_confirm:draw(element)
|
||||
end)
|
||||
end
|
||||
|
||||
--- Updates the action bar
|
||||
local player_list
|
||||
local player_list_name
|
||||
local function update_action_bar(player)
|
||||
local content = player_list:get_content(player)
|
||||
local element = Gui.find(content,action_bar)
|
||||
local frame = Gui.classes.left_frames.get_frame(player_list_name,player)
|
||||
local element = frame.container.action_bar
|
||||
local action_player_name = Store.get(action_player_store,player.name)
|
||||
|
||||
if not action_player_name then
|
||||
@@ -276,7 +212,6 @@ local function update_action_bar(player)
|
||||
element.visible = true
|
||||
for action_name,buttons in pairs(config) do
|
||||
if buttons.auth and not buttons.auth(player,action_player) then
|
||||
print(action_name)
|
||||
element[action_name].visible = false
|
||||
elseif Roles.player_allowed(player,action_name) then
|
||||
element[action_name].visible = true
|
||||
@@ -286,37 +221,70 @@ local function update_action_bar(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Adds a player to the player list
|
||||
local function add_player(list_table,player,role_name)
|
||||
open_action_bar(list_table,player.name)
|
||||
|
||||
-- flow to contain player_name to allow all to have trigger for zoom to map
|
||||
local player_name_flow =
|
||||
list_table.add{
|
||||
type='flow'
|
||||
}
|
||||
Gui.set_padding(player_name_flow)
|
||||
|
||||
-- player name with the tooltip of their highest role and in they colour
|
||||
local player_name =
|
||||
player_name_flow.add{
|
||||
name=zoom_to_map_name,
|
||||
type='label',
|
||||
caption=player.name,
|
||||
tooltip={'player-list.open-map',player.name,player.tag,role_name}
|
||||
}
|
||||
Gui.set_padding(player_name,0,0,0,2)
|
||||
player_name.style.font_color = player.chat_color
|
||||
|
||||
-- flow which allows right align for the play time
|
||||
local time_flow = Gui.create_alignment(list_table,'player-time-'..player.index)
|
||||
|
||||
-- time given in Xh Ym and is right aligned
|
||||
local tick = game.tick > 0 and game.tick or 1
|
||||
local percent = math.round(player.online_time/tick,3)*100
|
||||
local time =
|
||||
time_flow.add{
|
||||
name='label',
|
||||
type='label',
|
||||
caption=format_time(player.online_time),
|
||||
tooltip={'player-list.afk-time',percent,format_time(player.afk_time,{minutes=true,long=true})}
|
||||
}
|
||||
Gui.set_padding(time)
|
||||
end
|
||||
|
||||
--- Adds fake players to the player list
|
||||
local function add_fake_players(content_area,count)
|
||||
local function add_fake_players(list_table,count)
|
||||
local role_name = 'Fake Player'
|
||||
for i = 1,count do
|
||||
local player = {
|
||||
add_player(list_table,{
|
||||
name='Player '..i,
|
||||
index=0-i,
|
||||
tag='',
|
||||
online_time=math.random(0,game.tick),
|
||||
afk_time=math.random(0,game.tick),
|
||||
chat_color=table.get_random_dictionary_entry(Colors)
|
||||
}
|
||||
|
||||
player_info:draw(content_area,nil,player,role_name)
|
||||
},role_name)
|
||||
end
|
||||
end
|
||||
|
||||
--- Registers the player list
|
||||
-- @element player_list
|
||||
player_list =
|
||||
Gui.new_concept('toolbar-frame')
|
||||
:set_permission_alias('gui/player-list')
|
||||
:set_sprite('entity/character')
|
||||
local player_list =
|
||||
Gui.new_left_frame('gui/player-list')
|
||||
:set_sprites('entity/character')
|
||||
:set_tooltip{'player-list.main-tooltip'}
|
||||
:set_open_by_default(true)
|
||||
:set_open_by_default()
|
||||
:set_direction('vertical')
|
||||
:define_draw(function(properties,parent,element)
|
||||
local content_area =
|
||||
content_table:draw(element)
|
||||
action_bar:draw(element)
|
||||
reason_bar:draw(element)
|
||||
:on_creation(function(player,element)
|
||||
local list_table,action_bar = generate_container(player,element)
|
||||
generate_action_bar(player,action_bar)
|
||||
|
||||
local players = {}
|
||||
for _,next_player in pairs(game.connected_players) do
|
||||
@@ -330,49 +298,55 @@ Gui.new_concept('toolbar-frame')
|
||||
for _,role_name in pairs(Roles.config.order) do
|
||||
if players[role_name] then
|
||||
for _,next_player in pairs(players[role_name]) do
|
||||
player_info:draw(content_area,nil,next_player,role_name)
|
||||
add_player(list_table,next_player,role_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
add_fake_players(content_area,4)
|
||||
--add_fake_players(list_table,6)
|
||||
--add_fake_players(list_table,20)
|
||||
end)
|
||||
:on_update(function(event)
|
||||
local list = Gui.find(event.element,content_table,'table')
|
||||
:on_update(function(player,element)
|
||||
local list = element.container.scroll.table
|
||||
for _,next_player in pairs(game.connected_players) do
|
||||
local time_element = Gui.find(list,time.name..next_player.name,time)
|
||||
local time_element_name = 'player-time-'..next_player.index
|
||||
local time_element = list[time_element_name]
|
||||
if time_element and time_element.valid then
|
||||
time:update_time(time_element,next_player.online_time)
|
||||
time_element.label.caption = format_time(next_player.online_time)
|
||||
local tick = game.tick > 0 and game.tick or 1
|
||||
local percent = math.round(next_player.online_time/tick,3)*100
|
||||
time_element.label.tooltip = {'player-list.afk-time',percent,format_time(next_player.afk_time,{minutes=true,long=true})}
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
player_list_name = player_list:uid()
|
||||
|
||||
--- When the action player is changed the action bar will update
|
||||
Store.register(action_player_store,function(value,category)
|
||||
local player = Game.get_player_from_any(category)
|
||||
update_action_bar(player)
|
||||
|
||||
local frame = player_list:get_content(player)
|
||||
local data_table = Gui.find(frame,content_table,'table')
|
||||
local frame = player_list:get_frame(player)
|
||||
local data_table = frame.container.scroll.table
|
||||
for _,next_player in pairs(game.connected_players) do
|
||||
local element = Gui.find(data_table,next_player.name,open_action_bar)
|
||||
local element = data_table[next_player.name][open_action_bar.name]
|
||||
local style = 'frame_button'
|
||||
if next_player.name == value then
|
||||
style = 'tool_button'
|
||||
end
|
||||
element.style = style
|
||||
style = element.style
|
||||
style.padding = -2
|
||||
style.width = 8
|
||||
style.height = 14
|
||||
Gui.set_padding(element,-2,-2,-2,-2)
|
||||
element.style.width = 8
|
||||
element.style.height = 14
|
||||
end
|
||||
end)
|
||||
|
||||
--- When the action name is changed the reason input will update
|
||||
Store.register(action_name_store,function(value,category)
|
||||
local player = Game.get_player_from_any(category)
|
||||
local frame = player_list:get_content(player)
|
||||
local element = Gui.find(frame,reason_bar)
|
||||
local frame = Gui.classes.left_frames.get_frame(player_list_name,player)
|
||||
local element = frame.container.reason_bar
|
||||
if value then
|
||||
local action_player_name = Store.get(action_player_store,category)
|
||||
local action_player = Game.get_player_from_any(action_player_name)
|
||||
@@ -388,11 +362,10 @@ Store.register(action_name_store,function(value,category)
|
||||
end)
|
||||
|
||||
--- Many events which trigger the gui to be re drawn, it will also update the times every 30 seconds
|
||||
local update = function(event) player_list:update_all(event) end
|
||||
Event.on_nth_tick(1800,update)
|
||||
Event.add(defines.events.on_player_joined_game,update)
|
||||
Event.add(defines.events.on_player_left_game,update)
|
||||
Event.add(Roles.events.on_role_assigned,update)
|
||||
Event.add(Roles.events.on_role_unassigned,update)
|
||||
Event.on_nth_tick(1800,player_list 'update_all')
|
||||
Event.add(defines.events.on_player_joined_game,player_list 'redraw_all')
|
||||
Event.add(defines.events.on_player_left_game,player_list 'redraw_all')
|
||||
Event.add(Roles.events.on_role_assigned,player_list 'redraw_all')
|
||||
Event.add(Roles.events.on_role_unassigned,player_list 'redraw_all')
|
||||
|
||||
return player_list
|
||||
Reference in New Issue
Block a user