mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Merge branch 'feature/gui-inputs' into dev
This commit is contained in:
@@ -32,11 +32,13 @@ return {
|
||||
'modules.addons.scorched-earth',
|
||||
'modules.addons.pollution-grading',
|
||||
'modules.addons.random-player-colours',
|
||||
-- GUI
|
||||
'modules.commands.debug',
|
||||
-- Config Files
|
||||
'config.command_auth_admin', -- commands tagged with admin_only are blocked for non admins
|
||||
'config.command_auth_roles', -- commands must be allowed via the role config
|
||||
'config.command_auth_runtime_disable', -- allows commands to be enabled and disabled during runtime
|
||||
'config.permission_groups', -- loads some predefined permission groups
|
||||
'config.roles', -- loads some predefined roles
|
||||
'expcore.store_test'
|
||||
'expcore.gui.test'
|
||||
}
|
||||
@@ -44,6 +44,7 @@ Roles.new_role('Senior Administrator','SAdmin')
|
||||
:set_parent('Administrator')
|
||||
:allow{
|
||||
'command/interface',
|
||||
'command/debug',
|
||||
'command/toggle-cheat-mode'
|
||||
}
|
||||
|
||||
@@ -237,7 +238,7 @@ Roles.override_player_roles{
|
||||
FlipHalfling90={'Moderator','Member'},
|
||||
Gizan={'Pay to Win','Moderator','Member'},
|
||||
Hobbitkicker={'Moderator','Member'},
|
||||
jess_gaming={'Trainee','Member'},
|
||||
jessi_gaming={'Trainee','Member'},
|
||||
Koroto={'Moderator','Member'},
|
||||
mafisch3={'Moderator','Member'},
|
||||
maplesyrup01={'Moderator','Member'},
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
-- all files which are loaded (including the config files) are present in ./config/file_loader.lua
|
||||
-- this file is the landing point for all scenarios please DO NOT edit directly, further comments are to aid development
|
||||
|
||||
log('[START] -----| Explosive Gaming Scenario Loader |-----')
|
||||
|
||||
-- Info on the data lifecycle and how we use it: https://github.com/Refactorio/RedMew/wiki/The-data-lifecycle
|
||||
log('[INFO] Setting up lua environment')
|
||||
require 'resources.data_stages'
|
||||
_LIFECYCLE = _STAGE.control -- Control stage
|
||||
|
||||
@@ -22,6 +25,7 @@ require 'resources.version'
|
||||
ext_require = require('expcore.common').ext_require
|
||||
|
||||
-- Please go to config/file_loader.lua to edit the files that are loaded
|
||||
log('[INFO] Getting file loader config')
|
||||
local files = require 'config.file_loader'
|
||||
|
||||
-- Loads all files from the config and logs that they are loaded
|
||||
@@ -30,7 +34,7 @@ local errors = {}
|
||||
for index,path in pairs(files) do
|
||||
|
||||
-- Loads the next file in the list
|
||||
log(string.format('[INFO] Loading files %3d/%s (%s)',index,total_file_count,path))
|
||||
log(string.format('[INFO] Loading file %3d/%s (%s)',index,total_file_count,path))
|
||||
local success,file = pcall(require,path)
|
||||
|
||||
-- Error Checking
|
||||
@@ -49,4 +53,5 @@ end
|
||||
|
||||
-- Logs all errors again to make it make it easy to find
|
||||
log('[INFO] All files loaded with '..#errors..' errors:')
|
||||
for _,error in pairs(errors) do log(error) end
|
||||
for _,error in pairs(errors) do log(error) end
|
||||
log('[END] -----| Explosive Gaming Scenario Loader |-----')
|
||||
122
expcore/Gui/buttons.lua
Normal file
122
expcore/Gui/buttons.lua
Normal file
@@ -0,0 +1,122 @@
|
||||
--- Gui class define for buttons and sprite 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 spirte 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'
|
||||
local Gui = require './core'
|
||||
|
||||
local Button = {
|
||||
config={},
|
||||
_prototype=Gui._prototype_factory{
|
||||
on_click = Gui._event_factory('on_click'),
|
||||
on_left_click = Gui._event_factory('on_left_click'),
|
||||
on_right_click = Gui._event_factory('on_right_click'),
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new button element define
|
||||
-- @tparam[opt] name string the optional debug name that can be added
|
||||
-- @treturn table the new button element define
|
||||
function Button.new_button(name)
|
||||
|
||||
local self = Gui._define_factory(Button._prototype)
|
||||
self.draw_data.type = 'button'
|
||||
self.draw_data.style = mod_gui.button_style
|
||||
|
||||
if name then
|
||||
self:debug_name(name)
|
||||
end
|
||||
|
||||
Gui.on_click(self.name,function(event)
|
||||
local mouse_button = event.button
|
||||
local keys = {alt=event.alt,control=event.control,shift=event.shift}
|
||||
event.keys = keys
|
||||
|
||||
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 and self.events.on_left_click then
|
||||
self.events.on_left_click(event.player,event.element)
|
||||
elseif mouse_button == defines.mouse_button_type.right and self.events.on_right_click then
|
||||
self.events.on_right_click(event.player,event.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
|
||||
|
||||
if self.events.on_click then
|
||||
self.events.on_click(event.player,event.element,event)
|
||||
end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Adds sprites to a button making it a spirte button
|
||||
-- @tparam sprite SpritePath the sprite path for the default sprite for the button
|
||||
-- @tparam[opt] hovered_sprite SpritePath the sprite path for the sprite when the player hovers over the button
|
||||
-- @tparam[opt] clicked_sprite SpritePath 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 filter ?string|table either a table of mouse buttons or the first mouse button to filter, with a table true means allowed
|
||||
-- @tparam[opt] ... when filter is not a table 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 filter ?string|table either a table of control keys or the first control keys to filter, with a table true means allowed
|
||||
-- @tparam[opt] ... when filter is not a table you can add the control keyss 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
|
||||
266
expcore/Gui/checkboxs.lua
Normal file
266
expcore/Gui/checkboxs.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
--- Gui class define for checkboxs and radiobuttons
|
||||
--[[
|
||||
>>>> 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.player_store)
|
||||
|
||||
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 indivual 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 radiobutotns (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 radiobutotn in a element to false (unless excluded) and can act recursivly
|
||||
|
||||
Other functions present from expcore.gui.core
|
||||
]]
|
||||
local Gui = require './core'
|
||||
local Store = require 'expcore.store'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
--- Event call for on_checked_state_changed and store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value boolean the new state of the checkbox
|
||||
local function event_call(define,element,value)
|
||||
if define.events.on_element_update then
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
define.events.on_element_update(player,element,value)
|
||||
end
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value boolean the new state of the checkbox
|
||||
local function store_call(define,element,value)
|
||||
element.state = value
|
||||
event_call(define,element,value)
|
||||
end
|
||||
|
||||
local Checkbox = {
|
||||
option_sets={},
|
||||
option_categorize={},
|
||||
_prototype_checkbox=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
},
|
||||
_prototype_radiobutton=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new checkbox element define
|
||||
-- @tparam[opt] name string the optional debug name that can be added
|
||||
-- @treturn table the new checkbox element define
|
||||
function Checkbox.new_checkbox(name)
|
||||
|
||||
local self = Gui._define_factory(Checkbox._prototype_checkbox)
|
||||
self.draw_data.type = 'checkbox'
|
||||
self.draw_data.state = false
|
||||
|
||||
if name then
|
||||
self:debug_name(name)
|
||||
end
|
||||
|
||||
self.post_draw = function(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) or value
|
||||
self:set_store(category,value)
|
||||
|
||||
elseif self.store then
|
||||
local value = element.state
|
||||
local category = self.categorize and self.categorize(element) or value
|
||||
self:set_store(category,value)
|
||||
|
||||
else
|
||||
local value = element.state
|
||||
event_call(self,element,value)
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new radiobutton element define, has all functions checkbox has
|
||||
-- @tparam[opt] name string 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 option_set string the name of the option set to add this element to
|
||||
-- @tparam option_name string the name of this option that will be used to idenitife it
|
||||
-- @tparam 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 category[opt] string the category to get such as player name or force name
|
||||
-- @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
|
||||
|
||||
if self.categorize then
|
||||
return Store.get_child(location,category)
|
||||
else
|
||||
return Store.get(location)
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets the stored value of the radiobutton or the option set if present
|
||||
-- @tparam category[opt] string the category to get such as player name or force name
|
||||
-- @tparam value any the value to set for this define, must be valid for its type ie boolean for checkbox etc
|
||||
-- @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
|
||||
|
||||
if self.categorize then
|
||||
return Store.set_child(location,category,value)
|
||||
else
|
||||
return Store.set(location,category)
|
||||
end
|
||||
end
|
||||
|
||||
--- Registers a new option set that can be linked to radiobutotns (only one can be true at a time)
|
||||
-- @tparam name string the name of the option set, must be unique
|
||||
-- @tparam callback function the update callback when the value of the option set chagnes
|
||||
-- callback param - value string - the new selected option for this option set
|
||||
-- callback param - category string - the category that updated if categorize was used
|
||||
-- @tpram categorize function 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 name string the name of the option set to draw the radiobuttons of
|
||||
-- @tparam element LuaGuiElement 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 radiobutotn in a element to false (unless excluded) and can act recursivly
|
||||
-- @tparam element LuaGuiElement the root gui element to start setting radio buttons from
|
||||
-- @tparam[opt] exclude ?string|table the name of the radiobutton to exclude or a table of radiobuttons where true will set the state true
|
||||
-- @tparam[opt=false] recursive boolean if true will recur as much as possible, if a number 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
|
||||
537
expcore/Gui/core.lua
Normal file
537
expcore/Gui/core.lua
Normal file
@@ -0,0 +1,537 @@
|
||||
--- 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
|
||||
--[[
|
||||
>>>> Basic useage with no defines
|
||||
This module can be igroned if you are only wanting only event handlers as utils.gui adds the following:
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
>>>> Interal factory functions
|
||||
There are a few factory function that are used by the class definations the use of these function are important to
|
||||
know about but should only be used when making a new class deination rather than an element defination. See one of
|
||||
the existing class definations for an example of when to use these.
|
||||
|
||||
>>>> Basic prototype functions
|
||||
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
|
||||
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.player_store)
|
||||
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.player_store 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.player_store)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Example checkbox is now: '..tostring(value))
|
||||
end)
|
||||
|
||||
>>>> Functions
|
||||
Gui._prototype_factory(tbl) --- Used internally to create new prototypes for element defines
|
||||
Gui._event_factory(name) --- Used internally to create event handler adders for element defines
|
||||
Gui._store_factory(callback) --- Used internally to create store adders for element defines
|
||||
Gui._sync_store_factory(callback) --- Used internally to create synced store adders for element defines
|
||||
Gui._define_factory(prototype) --- Used internally to create new element defines from a class prototype
|
||||
|
||||
Gui._prototype:uid() --- Gets the uid for the element define
|
||||
Gui._prototype:debug_name(name) --- Sets a debug alias for the define
|
||||
Gui._prototype:set_caption(caption) --- Sets the caption for the element define
|
||||
Gui._prototype:set_tooltip(tooltip) --- Sets the tooltip for the element define
|
||||
Gui._prototype:on_element_update(callback) --- Add a hander to run on the general value update event, different classes will handle this event differently
|
||||
|
||||
Gui._prototype:set_pre_authenticator(callback) --- Sets an authenticator that blocks the draw function if check fails
|
||||
Gui._prototype:set_post_authenticator(callback) --- Sets an authenticator that disables the element if check fails
|
||||
Gui._prototype:draw_to(element) --- Draws the element using what is in the draw_data table, allows use of authenticator if present, registers new instances if store present
|
||||
Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to
|
||||
|
||||
Gui._prototype:add_store(categorize) --- Adds a store location for the define that will save the state of the element, categorize is a function that returns a string
|
||||
Gui._prototype:add_sync_store(location,categorize) --- Adds a store location for the define that will sync between games, categorize is a function that returns a string
|
||||
Gui._prototype:on_store_update(callback) --- Adds a event callback for when the store changes are other events are not gauenteted to be raised
|
||||
Gui.player_store(element) --- A categorize function to be used with add_store, each player has their own value
|
||||
Gui.force_store(element) --- A categorize function to be used with add_store, each force has its own value
|
||||
Gui.surface_store(element) --- A categorize function to be used with add_store, each surface has its own value
|
||||
|
||||
Gui._prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used
|
||||
Gui._prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used
|
||||
Gui.get_store(name,category) --- Gets the value that is stored for a given element define, category needed if categorize function used
|
||||
Gui.set_store(name,category,value) --- Sets the value stored for a given element define, category needed if categorize function used
|
||||
|
||||
Gui.toggle_enable(element) --- Will toggle the enabled state of an element
|
||||
Gui.toggle_visible(element) --- Will toggle the visiblity of an element
|
||||
]]
|
||||
local Gui = require 'utils.gui'
|
||||
local Game = require 'utils.game'
|
||||
local Global = require 'utils.global'
|
||||
local Store = require 'expcore.store'
|
||||
|
||||
Gui._prototype = {} -- Stores the base prototype of all element defines
|
||||
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
|
||||
Gui.instances = {} -- Stores runtime data of all active instances of an element define
|
||||
Global.register(Gui.instances,function(tbl)
|
||||
Gui.instances = tbl
|
||||
end)
|
||||
|
||||
--- Used internally to create new prototypes for element defines
|
||||
-- @tparam tbl table a table that will have functions added to it
|
||||
-- @treturn table the new table with the keys added to it
|
||||
function Gui._prototype_factory(tbl)
|
||||
for k,v in pairs(Gui._prototype) do
|
||||
if not tbl[k] then tbl[k] = v end
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
--- Used internally to create event handler adders for element defines
|
||||
-- @tparam name string the key that the event will be stored under, should be the same as the event name
|
||||
-- @treturn function the function that can be used to add an event handler
|
||||
function Gui._event_factory(name)
|
||||
--- Gui._prototype:on_event(callback)
|
||||
--- Add a hander to run on this event, replace event with the event, different classes have different events
|
||||
-- @tparam callback function the function that will be called on the event
|
||||
-- callback param - player LuaPlayer - the player who owns the gui element
|
||||
-- callback param - element LuaGuiElement - the element that caused the event
|
||||
-- callback param - value any - (not always present) the updated value for the element
|
||||
-- callback param - ... any - other class defines may add more params
|
||||
-- @treturn self the element define to allow chaining
|
||||
return function(self,callback)
|
||||
if type(callback) ~= 'function' then
|
||||
return error('Event callback must be a function',2)
|
||||
end
|
||||
|
||||
self.events[name] = callback
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
--- Used internally to create store adders for element defines
|
||||
-- @tparam callback a callback is called when there is an update to the stored value and stould set the state of the element
|
||||
-- @treturn function the function that can be used to add a store the the define
|
||||
function Gui._store_factory(callback)
|
||||
--- Gui._prototype:add_store(categorize)
|
||||
--- Adds a store location for the define that will save the state of the element, categorize is a function that returns a string
|
||||
-- @tparam[opt] categorize function if present will be called to convert an element into a category string
|
||||
-- categorize param - element LuaGuiElement - the element that needs to be converted
|
||||
-- categorize return - string - a determistic string that referses to a category such as player name or force name
|
||||
-- @treturn self the element define to allow chaining
|
||||
return function(self,categorize)
|
||||
if self.store then return end
|
||||
|
||||
self.store = Store.uid_location()
|
||||
self.categorize = categorize
|
||||
Gui.instances[self.name]={}
|
||||
|
||||
Store.register(self.store,function(value,category)
|
||||
if self.events.on_store_update then
|
||||
self.events.on_store_update(value,category)
|
||||
end
|
||||
|
||||
local instances = Gui.get_instances(self,category)
|
||||
if instances then
|
||||
|
||||
for k,element in pairs(instances) do
|
||||
if element and element.valid then
|
||||
callback(self,element,value)
|
||||
else
|
||||
instances[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
--- Used internally to create synced store adders for element defines
|
||||
-- @tparam callback a callback is called when there is an update to the stored value and stould set the state of the element
|
||||
-- @treturn function the function that can be used to add a sync store the the define
|
||||
function Gui._sync_store_factory(callback)
|
||||
--- Gui._prototype:add_sync_store(location,categorize)
|
||||
--- Adds a store location for the define that will sync between games, categorize is a function that returns a string
|
||||
-- @tparam location string a unique string location, unlike add_store a uid location should not be used to avoid migration problems
|
||||
-- @tparam[opt] categorize function if present will be called to convert an element into a category string
|
||||
-- categorize param - element LuaGuiElement - the element that needs to be converted
|
||||
-- categorize return - string - a determistic string that referses 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
|
||||
|
||||
if Store.is_registered(location) then
|
||||
return error('Location for store is already registered: '..location,2)
|
||||
end
|
||||
|
||||
self.store = location
|
||||
self.categorize = categorize
|
||||
Gui.instances[self.name]={}
|
||||
|
||||
Store.register_synced(self.store,function(value,category)
|
||||
if self.events.on_store_update then
|
||||
self.events.on_store_update(value,category)
|
||||
end
|
||||
|
||||
local instances = Gui.get_instances(self,category)
|
||||
if instances then
|
||||
|
||||
for k,element in pairs(instances) do
|
||||
if element and element.valid then
|
||||
callback(self,element,value)
|
||||
else
|
||||
instances[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
--- Used internally to create new element defines from a class prototype
|
||||
-- @tparam prototype table the class prototype that will be used for the element define
|
||||
-- @treturn table the new element define with all functions accessed via __index metamethod
|
||||
function Gui._define_factory(prototype)
|
||||
local uid = Gui.uid_name()
|
||||
local define = setmetatable({
|
||||
name=uid,
|
||||
events={},
|
||||
draw_data={
|
||||
name=uid
|
||||
}
|
||||
},{
|
||||
__index=prototype,
|
||||
__call=function(self,element)
|
||||
return self:draw_to(element)
|
||||
end
|
||||
})
|
||||
Gui.defines[define.name] = define
|
||||
return define
|
||||
end
|
||||
|
||||
--- Gets the uid for the element define
|
||||
-- @treturn string the uid of this element define
|
||||
function Gui._prototype:uid()
|
||||
return self.name
|
||||
end
|
||||
|
||||
--- Sets a debug alias for the define
|
||||
-- @tparam name string the debug name for the element define that can be used to get this element define
|
||||
-- @treturn self the element define to allow chaining
|
||||
function Gui._prototype:debug_name(name)
|
||||
self.debug_name = name
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the caption for the element define
|
||||
-- @tparam caption string the caption that will be drawn with the element
|
||||
-- @treturn self the element define to allow chaining
|
||||
function Gui._prototype:set_caption(caption)
|
||||
self.draw_data.caption = caption
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the tooltip for the element define
|
||||
-- @tparam tooltip string the tooltip that will be displayed for this element when drawn
|
||||
-- @treturn self the element define to allow chaining
|
||||
function Gui._prototype:set_tooltip(tooltip)
|
||||
self.draw_data.tooltip = tooltip
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets an authenticator that blocks the draw function if check fails
|
||||
-- @tparam callback function the function that will be ran to test if the element should be drawn or not
|
||||
-- callback param - player LuaPlayer - the player that the element is being drawn to
|
||||
-- callback param - define_name string - 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
|
||||
function Gui._prototype:set_pre_authenticator(callback)
|
||||
if type(callback) ~= 'function' then
|
||||
return error('Pre authenticator callback must be a function')
|
||||
end
|
||||
|
||||
self.pre_authenticator = callback
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets an authenticator that disables the element if check fails
|
||||
-- @tparam callback function the function that will be ran to test if the element should be enabled or not
|
||||
-- callback param - player LuaPlayer - the player that the element is being drawn to
|
||||
-- callback param - define_name string - 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
|
||||
function Gui._prototype:set_post_authenticator(callback)
|
||||
if type(callback) ~= 'function' then
|
||||
return error('Authenicater callback must be a function')
|
||||
end
|
||||
|
||||
self.post_authenticator = callback
|
||||
return self
|
||||
end
|
||||
|
||||
--- Draws the element using what is in the draw_data table, allows use of authenticator if present, registers new instances if store present
|
||||
-- the data with in the draw_data is set up through the use of all the other functions
|
||||
-- @tparam element LuaGuiElement the element that the define will draw a copy of its self onto
|
||||
-- @treturn LuaGuiElement the new element that was drawn so styles can be applied
|
||||
function Gui._prototype:draw_to(element)
|
||||
if element[self.name] then return end
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
if self.pre_authenticator then
|
||||
if not self.pre_authenticator(player,self.name) then return end
|
||||
end
|
||||
|
||||
local new_element = element.add(self.draw_data)
|
||||
|
||||
if self.post_authenticator then
|
||||
new_element.enabled = self.post_authenticator(player,self.name)
|
||||
end
|
||||
|
||||
if self.store then
|
||||
local category = self.categorize and self.categorize(element) or nil
|
||||
local instances = Gui.get_instances(self,category)
|
||||
if instances then
|
||||
table.insert(instances,new_element)
|
||||
end
|
||||
end
|
||||
|
||||
if self.post_draw then self.post_draw(new_element) end
|
||||
|
||||
return new_element
|
||||
end
|
||||
|
||||
--- Gets the value in this elements store, category needed if categorize function used
|
||||
-- @tparam category[opt] string the category to get such as player name or force name
|
||||
-- @treturn any the value that is stored for this define
|
||||
function Gui._prototype:get_store(category)
|
||||
if not self.store then return end
|
||||
if self.categorize then
|
||||
return Store.get_child(self.store,category)
|
||||
else
|
||||
return Store.get(self.store)
|
||||
end
|
||||
end
|
||||
|
||||
--- Sets the value in this elements store, category needed if categorize function used
|
||||
-- @tparam category[opt] string the category to get such as player name or force name
|
||||
-- @tparam value any the value to set for this define, must be valid for its type ie boolean for checkbox etc
|
||||
-- @treturn boolean true if the value was set
|
||||
function Gui._prototype:set_store(category,value)
|
||||
if not self.store then return end
|
||||
if self.categorize then
|
||||
return Store.set_child(self.store,category,value)
|
||||
else
|
||||
return Store.set(self.store,category)
|
||||
end
|
||||
end
|
||||
|
||||
--- Gets an element define give the uid, debug name or a copy of the element define
|
||||
-- @tparam name ?string|table the uid, debug name or define for the element define to get
|
||||
-- @tparam[opt] internal boolean 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
|
||||
|
||||
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 checkbox, name not found.',internal and 3 or 2) or nil
|
||||
|
||||
end
|
||||
|
||||
return define
|
||||
end
|
||||
|
||||
--- Gets all instances of the element define, mostly internal use and note invalid elements may be present in the return
|
||||
-- @tparam name string the uid or debug name for the define to get the instances for
|
||||
-- @tparam[opt] category string the category to get the instances for
|
||||
-- @treturn table a table of LuaGuiElements that might be invalid which belong to this define
|
||||
function Gui.get_instances(name,category)
|
||||
local define = Gui.get_define(name,true)
|
||||
if not Gui.instances[define.name] then return end
|
||||
|
||||
local instances = Gui.instances[define.name]
|
||||
if define.categorize then
|
||||
if not instances[category] then instances[category] = {} end
|
||||
return instances[category]
|
||||
|
||||
end
|
||||
|
||||
return instances
|
||||
end
|
||||
|
||||
--- Gets the value that is stored for a given element define, category needed if categorize function used
|
||||
-- @tparam name ?string|table the uid, debug name or define for the element define to get
|
||||
-- @tparam[opt] category string the category to get the value for
|
||||
-- @treturn any the value that is stored for this define
|
||||
function Gui.get_store(name,category)
|
||||
local define = Gui.get_define(name,true)
|
||||
return define:get_store(category)
|
||||
end
|
||||
|
||||
--- Sets the value stored for a given element define, category needed if categorize function used
|
||||
-- @tparam name ?string|table the uid, debug name or define for the element define to set
|
||||
-- @tparam[opt] category string the category to set the value for
|
||||
-- @tparam value any the value to set for the define, must be valid for its type ie boolean for a checkbox
|
||||
-- @treturn boolean true if the value was set
|
||||
function Gui.set_store(name,category,value)
|
||||
local define = Gui.get_define(name,true)
|
||||
return define:get_store(category,value)
|
||||
end
|
||||
|
||||
--- A categorize function to be used with add_store, each player has their own value
|
||||
-- @tparam element LuaGuiElement the element that will be converted to a string
|
||||
-- @treturn string the player's name who owns this element
|
||||
function Gui.player_store(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 value
|
||||
-- @tparam element LuaGuiElement the element that will be converted to a string
|
||||
-- @treturn string the player's force name who owns this element
|
||||
function Gui.force_store(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 value
|
||||
-- @tparam element LuaGuiElement the element that will be converted to a string
|
||||
-- @treturn string the player's surface name who owns this element
|
||||
function Gui.surface_store(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 name ?string|table the uid, debug name or define for the element define to draw
|
||||
-- @tparam element LuaGuiEelement 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 element LuaGuiElement the gui element to toggle
|
||||
function Gui.toggle_enable(element)
|
||||
if not element or not element.valid then return end
|
||||
if not element.enabled then
|
||||
element.enabled = true
|
||||
else
|
||||
element.enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Will toggle the visiblity of an element
|
||||
-- @tparam element LuaGuiElement the gui element to toggle
|
||||
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
|
||||
end
|
||||
|
||||
return Gui
|
||||
189
expcore/Gui/dropdown.lua
Normal file
189
expcore/Gui/dropdown.lua
Normal file
@@ -0,0 +1,189 @@
|
||||
--- Gui class define for dropdowns and list boxs
|
||||
--[[
|
||||
>>>> 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 './core'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
--- Event call for on_selection_state_changed and store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value string the new option for the dropdown
|
||||
local function event_call(define,element,value)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
if define.events.on_element_update then
|
||||
define.events.on_element_update(player,element,value)
|
||||
end
|
||||
|
||||
if define.option_callbacks and define.option_callbacks[value] then
|
||||
define.option_callbacks[value](player,element,value)
|
||||
end
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value string the new option for the dropdown
|
||||
local _select_value
|
||||
local function store_call(define,element,value)
|
||||
_select_value(element,value)
|
||||
event_call(define,element,value)
|
||||
end
|
||||
|
||||
local Dropdown = {
|
||||
_prototype=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new dropdown element define
|
||||
-- @tparam[opt] name string the optional debug name that can be added
|
||||
-- @treturn table the new dropdown element define
|
||||
function Dropdown.new_dropdown(name)
|
||||
|
||||
local self = Gui._define_factory(Dropdown._prototype)
|
||||
self.draw_data.type = 'drop-down'
|
||||
|
||||
if name then
|
||||
self:debug_name(name)
|
||||
end
|
||||
|
||||
self.post_draw = function(element)
|
||||
if self.dynamic_options then
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
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
|
||||
event_call(self,element,value)
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new list box element define
|
||||
-- @tparam[opt] name string 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 options ?string|table either a table of option strings or the first option string, with a table values are the options
|
||||
-- @tparam[opt] ... when options is not a table 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 callback function 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
|
||||
-- @tparam 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 option string the name of the option to trigger the callback on; if not already added then will be added as an option
|
||||
-- @tparam callback function 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
|
||||
-- @tparam 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 element LuaGuiElement the element that contains the option
|
||||
-- @tparam value string 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 element LuaGuiElement 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
|
||||
111
expcore/Gui/elem-button.lua
Normal file
111
expcore/Gui/elem-button.lua
Normal file
@@ -0,0 +1,111 @@
|
||||
--- Gui class defines for 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 './core'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
--- Event call for on_elem_changed and store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value string the new value for the elem button
|
||||
local function event_call(define,element,value)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
if define.events.on_element_update then
|
||||
define.events.on_element_update(player,element,value)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value string the new value for the elem button
|
||||
local function store_call(self,element,value)
|
||||
element.elem_value = value
|
||||
event_call(self,element,value)
|
||||
end
|
||||
|
||||
local ElemButton = {
|
||||
_prototype=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new elem button element define
|
||||
-- @tparam[opt] name string 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._define_factory(ElemButton._prototype)
|
||||
self.draw_data.type = 'choose-elem-button'
|
||||
|
||||
if name then
|
||||
self:debug_name(name)
|
||||
end
|
||||
|
||||
self.post_draw = function(element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
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
|
||||
event_call(self,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 type string the type that this elem button is see factorio api
|
||||
-- @treturn the element define to allow for chaining
|
||||
function ElemButton._prototype:set_type(type)
|
||||
self.draw_data.elem_type = type
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets the default value for the elem button, this may be a function or a string
|
||||
-- @tparam value ?string|function a string 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
|
||||
206
expcore/Gui/slider.lua
Normal file
206
expcore/Gui/slider.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
--- Gui class define for silders
|
||||
--[[
|
||||
>>>> 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 './core'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
--- Gets the active lables for a define
|
||||
-- @tparam define table the define to get the labels for
|
||||
-- @tparam element LuaGuiElement the element that will be used to get the category
|
||||
-- @treturn table the table of active instances for the slider lables
|
||||
local function get_labels(define,element)
|
||||
local function cat(e)
|
||||
return e.player_index
|
||||
end
|
||||
|
||||
local name = define.name..'-label'
|
||||
if not Gui.instances[name] then return end
|
||||
|
||||
local categorize = define.categorize or not define.store and cat
|
||||
local category = categorize and categorize(element) or nil
|
||||
local instances = Gui.get_instances({
|
||||
name=name,
|
||||
categorize=categorize
|
||||
},category)
|
||||
|
||||
return instances
|
||||
end
|
||||
|
||||
--- Gets and updates the label values
|
||||
-- @tparam define table the define to get the labels for
|
||||
-- @tparam element LuaGuiElement the element that will be used to get the category
|
||||
local function update_lables(define,element)
|
||||
local instances = get_labels(define,element)
|
||||
local value = element.slider_value
|
||||
if instances then
|
||||
for k,instance in pairs(instances) do
|
||||
if instance and instance.valid then
|
||||
instance.caption = tostring(math.round(value,2))
|
||||
else
|
||||
instances[k]=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Event call for on_value_changed and store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value number 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
|
||||
|
||||
if define.events.on_element_update then
|
||||
define.events.on_element_update(player,element,value,percent)
|
||||
end
|
||||
|
||||
update_lables(define,element)
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value number the new value for the slider
|
||||
local function store_call(define,element,value)
|
||||
element.slider_value = value
|
||||
event_call(define,element,value)
|
||||
end
|
||||
|
||||
local Slider = {
|
||||
_prototype=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new slider element define
|
||||
-- @tparam[opt] name string the optional debug name that can be added
|
||||
-- @treturn table the new slider element define
|
||||
function Slider.new_slider(name)
|
||||
|
||||
local self = Gui._define_factory(Slider._prototype)
|
||||
self.draw_data.type = 'slider'
|
||||
|
||||
if name then
|
||||
self:debug_name(name)
|
||||
end
|
||||
|
||||
self.post_draw = function(element)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
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] min number the minimum value that the slider can take
|
||||
-- @tparam[opt] max number 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 element LuaGuiElement the parent element that the lable 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))
|
||||
}
|
||||
|
||||
if not Gui.instances[name] then Gui.instances[name] = {} end
|
||||
|
||||
local labels = get_labels(self,element)
|
||||
table.insert(labels,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] state boolean 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
|
||||
552
expcore/Gui/test.lua
Normal file
552
expcore/Gui/test.lua
Normal file
@@ -0,0 +1,552 @@
|
||||
--- This file creates a teste gui that is used to test every input method
|
||||
-- note that this does not cover every permutation only features in indepentance
|
||||
-- for example store in most cases is just by player name, but other store methods are tested with checkbox
|
||||
local Gui = require 'expcore.gui'
|
||||
local format_chat_colour,table_keys = ext_require('expcore.common','format_chat_colour','table_keys')
|
||||
local Colors = require 'resources.color_presets'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
local tests = {}
|
||||
|
||||
--[[
|
||||
Toolbar Tests
|
||||
> No display - Toolbar button with no display
|
||||
> With caption - Toolbar button with a caption display
|
||||
> With icons - Toolbar button with an icon
|
||||
> Main test gui - Main test gui triggers all other tests
|
||||
]]
|
||||
|
||||
Gui.new_toolbar_button('click-1')
|
||||
:set_post_authenticator(function(player,button_name)
|
||||
return global.click_one
|
||||
end)
|
||||
:on_click(function(player,element)
|
||||
player.print('CLICK 1')
|
||||
end)
|
||||
|
||||
Gui.new_toolbar_button('click-2')
|
||||
:set_caption('Click Two')
|
||||
:set_post_authenticator(function(player,button_name)
|
||||
return global.click_two
|
||||
end)
|
||||
:on_click(function(player,element)
|
||||
player.print('CLICK 2')
|
||||
end)
|
||||
|
||||
Gui.new_toolbar_button('click-3')
|
||||
:set_sprites('utility/questionmark')
|
||||
:set_post_authenticator(function(player,button_name)
|
||||
return global.click_three
|
||||
end)
|
||||
:on_click(function(player,element)
|
||||
player.print('CLICK 3')
|
||||
end)
|
||||
|
||||
Gui.new_toolbar_button('gui-test-open')
|
||||
:set_caption('Open Test Gui')
|
||||
:set_post_authenticator(function(player,button_name)
|
||||
return global.show_test_gui
|
||||
end)
|
||||
:on_click(function(player,_element)
|
||||
if player.gui.center.TestGui then player.gui.center.TestGui.destroy() return end
|
||||
|
||||
local frame = player.gui.center.add{
|
||||
type='frame',
|
||||
caption='Gui Test',
|
||||
name='TestGui'
|
||||
}
|
||||
|
||||
for test_group_name,test_group in pairs(tests) do
|
||||
|
||||
player.print('Starting tests for: '..format_chat_colour(test_group_name,Colors.cyan))
|
||||
|
||||
local pass_count = 0
|
||||
local test_count = 0
|
||||
|
||||
local flow = frame.add{
|
||||
type='flow',
|
||||
name=test_group_name,
|
||||
direction='vertical'
|
||||
}
|
||||
|
||||
for test_name,test in pairs(test_group) do
|
||||
local test_function = type(test) == 'function' and test or test.draw_to
|
||||
test_count = test_count+1
|
||||
|
||||
local success,err = pcall(test_function,test,flow)
|
||||
if success then
|
||||
pass_count = pass_count+1
|
||||
else
|
||||
player.print('Failed Test: '..format_chat_colour(test_name,Colors.red))
|
||||
log('Gui Test Failed: '..test_name..' stacktrace:\n'..err)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if pass_count == test_count then
|
||||
player.print('All tests '..format_chat_colour('passed',Colors.green)..' ('..test_group_name..')')
|
||||
else
|
||||
player.print('Passed '..format_chat_colour(pass_count..'/'..test_count,Colors.cyan)..' ('..test_group_name..')')
|
||||
end
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
--[[
|
||||
Button Tests
|
||||
> No display - Simple button which has no display
|
||||
> Caption - Simple button but has a caption on it
|
||||
> Icons - Button with an icon display plus two icons for hover and select
|
||||
> Auth - Button which can only be passed when auth is true (press no display to toggle; needs reopen)
|
||||
]]
|
||||
|
||||
local button_no_display =
|
||||
Gui.new_button('test-button-no-display')
|
||||
:set_tooltip('Button no display')
|
||||
:on_click(function(player,element)
|
||||
player.print('Button no display')
|
||||
global.test_auth_button = not global.test_auth_button
|
||||
player.print('Auth Button auth state: '..tostring(global.test_auth_button))
|
||||
end)
|
||||
|
||||
local button_with_caption =
|
||||
Gui.new_button('test-button-with-caption')
|
||||
:set_tooltip('Button with caption')
|
||||
:set_caption('Button Caption')
|
||||
:on_click(function(player,element)
|
||||
player.print('Button with caption')
|
||||
end)
|
||||
|
||||
local button_with_icon =
|
||||
Gui.new_button('test-button-with-icon')
|
||||
:set_tooltip('Button with icons')
|
||||
:set_sprites('utility/warning_icon','utility/warning','utility/warning_white')
|
||||
:on_click(function(player,element)
|
||||
player.print('Button with icons')
|
||||
end)
|
||||
|
||||
local button_with_auth =
|
||||
Gui.new_button('test-button-with-auth')
|
||||
:set_tooltip('Button with auth')
|
||||
:set_post_authenticator(function(player,button_name)
|
||||
return global.test_auth_button
|
||||
end)
|
||||
:on_click(function(player,element)
|
||||
player.print('Button with auth')
|
||||
end)
|
||||
|
||||
tests.Buttons = {
|
||||
['No display']=button_no_display,
|
||||
['Caption']=button_with_caption,
|
||||
['Icons']=button_with_icon,
|
||||
['Auth']=button_with_auth
|
||||
}
|
||||
|
||||
--[[
|
||||
Checkbox Test
|
||||
> Local -- Simple checkbox that can toggle
|
||||
> Game store -- Checkbox which syncs its state between all players
|
||||
> Force store -- Checkbox which syncs its state with all players on the same force
|
||||
> Player store -- Checkbox that stores its state between re-draws
|
||||
]]
|
||||
|
||||
local checkbox_local =
|
||||
Gui.new_checkbox('test-checkbox-local')
|
||||
:set_tooltip('Checkbox local')
|
||||
:set_caption('Checkbox Local')
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Checkbox local: '..tostring(state))
|
||||
end)
|
||||
|
||||
local checkbox_game =
|
||||
Gui.new_checkbox('test-checkbox-store-game')
|
||||
:set_tooltip('Checkbox store game')
|
||||
:set_caption('Checkbox Store Game')
|
||||
:add_store()
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Checkbox store game: '..tostring(state))
|
||||
end)
|
||||
|
||||
local checkbox_force =
|
||||
Gui.new_checkbox('test-checkbox-store-force')
|
||||
:set_tooltip('Checkboc store force')
|
||||
:set_caption('Checkbox Store Force')
|
||||
:add_store(Gui.force_store)
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Checkbox store force: '..tostring(state))
|
||||
end)
|
||||
|
||||
local checkbox_player =
|
||||
Gui.new_checkbox('test-checkbox-store-player')
|
||||
:set_tooltip('Checkbox store player')
|
||||
:set_caption('Checkbox Store Player')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Checkbox store player: '..tostring(state))
|
||||
end)
|
||||
|
||||
tests.Checkboxs = {
|
||||
['Local']=checkbox_local,
|
||||
['Game store']=checkbox_game,
|
||||
['Force store']=checkbox_force,
|
||||
['Player store']=checkbox_player
|
||||
}
|
||||
|
||||
--[[
|
||||
Radiobutton Tests
|
||||
> Local -- Simple radiobutton that can only be toggled true
|
||||
> Player store -- Radio button that saves its state between re-draws
|
||||
> Option set -- A set of radio buttons where only one can be true at a time
|
||||
]]
|
||||
|
||||
local radiobutton_local =
|
||||
Gui.new_radiobutton('test-radiobutton-local')
|
||||
:set_tooltip('Radiobutton local')
|
||||
:set_caption('Radiobutton Local')
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Radiobutton local: '..tostring(state))
|
||||
end)
|
||||
|
||||
local radiobutton_player =
|
||||
Gui.new_radiobutton('test-radiobutton-store')
|
||||
:set_tooltip('Radiobutton store')
|
||||
:set_caption('Radiobutton Store')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Radiobutton store: '..tostring(state))
|
||||
end)
|
||||
|
||||
local radiobutton_option_set =
|
||||
Gui.new_radiobutton_option_set('gui.test.share',function(value,category)
|
||||
game.print('Radiobutton option set for: '..category..' is now: '..tostring(value))
|
||||
end,Gui.player_store)
|
||||
|
||||
local radiobutton_option_one =
|
||||
Gui.new_radiobutton('test-radiobutton-option-one')
|
||||
:set_tooltip('Radiobutton option set')
|
||||
:set_caption('Radiobutton Option One')
|
||||
:add_as_option(radiobutton_option_set,'One')
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Radiobutton option one: '..tostring(state))
|
||||
end)
|
||||
|
||||
local radiobutton_option_two =
|
||||
Gui.new_radiobutton('test-radiobutton-option-two')
|
||||
:set_tooltip('Radiobutton option set')
|
||||
:set_caption('Radiobutton Option Two')
|
||||
:add_as_option(radiobutton_option_set,'Two')
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Radiobutton option two: '..tostring(state))
|
||||
end)
|
||||
|
||||
local radiobutton_option_three =
|
||||
Gui.new_radiobutton('test-radiobutton-option-three')
|
||||
:set_tooltip('Radiobutton option set')
|
||||
:set_caption('Radiobutton Option Three')
|
||||
:add_as_option(radiobutton_option_set,'Three')
|
||||
:on_element_update(function(player,element,state)
|
||||
player.print('Radiobutton option three: '..tostring(state))
|
||||
end)
|
||||
|
||||
tests.Radiobuttons = {
|
||||
['Local']=radiobutton_local,
|
||||
['Player store']=radiobutton_player,
|
||||
['Option set']=function(self,frame)
|
||||
Gui.draw_option_set(radiobutton_option_set,frame)
|
||||
end
|
||||
}
|
||||
|
||||
--[[
|
||||
Dropdown Test
|
||||
> Local static general -- Simple dropdown with all static options and general handler
|
||||
> Player startic general -- Dropdown with all static options and general handler and stores option between re-draws
|
||||
> Local static case -- Dropdown with all static options but case handlers and a general handler
|
||||
> Player static case -- Dropdown with all static options but case handlers and a general handler and stores option between re-draws
|
||||
> Local dynamic -- Dropdown with one static option with the reset generated by a function
|
||||
> Player dynamic -- Dropdown with one static option with the reset generated by a function and stores option between re-draws
|
||||
]]
|
||||
|
||||
local dropdown_local_static_general =
|
||||
Gui.new_dropdown('test-dropdown-local-static-general')
|
||||
:set_tooltip('Dropdown local static general')
|
||||
:add_options('One','Two','Three','Four')
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown local static general: '..tostring(value))
|
||||
end)
|
||||
|
||||
local dropdown_player_static_general =
|
||||
Gui.new_dropdown('test-dropdown-store-static-general')
|
||||
:set_tooltip('Dropdown store static general')
|
||||
:add_options('One','Two','Three','Four')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown store static general: '..tostring(value))
|
||||
end)
|
||||
|
||||
local function print_option_selected_1(player,element,value)
|
||||
player.print('Dropdown local static case (case): '..tostring(value))
|
||||
end
|
||||
|
||||
local dropdown_local_static_case =
|
||||
Gui.new_dropdown('test-dropdown-local-static-case')
|
||||
:set_tooltip('Dropdown local static case')
|
||||
:add_options('One','Two')
|
||||
:add_option_callback('One',print_option_selected_1)
|
||||
:add_option_callback('Two',print_option_selected_1)
|
||||
:add_option_callback('Three',print_option_selected_1)
|
||||
:add_option_callback('Four',print_option_selected_1)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown local static case (general): '..tostring(value))
|
||||
end)
|
||||
|
||||
local function print_option_selected_2(player,element,value)
|
||||
player.print('Dropdown store static case (case): '..tostring(value))
|
||||
end
|
||||
|
||||
local dropdown_player_static_case =
|
||||
Gui.new_dropdown('test-dropdown-store-static-case')
|
||||
:set_tooltip('Dropdown store static case')
|
||||
:add_store(Gui.player_store)
|
||||
:add_options('One','Two')
|
||||
:add_option_callback('One',print_option_selected_2)
|
||||
:add_option_callback('Two',print_option_selected_2)
|
||||
:add_option_callback('Three',print_option_selected_2)
|
||||
:add_option_callback('Four',print_option_selected_2)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown store static case (general): '..tostring(value))
|
||||
end)
|
||||
|
||||
local dropdown_local_dynamic =
|
||||
Gui.new_dropdown('test-dropdown-local-dynamic')
|
||||
:set_tooltip('Dropdown local dynamic')
|
||||
:add_options('Static')
|
||||
:add_dynamic(function(player,element)
|
||||
return table_keys(Colors)
|
||||
end)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown local dynamic: '..tostring(value))
|
||||
end)
|
||||
|
||||
local dropdown_player_dynamic =
|
||||
Gui.new_dropdown('test-dropdown-store-dynamic')
|
||||
:set_tooltip('Dropdown store dynamic')
|
||||
:add_options('Static')
|
||||
:add_dynamic(function(player,element)
|
||||
return table_keys(Colors)
|
||||
end)
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown store dynamic: '..tostring(value))
|
||||
end)
|
||||
|
||||
tests.Dropdowns = {
|
||||
['Local static general']=dropdown_local_static_general,
|
||||
['Player startic general']=dropdown_player_static_general,
|
||||
['Local static case']=dropdown_local_static_case,
|
||||
['Player static case']=dropdown_player_static_case,
|
||||
['Local dynamic general']=dropdown_local_dynamic,
|
||||
['Player dynamic general']=dropdown_player_dynamic
|
||||
}
|
||||
|
||||
--[[
|
||||
List Box Tests
|
||||
> Local -- A list box with all static options and general handler
|
||||
> Store -- A list box with all static options and general handler and stores options between re-draws
|
||||
]]
|
||||
|
||||
local list_box_local =
|
||||
Gui.new_list_box('test-list-box-local')
|
||||
:set_tooltip('List box local')
|
||||
:add_options('One','Two','Three','Four')
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown local: '..tostring(value))
|
||||
end)
|
||||
|
||||
local list_box_player =
|
||||
Gui.new_list_box('test-list-box-store')
|
||||
:set_tooltip('List box store')
|
||||
:add_options('One','Two','Three','Four')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Dropdown store: '..tostring(value))
|
||||
end)
|
||||
|
||||
tests["List Boxs"] = {
|
||||
['Local']=list_box_local,
|
||||
['Player']=list_box_player
|
||||
}
|
||||
|
||||
--[[
|
||||
Slider Tests
|
||||
> Local default -- Simple slider with default range
|
||||
> Store default -- Slider with default range that stores value between re-draws
|
||||
> Static range -- Simple slider with a static range
|
||||
> Dynamic range -- Slider with a dynamic range
|
||||
> Local label -- Simple slider with default range which has a label
|
||||
> Store label -- Slider with default range which has a label and stores value between re-draws
|
||||
]]
|
||||
|
||||
local slider_local_default =
|
||||
Gui.new_slider('test-slider-local-default')
|
||||
:set_tooltip('Silder local default')
|
||||
:on_element_update(function(player,element,value,percent)
|
||||
player.print('Slider local default: '..tostring(math.round(value))..' '..tostring(math.round(percent,1)))
|
||||
end)
|
||||
|
||||
local slider_player_default =
|
||||
Gui.new_slider('test-slider-store-default')
|
||||
:set_tooltip('Silder store default')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value,percent)
|
||||
player.print('Slider store default: '..tostring(math.round(value))..' '..tostring(math.round(percent,1)))
|
||||
end)
|
||||
|
||||
local slider_static =
|
||||
Gui.new_slider('test-slider-static-range')
|
||||
:set_tooltip('Silder static range')
|
||||
:set_range(5,50)
|
||||
:on_element_update(function(player,element,value,percent)
|
||||
player.print('Slider static range: '..tostring(math.round(value))..' '..tostring(math.round(percent,1)))
|
||||
end)
|
||||
|
||||
local slider_dynamic =
|
||||
Gui.new_slider('test-slider-dynamic-range')
|
||||
:set_tooltip('Silder dynamic range')
|
||||
:set_range(function(player,element)
|
||||
return player.index - 5
|
||||
end,function(player,element)
|
||||
return player.index + 4
|
||||
end)
|
||||
:on_element_update(function(player,element,value,percent)
|
||||
player.print('Slider dynamic range: '..tostring(math.round(value))..' '..tostring(math.round(percent,1)))
|
||||
end)
|
||||
|
||||
local label_slider_local =
|
||||
Gui.new_slider('test-slider-local-label')
|
||||
:set_tooltip('Silder local label')
|
||||
:enable_auto_draw_label()
|
||||
:on_element_update(function(player,element,value,percent)
|
||||
player.print('Slider local label: '..tostring(math.round(value))..' '..tostring(math.round(percent,1)))
|
||||
end)
|
||||
|
||||
local label_slider_player =
|
||||
Gui.new_slider('test-slider-store-label')
|
||||
:set_tooltip('Silder store label')
|
||||
:enable_auto_draw_label()
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value,percent)
|
||||
player.print('Slider store label: '..tostring(math.round(value))..' '..tostring(math.round(percent,1)))
|
||||
end)
|
||||
|
||||
tests.Sliders = {
|
||||
['Local default']=slider_local_default,
|
||||
['Player default']=slider_player_default,
|
||||
['Static range']=slider_static,
|
||||
['Dynamic range']=slider_dynamic,
|
||||
['Local label']=function(self,frame)
|
||||
local flow = frame.add{type='flow'}
|
||||
label_slider_local:draw_to(flow)
|
||||
end,
|
||||
['Player label']=function(self,frame)
|
||||
local flow = frame.add{type='flow'}
|
||||
label_slider_player:draw_to(flow)
|
||||
end
|
||||
}
|
||||
|
||||
--[[
|
||||
Text Tests
|
||||
> Local field -- Simple text field
|
||||
> Store field -- Test field that stores text between re-draws
|
||||
> Local box -- Simple text box
|
||||
> Wrap box -- Text box which has word wrap and selection disabled
|
||||
]]
|
||||
|
||||
local text_filed_local =
|
||||
Gui.new_text_filed('test-text-field-local')
|
||||
:set_tooltip('Text field local')
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Text field local: '..value)
|
||||
end)
|
||||
|
||||
local text_filed_store =
|
||||
Gui.new_text_filed('test-text-field-store')
|
||||
:set_tooltip('Text field store')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Text field store: '..value)
|
||||
end)
|
||||
|
||||
local text_box_local =
|
||||
Gui.new_text_box('test-text-box-local')
|
||||
:set_tooltip('Text box local')
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Text box local: '..value)
|
||||
end)
|
||||
|
||||
local text_box_wrap =
|
||||
Gui.new_text_box('test-text-box-wrap')
|
||||
:set_tooltip('Text box wrap')
|
||||
:set_selectable(false)
|
||||
:set_word_wrap()
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Text box wrap: '..value)
|
||||
end)
|
||||
|
||||
tests.Texts = {
|
||||
['Local field']=text_filed_local,
|
||||
['Store field']=text_filed_store,
|
||||
['Local box']=text_box_local,
|
||||
['Wrap box']=text_box_wrap
|
||||
}
|
||||
|
||||
--[[
|
||||
Elem Button Tests
|
||||
> Local -- Simple elem button
|
||||
> Default -- Simple elem button which has a default value
|
||||
> Function -- Elem button which has a dynamic default
|
||||
> Store -- Elem button which stores its value between re-draws
|
||||
]]
|
||||
|
||||
local elem_local =
|
||||
Gui.new_elem_button('test-elem-local')
|
||||
:set_tooltip('Elem')
|
||||
:set_type('item')
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Elem: '..value)
|
||||
end)
|
||||
|
||||
local elem_default =
|
||||
Gui.new_elem_button('test-elem-default')
|
||||
:set_tooltip('Elem default')
|
||||
:set_type('item')
|
||||
:set_default('iron-plate')
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Elem default: '..value)
|
||||
end)
|
||||
|
||||
local elem_function =
|
||||
Gui.new_elem_button('test-elem-function')
|
||||
:set_tooltip('Elem function')
|
||||
:set_type('item')
|
||||
:set_default(function(player,element)
|
||||
return 'iron-plate'
|
||||
end)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Elem function: '..value)
|
||||
end)
|
||||
|
||||
local elem_store =
|
||||
Gui.new_elem_button('test-elem-store')
|
||||
:set_tooltip('Elem store')
|
||||
:set_type('item')
|
||||
:add_store(Gui.player_store)
|
||||
:on_element_update(function(player,element,value)
|
||||
player.print('Elem store: '..value)
|
||||
end)
|
||||
|
||||
tests["Elem Buttons"] = {
|
||||
['Local']=elem_local,
|
||||
['Default']=elem_default,
|
||||
['Function']=elem_function,
|
||||
['Store']=elem_store
|
||||
}
|
||||
156
expcore/Gui/text.lua
Normal file
156
expcore/Gui/text.lua
Normal file
@@ -0,0 +1,156 @@
|
||||
--- Gui class define for text fields and text boxs
|
||||
--[[
|
||||
>>>> 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 './core'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
--- Event call for on_text_changed and store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value string the new text for the text field
|
||||
local function event_call(define,element,value)
|
||||
local player = Game.get_player_by_index(element.player_index)
|
||||
|
||||
if define.events.on_element_update then
|
||||
define.events.on_element_update(player,element,value)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Store call for store update
|
||||
-- @tparam define table the define that this is acting on
|
||||
-- @tparam element LuaGuiElement the element that triggered the event
|
||||
-- @tparam value string the new text for the text field
|
||||
local function store_call(self,element,value)
|
||||
element.text = value
|
||||
event_call(self,element,value)
|
||||
end
|
||||
|
||||
local Text = {
|
||||
_prototype_field=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
},
|
||||
_prototype_box=Gui._prototype_factory{
|
||||
on_element_update = Gui._event_factory('on_element_update'),
|
||||
on_store_update = Gui._event_factory('on_store_update'),
|
||||
add_store = Gui._store_factory(store_call),
|
||||
add_sync_store = Gui._sync_store_factory(store_call)
|
||||
}
|
||||
}
|
||||
|
||||
--- Creates a new text field element define
|
||||
-- @tparam[opt] name string 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._define_factory(Text._prototype_field)
|
||||
self.draw_data.type = 'textfield'
|
||||
|
||||
if name then
|
||||
self:debug_name(name)
|
||||
end
|
||||
|
||||
self.post_draw = function(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
|
||||
event_call(self,element,value)
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new text box element define
|
||||
-- @tparam[opt] name string 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] state boolean 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] state boolean 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] state boolean 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
|
||||
82
expcore/Gui/toolbar.lua
Normal file
82
expcore/Gui/toolbar.lua
Normal file
@@ -0,0 +1,82 @@
|
||||
--- Gui structure for the toolbar (top left)
|
||||
--[[
|
||||
>>>> 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 Buttons = require './buttons'
|
||||
local Gui = require './core'
|
||||
local Roles = require 'expcore.roles'
|
||||
local Event = require 'utils.event'
|
||||
local Game = require 'utils.game'
|
||||
|
||||
local Toolbar = {
|
||||
buttons = {}
|
||||
}
|
||||
|
||||
--- Adds a new button to the toolbar
|
||||
-- @tparam[opt] name string the name of the button to be added
|
||||
-- @treturn table the button define
|
||||
function Toolbar.new_button(name)
|
||||
name = name or #Toolbar.buttons+1
|
||||
local button = Buttons.new_button('toolbar/'..name)
|
||||
button:set_post_authenticator(Roles.player_allowed)
|
||||
Toolbar.add_button(button)
|
||||
return button
|
||||
end
|
||||
|
||||
--- Adds an existing buttton to the toolbar
|
||||
-- @tparam button table 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 player LuaPlayer 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.player_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.player_role_unassigned,function(event)
|
||||
local player = Game.get_player_by_index(event.player_index)
|
||||
Toolbar.update(player)
|
||||
end)
|
||||
|
||||
return Toolbar
|
||||
150
expcore/gui.lua
Normal file
150
expcore/gui.lua
Normal file
@@ -0,0 +1,150 @@
|
||||
--- 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 seperate files in ./gui
|
||||
|
||||
local Gui = require('./gui/core')
|
||||
--[[
|
||||
Gui._prototype_factory(tbl) --- Used internally to create new prototypes for element defines
|
||||
Gui._event_factory(name) --- Used internally to create event handler adders for element defines
|
||||
Gui._store_factory(callback) --- Used internally to create store adders for element defines
|
||||
Gui._sync_store_factory(callback) --- Used internally to create synced store adders for element defines
|
||||
Gui._define_factory(prototype) --- Used internally to create new element defines from a class prototype
|
||||
|
||||
Gui._prototype:uid() --- Gets the uid for the element define
|
||||
Gui._prototype:debug_name(name) --- Sets a debug alias for the define
|
||||
Gui._prototype:set_caption(caption) --- Sets the caption for the element define
|
||||
Gui._prototype:set_tooltip(tooltip) --- Sets the tooltip for the element define
|
||||
Gui._prototype:on_element_update(callback) --- Add a hander to run on the general value update event, different classes will handle this event differently
|
||||
|
||||
Gui._prototype:set_pre_authenticator(callback) --- Sets an authenticator that blocks the draw function if check fails
|
||||
Gui._prototype:set_post_authenticator(callback) --- Sets an authenticator that disables the element if check fails
|
||||
Gui._prototype:draw_to(element) --- Draws the element using what is in the draw_data table, allows use of authenticator if present, registers new instances if store present
|
||||
Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to
|
||||
|
||||
Gui._prototype:add_store(categorize) --- Adds a store location for the define that will save the state of the element, categorize is a function that returns a string
|
||||
Gui._prototype:add_sync_store(location,categorize) --- Adds a store location for the define that will sync between games, categorize is a function that returns a string
|
||||
Gui._prototype:on_store_update(callback) --- Adds a event callback for when the store changes are other events are not gauenteted to be raised
|
||||
Gui.player_store(element) --- A categorize function to be used with add_store, each player has their own value
|
||||
Gui.force_store(element) --- A categorize function to be used with add_store, each force has its own value
|
||||
Gui.surface_store(element) --- A categorize function to be used with add_store, each surface has its own value
|
||||
|
||||
Gui._prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used
|
||||
Gui._prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used
|
||||
Gui.get_store(name,category) --- Gets the value that is stored for a given element define, category needed if categorize function used
|
||||
Gui.set_store(name,category,value) --- Sets the value stored for a given element define, category needed if categorize function used
|
||||
|
||||
Gui.toggle_enable(element) --- Will toggle the enabled state of an element
|
||||
Gui.toggle_visible(element) --- Will toggle the visiblity of an element
|
||||
]]
|
||||
|
||||
local Button = require('./gui/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 spirte 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 Toolbar = require('./gui/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 Checkbox = require('./gui/checkboxs')
|
||||
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 radiobutotns (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 radiobutotn in a element to false (unless excluded) and can act recursivly
|
||||
]]
|
||||
|
||||
local Dropdown = require('./gui/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('./gui/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('./gui/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('./gui/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
|
||||
]]
|
||||
|
||||
return Gui
|
||||
@@ -24,4 +24,9 @@ error-log-format-promote=[ERROR] rolePromote/__1__ :: __2__
|
||||
game-message-assign=__1__ has been assigned to __2__ by __3__
|
||||
game-message-unassign=__1__ has been unassigned from __2__ by __3__
|
||||
reject-role=Invalid Role Name.
|
||||
reject-player-role=Player has a higher role.
|
||||
reject-player-role=Player has a higher role.
|
||||
|
||||
[gui_util]
|
||||
button_tooltip=Shows / hides the Toolbar Gui buttons.
|
||||
|
||||
[expcore-gui]
|
||||
|
||||
@@ -74,11 +74,28 @@
|
||||
Store.add_watch('game.speed',function()
|
||||
return game.speed
|
||||
end)
|
||||
|
||||
>>>> Alternative method
|
||||
Some people may prefer to use a varible rather than a string for formating reasons here is an example. Also for any times when
|
||||
there will be little external input Store.uid_location() can be used to generate non conflicting locations, use of register_synced will
|
||||
still require a name other wise there may be mirgration issuses.
|
||||
|
||||
local store_game_speed = Store.uid_location()
|
||||
|
||||
Store.register(store_game_speed,function(value)
|
||||
game.print('The game speed has been set to: '..value)
|
||||
end)
|
||||
|
||||
Store.add_watch(store_game_speed,function()
|
||||
return game.speed
|
||||
end)
|
||||
|
||||
]]
|
||||
|
||||
local Global = require 'util.global'
|
||||
local Event = require 'util.event'
|
||||
local write_json,table_keys = ext_require('expcore.common','write_json','table_keys')
|
||||
local Global = require 'utils.global'
|
||||
local Event = require 'utils.event'
|
||||
local write_json = ext_require('expcore.common','write_json','table_keys')
|
||||
local Token = require 'utils.token'
|
||||
|
||||
local Store = {
|
||||
data={},
|
||||
@@ -90,6 +107,19 @@ Global.register(Store.data,function(tbl)
|
||||
Store.data = tbl
|
||||
end)
|
||||
|
||||
--- Check for if a lcoation is registered
|
||||
-- @tparam location string the location to test for
|
||||
-- @treturn boolean true if registered
|
||||
function Store.is_registered(location)
|
||||
return not not Store.callbacks[location]
|
||||
end
|
||||
|
||||
--- Returns a unqiue name that can be used for a store
|
||||
-- @treturn string a unqiue name
|
||||
function Store.uid_location()
|
||||
return tostring(Token.uid())
|
||||
end
|
||||
|
||||
--- Registers a new location with an update callback which is triggered when the value updates
|
||||
-- @tparam location string a unique string that points to the data, string used rather than token to allow migration
|
||||
-- @tparam callback function this callback will be called when the stored value is set to a new value
|
||||
@@ -109,6 +139,8 @@ function Store.register(location,callback,start_value)
|
||||
|
||||
Store.data[location] = start_value
|
||||
Store.callbacks[location] = callback
|
||||
|
||||
return location
|
||||
end
|
||||
|
||||
--- Registers a new cross server synced location with an update callback, and external script is required for cross server
|
||||
@@ -167,8 +199,9 @@ end
|
||||
--- Sets the value at a location, this location must be registered, if server synced it will emit the change to file
|
||||
-- @tparam location string the location to set the data to
|
||||
-- @tparam value any the new value to set at the location, value may be reverted if there is a watch callback
|
||||
-- @treturn boolean true if it was successful
|
||||
function Store.set(location,value)
|
||||
if not Store.callbacks[location] and not no_error then
|
||||
if not Store.callbacks[location] then
|
||||
return error('Location is not registered', 2)
|
||||
end
|
||||
|
||||
@@ -181,6 +214,8 @@ function Store.set(location,value)
|
||||
value=value
|
||||
})
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Gets all non nil children at a location, children can be added and removed during runtime
|
||||
@@ -190,7 +225,7 @@ end
|
||||
function Store.get_children(location)
|
||||
local store = Store.get(location)
|
||||
|
||||
if type(store) ~= 'table' and table ~= nil then
|
||||
if type(store) ~= 'table' and store ~= nil then
|
||||
return error('Location has a non table value', 2)
|
||||
end
|
||||
|
||||
@@ -204,11 +239,11 @@ end
|
||||
function Store.get_child(location,child)
|
||||
local store = Store.get(location)
|
||||
|
||||
if type(store) ~= 'table' and table ~= nil then
|
||||
if type(store) ~= 'table' and store ~= nil then
|
||||
return error('Location has a non table value', 2)
|
||||
end
|
||||
|
||||
return store[child]
|
||||
return store and store[child]
|
||||
end
|
||||
|
||||
--- Sets the value of the chlid to a location, children can be added and removed during runtime
|
||||
@@ -217,10 +252,11 @@ end
|
||||
-- @tparam location string the location of which the child is located
|
||||
-- @tparam child string the child element to set the value of
|
||||
-- @tparam value any the value to set at this location
|
||||
-- @treturn boolean true if it was successful
|
||||
function Store.set_child(location,child,value)
|
||||
local store = Store.get(location)
|
||||
|
||||
if type(store) ~= 'table' and table ~= nil then
|
||||
if type(store) ~= 'table' and store ~= nil then
|
||||
return error('Location has a non table value', 2)
|
||||
end
|
||||
|
||||
@@ -238,6 +274,8 @@ function Store.set_child(location,child,value)
|
||||
value=value
|
||||
})
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Event handler for the watcher callbacks
|
||||
@@ -251,14 +289,18 @@ Event.add(defines.events.on_tick,function()
|
||||
if not success then
|
||||
table.insert(errors,store_new)
|
||||
else
|
||||
if store_old ~= store_new then
|
||||
if type(store_old) ~= type(store_new)
|
||||
or type(store_old) == 'table' and not table.compare(store_new,store_new)
|
||||
or store_old ~= store_new then
|
||||
Store.data[location] = store_new
|
||||
Store.callbacks[location](store_new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
error(errors)
|
||||
if #errors > 0 then
|
||||
error(table.concat(errors,'; '))
|
||||
end
|
||||
end)
|
||||
|
||||
return Store
|
||||
@@ -1,5 +1,4 @@
|
||||
time-symbol-days-short=__1__d
|
||||
color-tag=[color=__1__]__2__[/color]
|
||||
|
||||
[expcore-commands]
|
||||
unauthorized=Unauthorized, Access is denied due to invalid credentials
|
||||
@@ -25,4 +24,9 @@ error-log-format-promote=[ERROR] rolePromote/__1__ :: __2__
|
||||
game-message-assign=__1__ has been assigned to __2__ by __3__
|
||||
game-message-unassign=__1__ has been unassigned from __2__ by __3__
|
||||
reject-role=Invalid Role Name.
|
||||
reject-player-role=Player has a higher role.
|
||||
reject-player-role=Player has a higher role.
|
||||
|
||||
[gui_util]
|
||||
button_tooltip=Shows / hides the Toolbar Gui buttons.
|
||||
|
||||
[expcore-gui]
|
||||
|
||||
7
modules/commands/debug.lua
Normal file
7
modules/commands/debug.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
local DebugView = require 'modules.gui.debug.main_view'
|
||||
local Commands = require 'expcore.commands'
|
||||
|
||||
Commands.new_command('debug','Opens the debug pannel for viewing tables.')
|
||||
:register(function(player,raw)
|
||||
DebugView.open_dubug(player)
|
||||
end)
|
||||
@@ -10,7 +10,8 @@ local interface_modules = {
|
||||
['output']=Common.player_return,
|
||||
['Group']='expcore.permission_groups',
|
||||
['Roles']='expcore.roles',
|
||||
['Store']='expcore.store'
|
||||
['Store']='expcore.store',
|
||||
['Gui']='expcore.gui'
|
||||
}
|
||||
|
||||
-- loads all the modules given in the above table
|
||||
@@ -95,5 +96,6 @@ add_interface_callback('tile',function(player) return player.surface.get_tile(pl
|
||||
return {
|
||||
add_interface_callback=add_interface_callback,
|
||||
interface_env=interface_env,
|
||||
interface_callbacks=interface_callbacks
|
||||
interface_callbacks=interface_callbacks,
|
||||
clean_stack_trace=function(str) return str:gsub('%.%.%..-/temp/currently%-playing','') end
|
||||
}
|
||||
114
modules/gui/debug/_g_view.lua
Normal file
114
modules/gui/debug/_g_view.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Model = require 'modules.gui.debug.model'
|
||||
local Color = require 'resources.color_presets'
|
||||
|
||||
local dump = Model.dump
|
||||
|
||||
local Public = {}
|
||||
|
||||
local ignore = {
|
||||
_G = true,
|
||||
assert = true,
|
||||
collectgarbage = true,
|
||||
error = true,
|
||||
getmetatable = true,
|
||||
ipairs = true,
|
||||
load = true,
|
||||
loadstring = true,
|
||||
next = true,
|
||||
pairs = true,
|
||||
pcall = true,
|
||||
print = true,
|
||||
rawequal = true,
|
||||
rawlen = true,
|
||||
rawget = true,
|
||||
rawset = true,
|
||||
select = true,
|
||||
setmetatable = true,
|
||||
tonumber = true,
|
||||
tostring = true,
|
||||
type = true,
|
||||
xpcall = true,
|
||||
_VERSION = true,
|
||||
module = true,
|
||||
require = true,
|
||||
package = true,
|
||||
unpack = true,
|
||||
table = true,
|
||||
string = true,
|
||||
bit32 = true,
|
||||
math = true,
|
||||
debug = true,
|
||||
serpent = true,
|
||||
log = true,
|
||||
table_size = true,
|
||||
global = true,
|
||||
remote = true,
|
||||
commands = true,
|
||||
settings = true,
|
||||
rcon = true,
|
||||
script = true,
|
||||
util = true,
|
||||
mod_gui = true,
|
||||
game = true,
|
||||
rendering = true
|
||||
}
|
||||
|
||||
local header_name = Gui.uid_name()
|
||||
local left_panel_name = Gui.uid_name()
|
||||
local right_panel_name = Gui.uid_name()
|
||||
|
||||
Public.name = '_G'
|
||||
|
||||
function Public.show(container)
|
||||
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
|
||||
local left_panel_style = left_panel.style
|
||||
left_panel_style.width = 300
|
||||
|
||||
for key, value in pairs(_G) do
|
||||
if not ignore[key] then
|
||||
local header =
|
||||
left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = tostring(key)}
|
||||
Gui.set_data(header, value)
|
||||
end
|
||||
end
|
||||
|
||||
local right_panel = main_flow.add {type = 'text-box', name = right_panel_name}
|
||||
right_panel.read_only = true
|
||||
right_panel.selectable = true
|
||||
|
||||
local right_panel_style = right_panel.style
|
||||
right_panel_style.vertically_stretchable = true
|
||||
right_panel_style.horizontally_stretchable = true
|
||||
right_panel_style.maximal_width = 1000
|
||||
right_panel_style.maximal_height = 1000
|
||||
|
||||
Gui.set_data(left_panel, {right_panel = right_panel, selected_header = nil})
|
||||
end
|
||||
|
||||
Gui.on_click(
|
||||
header_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local value = Gui.get_data(element)
|
||||
|
||||
local left_panel = element.parent.parent
|
||||
local left_panel_data = Gui.get_data(left_panel)
|
||||
local right_panel = left_panel_data.right_panel
|
||||
local selected_header = left_panel_data.selected_header
|
||||
|
||||
if selected_header then
|
||||
selected_header.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
left_panel_data.selected_header = element
|
||||
|
||||
local content = dump(value)
|
||||
right_panel.text = content
|
||||
end
|
||||
)
|
||||
|
||||
return Public
|
||||
117
modules/gui/debug/event_view.lua
Normal file
117
modules/gui/debug/event_view.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
local Event = require 'utils.event'
|
||||
local table = require 'utils.table'
|
||||
local Gui = require 'utils.gui'
|
||||
local Model = require 'modules.gui.debug.model'
|
||||
|
||||
local format = string.format
|
||||
local insert = table.insert
|
||||
|
||||
local events = defines.events
|
||||
|
||||
-- Constants
|
||||
local events_to_keep = 10
|
||||
|
||||
-- Local vars
|
||||
local Public = {
|
||||
name = 'Events'
|
||||
}
|
||||
local name_lookup = {}
|
||||
|
||||
-- GUI names
|
||||
local checkbox_name = Gui.uid_name()
|
||||
|
||||
-- global tables
|
||||
local enabled = {}
|
||||
local last_events = {}
|
||||
global.debug_event_view = {
|
||||
enabled = enabled,
|
||||
last_events = last_events
|
||||
}
|
||||
|
||||
function Public.on_open_debug()
|
||||
local tbl = global.debug_event_view
|
||||
if tbl then
|
||||
enabled = tbl.enabled
|
||||
last_events = tbl.last_events
|
||||
else
|
||||
enabled = {}
|
||||
last_events = {}
|
||||
|
||||
global.debug_event_view = {
|
||||
enabled = enabled,
|
||||
last_events = last_events
|
||||
}
|
||||
end
|
||||
|
||||
Public.on_open_debug = nil
|
||||
end
|
||||
|
||||
-- Local functions
|
||||
local function event_callback(event)
|
||||
local id = event.name
|
||||
if not enabled[id] then
|
||||
return
|
||||
end
|
||||
local name = name_lookup[id]
|
||||
|
||||
if not last_events[name] then
|
||||
last_events[name] = {}
|
||||
end
|
||||
|
||||
insert(last_events[name], 1, event)
|
||||
last_events[name][events_to_keep + 1] = nil
|
||||
event.name = nil
|
||||
|
||||
local str = format('%s (id = %s): %s', name, id, Model.dump(event))
|
||||
game.print(str)
|
||||
log(str)
|
||||
end
|
||||
|
||||
local function on_gui_checked_state_changed(event)
|
||||
local element = event.element
|
||||
local name = element.caption
|
||||
local id = events[name]
|
||||
local state = element.state and true or false
|
||||
element.state = state
|
||||
if state then
|
||||
enabled[id] = true
|
||||
else
|
||||
enabled[id] = false
|
||||
end
|
||||
end
|
||||
|
||||
-- GUI
|
||||
|
||||
-- Create a table with events sorted by their names
|
||||
local grid_builder = {}
|
||||
for name, _ in pairs(events) do
|
||||
grid_builder[#grid_builder + 1] = name
|
||||
end
|
||||
|
||||
table.sort(grid_builder)
|
||||
|
||||
function Public.show(container)
|
||||
local main_frame_flow = container.add({type = 'flow', direction = 'vertical'})
|
||||
local scroll_pane = main_frame_flow.add({type = 'scroll-pane'})
|
||||
local gui_table = scroll_pane.add({type = 'table', column_count = 3, draw_horizontal_lines = true})
|
||||
|
||||
for _, event_name in pairs(grid_builder) do
|
||||
local index = events[event_name]
|
||||
gui_table.add({type = 'flow'}).add {
|
||||
name = checkbox_name,
|
||||
type = 'checkbox',
|
||||
state = enabled[index] or false,
|
||||
caption = event_name
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
Gui.on_checked_state_changed(checkbox_name, on_gui_checked_state_changed)
|
||||
|
||||
-- Event registers (TODO: turn to removable hooks.. maybe)
|
||||
for name, id in pairs(events) do
|
||||
name_lookup[id] = name
|
||||
Event.add(id, event_callback)
|
||||
end
|
||||
|
||||
return Public
|
||||
133
modules/gui/debug/global_view.lua
Normal file
133
modules/gui/debug/global_view.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Model = require 'modules.gui.debug.model'
|
||||
local Color = require 'resources.color_presets'
|
||||
|
||||
local dump = Model.dump
|
||||
local dump_text = Model.dump_text
|
||||
local concat = table.concat
|
||||
|
||||
local Public = {}
|
||||
|
||||
local ignore = {tokens = true}
|
||||
|
||||
local header_name = Gui.uid_name()
|
||||
local left_panel_name = Gui.uid_name()
|
||||
local right_panel_name = Gui.uid_name()
|
||||
local input_text_box_name = Gui.uid_name()
|
||||
local refresh_name = Gui.uid_name()
|
||||
|
||||
Public.name = 'global'
|
||||
|
||||
function Public.show(container)
|
||||
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
|
||||
local left_panel_style = left_panel.style
|
||||
left_panel_style.width = 300
|
||||
|
||||
for key, _ in pairs(global) do
|
||||
if not ignore[key] then
|
||||
local header =
|
||||
left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = tostring(key)}
|
||||
Gui.set_data(header, key)
|
||||
end
|
||||
end
|
||||
|
||||
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
|
||||
|
||||
local right_top_flow = right_flow.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local input_text_box = right_top_flow.add {type = 'text-box', name = input_text_box_name}
|
||||
local input_text_box_style = input_text_box.style
|
||||
input_text_box_style.horizontally_stretchable = true
|
||||
input_text_box_style.height = 32
|
||||
input_text_box_style.maximal_width = 1000
|
||||
|
||||
local refresh_button =
|
||||
right_top_flow.add {type = 'sprite-button', name = refresh_name, sprite = 'utility/reset', tooltip = 'refresh'}
|
||||
local refresh_button_style = refresh_button.style
|
||||
refresh_button_style.width = 32
|
||||
refresh_button_style.height = 32
|
||||
|
||||
local right_panel = right_flow.add {type = 'text-box', name = right_panel_name}
|
||||
right_panel.read_only = true
|
||||
right_panel.selectable = true
|
||||
|
||||
local right_panel_style = right_panel.style
|
||||
right_panel_style.vertically_stretchable = true
|
||||
right_panel_style.horizontally_stretchable = true
|
||||
right_panel_style.maximal_width = 1000
|
||||
right_panel_style.maximal_height = 1000
|
||||
|
||||
local data = {
|
||||
right_panel = right_panel,
|
||||
input_text_box = input_text_box,
|
||||
selected_header = nil,
|
||||
selected_token_id = nil
|
||||
}
|
||||
|
||||
Gui.set_data(input_text_box, data)
|
||||
Gui.set_data(left_panel, data)
|
||||
Gui.set_data(refresh_button, data)
|
||||
end
|
||||
|
||||
Gui.on_click(
|
||||
header_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local key = Gui.get_data(element)
|
||||
|
||||
local left_panel = element.parent.parent
|
||||
local data = Gui.get_data(left_panel)
|
||||
local right_panel = data.right_panel
|
||||
local selected_header = data.selected_header
|
||||
local input_text_box = data.input_text_box
|
||||
|
||||
if selected_header then
|
||||
selected_header.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
data.selected_header = element
|
||||
|
||||
input_text_box.text = concat {"global['", key, "']"}
|
||||
input_text_box.style.font_color = Color.black
|
||||
|
||||
local content = dump(global[key]) or 'nil'
|
||||
right_panel.text = content
|
||||
end
|
||||
)
|
||||
|
||||
local function update_dump(text_input, data, player)
|
||||
local suc, ouput = dump_text(text_input.text, player)
|
||||
if not suc then
|
||||
text_input.style.font_color = Color.red
|
||||
else
|
||||
text_input.style.font_color = Color.black
|
||||
data.right_panel.text = ouput
|
||||
end
|
||||
end
|
||||
|
||||
Gui.on_text_changed(
|
||||
input_text_box_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local data = Gui.get_data(element)
|
||||
|
||||
update_dump(element, data, event.player)
|
||||
end
|
||||
)
|
||||
|
||||
Gui.on_click(
|
||||
refresh_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local data = Gui.get_data(element)
|
||||
|
||||
local input_text_box = data.input_text_box
|
||||
|
||||
update_dump(input_text_box, data, event.player)
|
||||
end
|
||||
)
|
||||
|
||||
return Public
|
||||
103
modules/gui/debug/main_view.lua
Normal file
103
modules/gui/debug/main_view.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Color = require 'resources.color_presets'
|
||||
|
||||
local Public = {}
|
||||
|
||||
local pages = {
|
||||
require 'modules.gui.debug.redmew_global_view',
|
||||
require 'modules.gui.debug.global_view',
|
||||
require 'modules.gui.debug.package_view',
|
||||
require 'modules.gui.debug._g_view',
|
||||
require 'modules.gui.debug.event_view'
|
||||
}
|
||||
|
||||
local main_frame_name = Gui.uid_name()
|
||||
local close_name = Gui.uid_name()
|
||||
local tab_name = Gui.uid_name()
|
||||
|
||||
function Public.open_dubug(player)
|
||||
for i = 1, #pages do
|
||||
local page = pages[i]
|
||||
local callback = page.on_open_debug
|
||||
if callback then
|
||||
callback()
|
||||
end
|
||||
end
|
||||
|
||||
local center = player.gui.center
|
||||
local frame = center[main_frame_name]
|
||||
if frame then
|
||||
return
|
||||
end
|
||||
|
||||
frame = center.add {type = 'frame', name = main_frame_name, caption = 'Debuggertron 3001', direction = 'vertical'}
|
||||
local frame_style = frame.style
|
||||
frame_style.height = 600
|
||||
frame_style.width = 900
|
||||
|
||||
local tab_flow = frame.add {type = 'flow', direction = 'horizontal'}
|
||||
local container = frame.add {type = 'flow'}
|
||||
container.style.vertically_stretchable = true
|
||||
|
||||
local data = {}
|
||||
|
||||
for i = 1, #pages do
|
||||
local page = pages[i]
|
||||
local tab_button = tab_flow.add({type = 'flow'}).add {type = 'button', name = tab_name, caption = page.name}
|
||||
local tab_button_style = tab_button.style
|
||||
|
||||
Gui.set_data(tab_button, {index = i, frame_data = data})
|
||||
|
||||
if i == 1 then
|
||||
tab_button_style.font_color = Color.orange
|
||||
|
||||
data.selected_index = i
|
||||
data.selected_tab_button = tab_button
|
||||
data.container = container
|
||||
|
||||
Gui.set_data(frame, data)
|
||||
page.show(container)
|
||||
end
|
||||
end
|
||||
|
||||
frame.add {type = 'button', name = close_name, caption = 'Close'}
|
||||
end
|
||||
|
||||
Gui.on_click(
|
||||
tab_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local data = Gui.get_data(element)
|
||||
|
||||
local index = data.index
|
||||
local frame_data = data.frame_data
|
||||
local selected_index = frame_data.selected_index
|
||||
|
||||
if selected_index == index then
|
||||
return
|
||||
end
|
||||
|
||||
local selected_tab_button = frame_data.selected_tab_button
|
||||
selected_tab_button.style.font_color = Color.black
|
||||
|
||||
frame_data.selected_tab_button = element
|
||||
frame_data.selected_index = index
|
||||
element.style.font_color = Color.orange
|
||||
|
||||
local container = frame_data.container
|
||||
Gui.clear(container)
|
||||
pages[index].show(container)
|
||||
end
|
||||
)
|
||||
|
||||
Gui.on_click(
|
||||
close_name,
|
||||
function(event)
|
||||
local frame = event.player.gui.center[main_frame_name]
|
||||
if frame then
|
||||
Gui.destroy(frame)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return Public
|
||||
147
modules/gui/debug/model.lua
Normal file
147
modules/gui/debug/model.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local table = require 'utils.table'
|
||||
|
||||
local gui_names = Gui.names
|
||||
local type = type
|
||||
local concat = table.concat
|
||||
local inspect = table.inspect
|
||||
local pcall = pcall
|
||||
local loadstring = loadstring
|
||||
local rawset = rawset
|
||||
|
||||
local Public = {}
|
||||
|
||||
local luaObject = {'{', nil, ", name = '", nil, "'}"}
|
||||
local luaPlayer = {"{LuaPlayer, name = '", nil, "', index = ", nil, '}'}
|
||||
local luaEntity = {"{LuaEntity, name = '", nil, "', unit_number = ", nil, '}'}
|
||||
local luaGuiElement = {"{LuaGuiElement, name = '", nil, "'}"}
|
||||
|
||||
local function get(obj, prop)
|
||||
return obj[prop]
|
||||
end
|
||||
|
||||
local function get_name_safe(obj)
|
||||
local s, r = pcall(get, obj, 'name')
|
||||
if not s then
|
||||
return 'nil'
|
||||
else
|
||||
return r or 'nil'
|
||||
end
|
||||
end
|
||||
|
||||
local function get_lua_object_type_safe(obj)
|
||||
local s, r = pcall(get, obj, 'help')
|
||||
|
||||
if not s then
|
||||
return
|
||||
end
|
||||
|
||||
return r():match('Lua%a+')
|
||||
end
|
||||
|
||||
local function inspect_process(item)
|
||||
if type(item) ~= 'table' or type(item.__self) ~= 'userdata' then
|
||||
return item
|
||||
end
|
||||
|
||||
local suc, valid = pcall(get, item, 'valid')
|
||||
if not suc then
|
||||
-- no 'valid' property
|
||||
return get_lua_object_type_safe(item) or '{NoHelp LuaObject}'
|
||||
end
|
||||
|
||||
if not valid then
|
||||
return '{Invalid LuaObject}'
|
||||
end
|
||||
|
||||
local obj_type = get_lua_object_type_safe(item)
|
||||
if not obj_type then
|
||||
return '{NoHelp LuaObject}'
|
||||
end
|
||||
|
||||
if obj_type == 'LuaPlayer' then
|
||||
luaPlayer[2] = item.name or 'nil'
|
||||
luaPlayer[4] = item.index or 'nil'
|
||||
|
||||
return concat(luaPlayer)
|
||||
elseif obj_type == 'LuaEntity' then
|
||||
luaEntity[2] = item.name or 'nil'
|
||||
luaEntity[4] = item.unit_number or 'nil'
|
||||
|
||||
return concat(luaEntity)
|
||||
elseif obj_type == 'LuaGuiElement' then
|
||||
local name = item.name
|
||||
luaGuiElement[2] = gui_names and gui_names[name] or name or 'nil'
|
||||
|
||||
return concat(luaGuiElement)
|
||||
else
|
||||
luaObject[2] = obj_type
|
||||
luaObject[4] = get_name_safe(item)
|
||||
|
||||
return concat(luaObject)
|
||||
end
|
||||
end
|
||||
|
||||
local inspect_options = {process = inspect_process}
|
||||
function Public.dump(data)
|
||||
return inspect(data, inspect_options)
|
||||
end
|
||||
local dump = Public.dump
|
||||
|
||||
function Public.dump_ignore_builder(ignore)
|
||||
local function process(item)
|
||||
if ignore[item] then
|
||||
return nil
|
||||
end
|
||||
|
||||
return inspect_process(item)
|
||||
end
|
||||
|
||||
local options = {process = process}
|
||||
return function(data)
|
||||
return inspect(data, options)
|
||||
end
|
||||
end
|
||||
|
||||
function Public.dump_function(func)
|
||||
local res = {'upvalues:\n'}
|
||||
|
||||
local i = 1
|
||||
while true do
|
||||
local n, v = debug.getupvalue(func, i)
|
||||
|
||||
if n == nil then
|
||||
break
|
||||
elseif n ~= '_ENV' then
|
||||
res[#res + 1] = n
|
||||
res[#res + 1] = ' = '
|
||||
res[#res + 1] = dump(v)
|
||||
res[#res + 1] = '\n'
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
return concat(res)
|
||||
end
|
||||
|
||||
function Public.dump_text(text, player)
|
||||
local func = loadstring('return ' .. text)
|
||||
if not func then
|
||||
return false
|
||||
end
|
||||
|
||||
rawset(game, 'player', player)
|
||||
|
||||
local suc, var = pcall(func)
|
||||
|
||||
rawset(game, 'player', nil)
|
||||
|
||||
if not suc then
|
||||
return false
|
||||
end
|
||||
|
||||
return true, dump(var)
|
||||
end
|
||||
|
||||
return Public
|
||||
161
modules/gui/debug/package_view.lua
Normal file
161
modules/gui/debug/package_view.lua
Normal file
@@ -0,0 +1,161 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Color = require 'resources.color_presets'
|
||||
local Model = require 'modules.gui.debug.model'
|
||||
|
||||
local dump_function = Model.dump_function
|
||||
local loaded = _G.package.loaded
|
||||
|
||||
local Public = {}
|
||||
|
||||
local ignore = {
|
||||
_G = true,
|
||||
package = true,
|
||||
coroutine = true,
|
||||
table = true,
|
||||
string = true,
|
||||
bit32 = true,
|
||||
math = true,
|
||||
debug = true,
|
||||
serpent = true,
|
||||
['utils.math'] = true,
|
||||
util = true,
|
||||
['utils.inspect'] = true,
|
||||
['mod-gui'] = true
|
||||
}
|
||||
|
||||
local file_label_name = Gui.uid_name()
|
||||
local left_panel_name = Gui.uid_name()
|
||||
local breadcrumbs_name = Gui.uid_name()
|
||||
local top_panel_name = Gui.uid_name()
|
||||
local variable_label_name = Gui.uid_name()
|
||||
local text_box_name = Gui.uid_name()
|
||||
|
||||
Public.name = 'package'
|
||||
|
||||
function Public.show(container)
|
||||
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
|
||||
local left_panel_style = left_panel.style
|
||||
left_panel_style.width = 300
|
||||
|
||||
for name, file in pairs(loaded) do
|
||||
if not ignore[name] then
|
||||
local file_label =
|
||||
left_panel.add({type = 'flow'}).add {type = 'label', name = file_label_name, caption = name}
|
||||
Gui.set_data(file_label, file)
|
||||
end
|
||||
end
|
||||
|
||||
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
|
||||
|
||||
local breadcrumbs = right_flow.add {type = 'label', name = breadcrumbs_name}
|
||||
|
||||
local top_panel = right_flow.add {type = 'scroll-pane', name = top_panel_name}
|
||||
local top_panel_style = top_panel.style
|
||||
top_panel_style.height = 200
|
||||
top_panel_style.maximal_width = 1000
|
||||
top_panel_style.horizontally_stretchable = true
|
||||
|
||||
local text_box = right_flow.add {type = 'text-box', name = text_box_name}
|
||||
text_box.read_only = true
|
||||
text_box.selectable = true
|
||||
|
||||
local text_box_style = text_box.style
|
||||
text_box_style.vertically_stretchable = true
|
||||
text_box_style.horizontally_stretchable = true
|
||||
text_box_style.maximal_width = 1000
|
||||
text_box_style.maximal_height = 1000
|
||||
|
||||
local data = {
|
||||
left_panel = left_panel,
|
||||
breadcrumbs = breadcrumbs,
|
||||
top_panel = top_panel,
|
||||
text_box = text_box,
|
||||
selected_file_label = nil,
|
||||
selected_variable_label = nil
|
||||
}
|
||||
|
||||
Gui.set_data(left_panel, data)
|
||||
Gui.set_data(top_panel, data)
|
||||
end
|
||||
|
||||
Gui.on_click(
|
||||
file_label_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local file = Gui.get_data(element)
|
||||
|
||||
local left_panel = element.parent.parent
|
||||
local data = Gui.get_data(left_panel)
|
||||
|
||||
local selected_file_label = data.selected_file_label
|
||||
|
||||
if selected_file_label then
|
||||
selected_file_label.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
data.selected_file_label = element
|
||||
|
||||
local top_panel = data.top_panel
|
||||
local text_box = data.text_box
|
||||
|
||||
Gui.clear(top_panel)
|
||||
|
||||
local file_type = type(file)
|
||||
|
||||
if file_type == 'table' then
|
||||
for k, v in pairs(file) do
|
||||
local label =
|
||||
top_panel.add({type = 'flow'}).add {type = 'label', name = variable_label_name, caption = k}
|
||||
Gui.set_data(label, v)
|
||||
end
|
||||
elseif file_type == 'function' then
|
||||
text_box.text = dump_function(file)
|
||||
else
|
||||
text_box.text = tostring(file)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
Gui.on_click(
|
||||
variable_label_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local variable = Gui.get_data(element)
|
||||
|
||||
local top_panel = element.parent.parent
|
||||
local data = Gui.get_data(top_panel)
|
||||
local text_box = data.text_box
|
||||
|
||||
local variable_type = type(variable)
|
||||
|
||||
if variable_type == 'table' then
|
||||
Gui.clear(top_panel)
|
||||
for k, v in pairs(variable) do
|
||||
local label =
|
||||
top_panel.add({type = 'flow'}).add {type = 'label', name = variable_label_name, caption = k}
|
||||
Gui.set_data(label, v)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local selected_label = data.selected_variable_label
|
||||
|
||||
if selected_label and selected_label.valid then
|
||||
selected_label.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
data.selected_variable_label = element
|
||||
|
||||
if variable_type == 'function' then
|
||||
text_box.text = dump_function(variable)
|
||||
else
|
||||
text_box.text = tostring(variable)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return Public
|
||||
129
modules/gui/debug/redmew_global_view.lua
Normal file
129
modules/gui/debug/redmew_global_view.lua
Normal file
@@ -0,0 +1,129 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Global = require 'utils.global'
|
||||
local Token = require 'utils.token'
|
||||
local Color = require 'resources.color_presets'
|
||||
local Model = require 'modules.gui.debug.model'
|
||||
|
||||
local dump = Model.dump
|
||||
local dump_text = Model.dump_text
|
||||
local concat = table.concat
|
||||
|
||||
local Public = {}
|
||||
|
||||
local header_name = Gui.uid_name()
|
||||
local left_panel_name = Gui.uid_name()
|
||||
local right_panel_name = Gui.uid_name()
|
||||
local input_text_box_name = Gui.uid_name()
|
||||
local refresh_name = Gui.uid_name()
|
||||
|
||||
Public.name = 'Global'
|
||||
|
||||
function Public.show(container)
|
||||
local main_flow = container.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name}
|
||||
local left_panel_style = left_panel.style
|
||||
left_panel_style.width = 300
|
||||
|
||||
for token_id, token_name in pairs(Global.names) do
|
||||
local header = left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = token_name}
|
||||
Gui.set_data(header, token_id)
|
||||
end
|
||||
|
||||
local right_flow = main_flow.add {type = 'flow', direction = 'vertical'}
|
||||
|
||||
local right_top_flow = right_flow.add {type = 'flow', direction = 'horizontal'}
|
||||
|
||||
local input_text_box = right_top_flow.add {type = 'text-box', name = input_text_box_name}
|
||||
local input_text_box_style = input_text_box.style
|
||||
input_text_box_style.horizontally_stretchable = true
|
||||
input_text_box_style.height = 32
|
||||
input_text_box_style.maximal_width = 1000
|
||||
|
||||
local refresh_button =
|
||||
right_top_flow.add {type = 'sprite-button', name = refresh_name, sprite = 'utility/reset', tooltip = 'refresh'}
|
||||
local refresh_button_style = refresh_button.style
|
||||
refresh_button_style.width = 32
|
||||
refresh_button_style.height = 32
|
||||
|
||||
local right_panel = right_flow.add {type = 'text-box', name = right_panel_name}
|
||||
right_panel.read_only = true
|
||||
right_panel.selectable = true
|
||||
|
||||
local right_panel_style = right_panel.style
|
||||
right_panel_style.vertically_stretchable = true
|
||||
right_panel_style.horizontally_stretchable = true
|
||||
right_panel_style.maximal_width = 1000
|
||||
right_panel_style.maximal_height = 1000
|
||||
|
||||
local data = {
|
||||
right_panel = right_panel,
|
||||
input_text_box = input_text_box,
|
||||
selected_header = nil
|
||||
}
|
||||
|
||||
Gui.set_data(input_text_box, data)
|
||||
Gui.set_data(left_panel, data)
|
||||
Gui.set_data(refresh_button, data)
|
||||
end
|
||||
|
||||
Gui.on_click(
|
||||
header_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local token_id = Gui.get_data(element)
|
||||
|
||||
local left_panel = element.parent.parent
|
||||
local data = Gui.get_data(left_panel)
|
||||
local right_panel = data.right_panel
|
||||
local selected_header = data.selected_header
|
||||
local input_text_box = data.input_text_box
|
||||
|
||||
if selected_header then
|
||||
selected_header.style.font_color = Color.white
|
||||
end
|
||||
|
||||
element.style.font_color = Color.orange
|
||||
data.selected_header = element
|
||||
|
||||
input_text_box.text = concat {'global.tokens[', token_id, ']'}
|
||||
input_text_box.style.font_color = Color.black
|
||||
|
||||
local content = dump(Token.get_global(token_id)) or 'nil'
|
||||
right_panel.text = content
|
||||
end
|
||||
)
|
||||
|
||||
local function update_dump(text_input, data, player)
|
||||
local suc, ouput = dump_text(text_input.text, player)
|
||||
if not suc then
|
||||
text_input.style.font_color = Color.red
|
||||
else
|
||||
text_input.style.font_color = Color.black
|
||||
data.right_panel.text = ouput
|
||||
end
|
||||
end
|
||||
|
||||
Gui.on_text_changed(
|
||||
input_text_box_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local data = Gui.get_data(element)
|
||||
|
||||
update_dump(element, data, event.player)
|
||||
end
|
||||
)
|
||||
|
||||
Gui.on_click(
|
||||
refresh_name,
|
||||
function(event)
|
||||
local element = event.element
|
||||
local data = Gui.get_data(element)
|
||||
|
||||
local input_text_box = data.input_text_box
|
||||
|
||||
update_dump(input_text_box, data, event.player)
|
||||
end
|
||||
)
|
||||
|
||||
return Public
|
||||
@@ -3,13 +3,11 @@
|
||||
-- Dependencies
|
||||
local Game = require 'utils.game'
|
||||
local Color = require 'resources.color_presets'
|
||||
local Server = require 'features.server'
|
||||
|
||||
-- localized functions
|
||||
local random = math.random
|
||||
local sqrt = math.sqrt
|
||||
local floor = math.floor
|
||||
local format = string.format
|
||||
local match = string.match
|
||||
local insert = table.insert
|
||||
local concat = table.concat
|
||||
@@ -201,27 +199,6 @@ function Module.set_and_return(tbl, key, value)
|
||||
return value
|
||||
end
|
||||
|
||||
--- Takes msg and prints it to all players. Also prints to the log and discord
|
||||
-- @param msg <string> The message to print
|
||||
-- @param warning_prefix <string> The name of the module/warning
|
||||
function Module.action_warning(warning_prefix, msg)
|
||||
game.print(prefix .. msg, Color.yellow)
|
||||
msg = format('%s %s', warning_prefix, msg)
|
||||
log(msg)
|
||||
Server.to_discord_bold(msg)
|
||||
end
|
||||
|
||||
--- Takes msg and prints it to all players except provided player. Also prints to the log and discord
|
||||
-- @param msg <string> The message to print
|
||||
-- @param warning_prefix <string> The name of the module/warning
|
||||
-- @param player <LuaPlayer> the player not to send the message to
|
||||
function Module.silent_action_warning(warning_prefix, msg, player)
|
||||
Module.print_except(prefix .. msg, player, Color.yellow)
|
||||
msg = format('%s %s', warning_prefix, msg)
|
||||
log(msg)
|
||||
Server.to_discord_bold(msg)
|
||||
end
|
||||
|
||||
-- add utility functions that exist in base factorio/util
|
||||
require 'util'
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ end
|
||||
|
||||
local function on_init()
|
||||
_LIFECYCLE = 5 -- on_init
|
||||
log('[INFO] Entering on_init')
|
||||
local handlers = event_handlers[init_event_name]
|
||||
call_handlers(handlers)
|
||||
|
||||
@@ -47,10 +48,12 @@ local function on_init()
|
||||
event_handlers[load_event_name] = nil
|
||||
|
||||
_LIFECYCLE = 8 -- Runtime
|
||||
log('[INFO] Entering runtime')
|
||||
end
|
||||
|
||||
local function on_load()
|
||||
_LIFECYCLE = 6 -- on_load
|
||||
log('[INFO] Entering on_load')
|
||||
local handlers = event_handlers[load_event_name]
|
||||
call_handlers(handlers)
|
||||
|
||||
@@ -58,6 +61,7 @@ local function on_load()
|
||||
event_handlers[load_event_name] = nil
|
||||
|
||||
_LIFECYCLE = 8 -- Runtime
|
||||
log('[INFO] Entering runtime')
|
||||
end
|
||||
|
||||
local function on_nth_tick_event(event)
|
||||
|
||||
@@ -36,7 +36,7 @@ function Global.register_init(tbl, init_handler, callback)
|
||||
)
|
||||
end
|
||||
|
||||
if _DEBUG then
|
||||
if _DEBUG or true then
|
||||
local concat = table.concat
|
||||
|
||||
local names = {}
|
||||
|
||||
@@ -2,6 +2,7 @@ local Token = require 'utils.token'
|
||||
local Event = require 'utils.event'
|
||||
local Game = require 'utils.game'
|
||||
local Global = require 'utils.global'
|
||||
local mod_gui = require 'mod-gui'
|
||||
|
||||
local Gui = {}
|
||||
|
||||
@@ -179,7 +180,7 @@ Gui.on_player_show_top = custom_handler_factory(on_visible_handlers)
|
||||
Gui.on_pre_player_hide_top = custom_handler_factory(on_pre_hidden_handlers)
|
||||
|
||||
--- Allows the player to show / hide this element.
|
||||
-- The element must be part in gui.top.
|
||||
-- The element must be in Gui.get_top_element_flow(player)
|
||||
-- This function must be called in the control stage, i.e not inside an event.
|
||||
-- @param element_name<string> This name must be globally unique.
|
||||
function Gui.allow_player_to_toggle_top_element_visibility(element_name)
|
||||
@@ -189,7 +190,17 @@ function Gui.allow_player_to_toggle_top_element_visibility(element_name)
|
||||
top_elements[#top_elements + 1] = element_name
|
||||
end
|
||||
|
||||
--- Returns the flow where top elements can be added and will be effected by google visibility
|
||||
-- For the toggle to work it must be registed with Gui.allow_player_to_toggle_top_element_visibility(element_name)
|
||||
-- @tparam player LuaPlayer pointer to the player who has the gui
|
||||
-- @treturn LuaGuiEelement the top element flow
|
||||
function Gui.get_top_element_flow(player)
|
||||
player = Game.get_player_from_any(player)
|
||||
return mod_gui.get_button_flow(player)
|
||||
end
|
||||
|
||||
local toggle_button_name = Gui.uid_name()
|
||||
Gui.top_toggle_button_name = toggle_button_name
|
||||
|
||||
Event.add(
|
||||
defines.events.on_player_created,
|
||||
@@ -200,16 +211,18 @@ Event.add(
|
||||
return
|
||||
end
|
||||
|
||||
local b =
|
||||
player.gui.top.add {
|
||||
local top = Gui.get_top_element_flow(player)
|
||||
|
||||
local b = top.add {
|
||||
type = 'button',
|
||||
name = toggle_button_name,
|
||||
style = mod_gui.button_style,
|
||||
caption = '<',
|
||||
tooltip = 'Shows / hides the Redmew Gui buttons.'
|
||||
tooltip = {'gui_util.button_tooltip'}
|
||||
}
|
||||
local style = b.style
|
||||
style.width = 18
|
||||
style.height = 38
|
||||
style.height = 36
|
||||
style.left_padding = 0
|
||||
style.top_padding = 0
|
||||
style.right_padding = 0
|
||||
@@ -223,21 +236,16 @@ Gui.on_click(
|
||||
function(event)
|
||||
local button = event.element
|
||||
local player = event.player
|
||||
local top = player.gui.top
|
||||
local top = Gui.get_top_element_flow(player)
|
||||
|
||||
if button.caption == '<' then
|
||||
for i = 1, #top_elements do
|
||||
local name = top_elements[i]
|
||||
local ele = top[name]
|
||||
if ele and ele.valid then
|
||||
local style = ele.style
|
||||
|
||||
-- if visible is not set it has the value of nil.
|
||||
-- Hence nil is treated as is visible.
|
||||
local v = style.visible
|
||||
if v or v == nil then
|
||||
if ele.visible then
|
||||
custom_raise(on_pre_hidden_handlers, ele, player)
|
||||
style.visible = false
|
||||
ele.visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -249,17 +257,15 @@ Gui.on_click(
|
||||
local name = top_elements[i]
|
||||
local ele = top[name]
|
||||
if ele and ele.valid then
|
||||
local style = ele.style
|
||||
|
||||
if not style.visible then
|
||||
style.visible = true
|
||||
if not ele.visible then
|
||||
ele.visible = true
|
||||
custom_raise(on_visible_handlers, ele, player)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
button.caption = '<'
|
||||
button.style.height = 38
|
||||
button.style.height = 36
|
||||
end
|
||||
end
|
||||
)
|
||||
@@ -284,4 +290,4 @@ if _DEBUG then
|
||||
end
|
||||
end
|
||||
|
||||
return Gui
|
||||
return Gui
|
||||
Reference in New Issue
Block a user