diff --git a/README.md b/README.md index affbc44a..c1ab73b8 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Please report these errors to [the issues page](issues). ## Contributing -All are welcome to make pull requests and issues for this scenario, if you are in any doubt, please ask someone in our [discord]. If you do not know lua and don't feel like learning you can always make a [feature request]. All our docs can be found [here][docs]. Please keep in mind while making code changes: +All are welcome to make pull requests and issues for this scenario, if you are in any doubt, please ask someone in our [discord]. If you do not know lua and don't feel like learning you can always make a [feature request]. To find out what we already have please read our [docs]. Please keep in mind while making code changes: * New features should have the branch names: `feature/feature-name` * New features are merged into `dev` after it has been completed, this can be done through a pull request. diff --git a/config/_file_loader.lua b/config/_file_loader.lua index 6c6c0c0d..35a07946 100644 --- a/config/_file_loader.lua +++ b/config/_file_loader.lua @@ -55,5 +55,4 @@ return { 'config.expcore-commands.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.gui.test' -- loads multiple gui defines to test the gui system } \ No newline at end of file diff --git a/config/action_buttons.lua b/config/action_buttons.lua index 2ce10565..b5306cf1 100644 --- a/config/action_buttons.lua +++ b/config/action_buttons.lua @@ -22,13 +22,6 @@ local function set_store_uids(player,action) selected_action_store = action end --- common style used by all action buttons -local function tool_button_style(style) - Gui.set_padding_style(style,-1,-1,-1,-1) - style.height = 28 - style.width = 28 -end - -- auth that will only allow when on player's of lower roles local function auth_lower_role(player,selected_player_name) local player_highest = Roles.get_player_highest_role(player) @@ -56,14 +49,23 @@ local function teleport(from_player,to_player) return true end +local function new_button(sprite,tooltip) + return Gui.element{ + type = 'sprite-button', + style = 'tool_button', + sprite = sprite, + tooltip = tooltip + }:style{ + padding = -1, + height = 28, + width = 28 + } +end + --- Teleports the user to the action player -- @element goto_player -local goto_player = -Gui.new_button() -:set_sprites('utility/export') -:set_tooltip{'player-list.goto-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local goto_player = new_button('utility/export',{'player-list.goto-player'}) +:on_click(function(player) local selected_player_name = get_action_player_name(player) local selected_player = Game.get_player_from_any(selected_player_name) if not player.character or not selected_player.character then @@ -75,12 +77,8 @@ end) --- Teleports the action player to the user -- @element bring_player -local bring_player = -Gui.new_button() -:set_sprites('utility/import') -:set_tooltip{'player-list.bring-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local bring_player = new_button('utility/import',{'player-list.bring-player'}) +:on_click(function(player) local selected_player_name = get_action_player_name(player) local selected_player = Game.get_player_from_any(selected_player_name) if not player.character or not selected_player.character then @@ -92,12 +90,8 @@ end) --- Kills the action player, if there are alive -- @element kill_player -local kill_player = -Gui.new_button() -:set_sprites('utility/too_far') -:set_tooltip{'player-list.kill-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local kill_player = new_button('utility/too_far',{'player-list.kill-player'}) +:on_click(function(player) local selected_player_name = get_action_player_name(player) local selected_player = Game.get_player_from_any(selected_player_name) if selected_player.character then @@ -109,12 +103,8 @@ end) --- Reports the action player, requires a reason to be given -- @element report_player -local report_player = -Gui.new_button() -:set_sprites('utility/spawn_flag') -:set_tooltip{'player-list.report-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local report_player = new_button('utility/spawn_flag',{'player-list.report-player'}) +:on_click(function(player) local selected_player_name = get_action_player_name(player) if Reports.is_reported(selected_player_name,player.name) then player.print({'expcom-report.already-reported'},Colors.orange_red) @@ -133,12 +123,8 @@ end --- Gives the action player a warning, requires a reason -- @element warn_player -local warn_player = -Gui.new_button() -:set_sprites('utility/spawn_flag') -:set_tooltip{'player-list.warn-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local warn_player = new_button('utility/spawn_flag',{'player-list.warn-player'}) +:on_click(function(player) Store.set(selected_action_store,player,'command/give-warning') end) @@ -151,12 +137,8 @@ end --- Jails the action player, requires a reason -- @element jail_player -local jail_player = -Gui.new_button() -:set_sprites('utility/item_editor_icon') -:set_tooltip{'player-list.jail-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local jail_player = new_button('utility/multiplayer_waiting_icon',{'player-list.jail-player'}) +:on_click(function(player) local selected_player_name, selected_player_color = get_action_player_name(player) if Jail.is_jailed(selected_player_name) then player.print({'expcom-jail.already-jailed', selected_player_color},Colors.orange_red) @@ -174,12 +156,8 @@ end --- Temp bans the action player, requires a reason -- @element temp_ban_player -local temp_ban_player = -Gui.new_button() -:set_sprites('utility/clock') -:set_tooltip{'player-list.temp-ban-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local temp_ban_player = new_button('utility/warning_white',{'player-list.temp-ban-player'}) +:on_click(function(player) local selected_player_name, selected_player_color = get_action_player_name(player) if Jail.is_jailed(selected_player_name) then player.print({'expcom-jail.already-banned', selected_player_color},Colors.orange_red) @@ -197,12 +175,8 @@ end --- Kicks the action player, requires a reason -- @element kick_player -local kick_player = -Gui.new_button() -:set_sprites('utility/warning_icon') -:set_tooltip{'player-list.kick-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local kick_player = new_button('utility/warning_icon',{'player-list.kick-player'}) +:on_click(function(player) Store.set(selected_action_store,player,'command/kick') end) @@ -213,12 +187,8 @@ end --- Bans the action player, requires a reason -- @element ban_player -local ban_player = -Gui.new_button() -:set_sprites('utility/danger_icon') -:set_tooltip{'player-list.ban-player'} -:set_style('tool_button',tool_button_style) -:on_click(function(player,element) +local ban_player = new_button('utility/danger_icon',{'player-list.ban-player'}) +:on_click(function(player) Store.set(selected_action_store,player,'command/ban') end) diff --git a/config/roles.lua b/config/roles.lua index b25704a6..ff40131f 100644 --- a/config/roles.lua +++ b/config/roles.lua @@ -61,7 +61,8 @@ Roles.new_role('Administrator','Admin') :set_flag('instance-respawn') :set_parent('Moderator') :allow{ - 'gui/warp-list/no-limit', + 'gui/warp-list/bypass-cooldown', + 'gui/warp-list/bypass-proximity', } Roles.new_role('Moderator','Mod') @@ -181,7 +182,9 @@ Roles.new_role('Member','Mem') :set_custom_color{r=24,g=172,b=188} :set_parent('Regular') :allow{ + 'gui/task-list/add', 'gui/task-list/edit', + 'gui/warp-list/add', 'gui/warp-list/edit' } @@ -217,7 +220,7 @@ local default = Roles.new_role('Guest','') 'gui/rocket-info', 'gui/science-info', 'gui/task-list', - 'gui/warp-list', + 'gui/warp-list' } --- Jail role diff --git a/config/tasks.lua b/config/tasks.lua index 95165ee0..f7968e8e 100644 --- a/config/tasks.lua +++ b/config/tasks.lua @@ -2,8 +2,12 @@ -- @config Tasks return { - any_user_can_add_new_task = true, --- @setting any_user_can_add_new_task when false only people with edit permission can make new reports - user_can_edit_own_tasks = true, --- @setting user_can_edit_own_tasks when false only people with edit permission can edit reports - only_admins_can_edit = false, --- @setting only_admins_can_edit true will hide the edit and delete buttons from non (game) admins - edit_tasks_role_permission = 'gui/task-list/edit' --- @setting edit_tasks_role_permission value used with custom permission system + -- Adding tasks + allow_add_task = 'all', --- @setting allow_add_task dictates who is allowed to add new tasks; values: all, admin, expcore.roles, none + expcore_roles_allow_add_task = 'gui/task-list/add', --- @setting expcore_roles_allow_add_task if expcore.roles is used then this is the required permission + + -- Editing tasks + allow_edit_task = 'expcore.roles', --- @setting allow_edit_task dictates who is allowed to edit existing tasks; values: all, admin, expcore.roles, none + expcore_roles_allow_edit_task = 'gui/task-list/edit', --- @setting expcore_roles_allow_edit_task if expcore.roles is used then this is the required permission + user_can_edit_own_tasks = true --- @settings if true then the user who made the task can edit it regardless of the allow_edit_task setting } \ No newline at end of file diff --git a/config/warps.lua b/config/warps.lua index fb620108..d1710ba8 100644 --- a/config/warps.lua +++ b/config/warps.lua @@ -2,24 +2,39 @@ -- @config Warps return { - recharge_time = 60, --- @setting recharge_time The amount of time in seconds that the player must wait between warps, acts as a balance - update_smoothing = 10, --- @setting update_smoothing Higher is better, the amount of smoothing applied to recharge timer and other gui updates, max is 60 - minimum_distance = 100, --- @setting minimum_distance The minimum distance that must be between warp points, creating new ones is blocked when too close - activation_range = 4, --- @setting activation_range The distance the player must be to a warp in order to use the warp gui, gui can still be viewed but not used - spawn_activation_range = 20, --- @setting spawn_activation_range A second activation range which is used for the forces spawn point - default_icon = 'discharge-defense-equipment', --- @setting default_icon The default icon which is used by warps; must be an item name - user_can_edit_own_warps = false, --- @setting user_can_edit_own_warps When true the user can always edit warps which they created regardless of other settings - any_user_can_add_new_warp = false, --- @setting any_user_can_add_new_warp When true any user is able to create new warps, however editing may still be restricted - only_admins_can_edit = false, --- @setting only_admins_can_edit When true only admins can edit warps - edit_warps_role_permission = 'gui/warp-list/edit', --- @setting edit_warps_role_permission Role permission used by the role system to allow editing warps - bypass_warp_limits_permission = 'gui/warp-list/no-limit', --- @setting bypass_warp_limits_permission Role permission used by the role system to allow bypassing the time and distance restrictions - entities = { --- @setting entities The entities which are created for warps + -- General config + update_smoothing = 10, --- @setting update_smoothing the amount of smoothing applied to updates to the cooldown timer, higher is better, max is 60 + minimum_distance = 100, --- @setting minimum_distance the minimum distance that is allowed between warps on the same force + default_icon = 'discharge-defense-equipment', --- @setting default_icon the default icon that will be used for warps + + -- Warp cooldowns + bypass_warp_cooldown = 'expcore.roles', --- @setting bypass_warp_cooldown dictates who the warp cooldown is applied to; values: all, admin, expcore.roles, none + expcore_roles_bypass_warp_cooldown = 'gui/warp-list/bypass-cooldown', --- @setting expcore_roles_bypass_warp_cooldown if expcore.roles is used then this is the required permission + cooldown_duraction = 60, --- @setting cooldown_duraction the duration of the warp cooldown in seconds + + -- Warp proximity + bypass_warp_proximity = 'expcore.roles', --- @setting bypass_warp_proximity dictates who the warp proximity is applied to; values: all, admin, expcore.roles, none + expcore_roles_bypass_warp_proximity = 'gui/warp-list/bypass-proximity', --- @setting expcore_roles_bypass_warp_proximity if expcore.roles is used then this is the required permission + standard_proximity_radius = 4, --- @setting standard_proximity_radius the minimum distance a player is allowed to be to a warp in order to use it + spawn_proximity_radius = 20, --- @setting spawn_proximity_radius the minimum distance a player is allowed to be from they spawn point to use warps + + -- Adding warps + allow_add_warp = 'expcore.roles', --- @setting allow_add_warp dictates who is allowed to add warps; values: all, admin, expcore.roles, none + expcore_roles_allow_add_warp = 'gui/warp-list/add', --- @setting expcore_roles_allow_add_warp if expcore.roles is used then this is the required permission + + -- Editing warps + allow_edit_warp = 'expcore.roles', --- @setting allow_edit_warp dictates who is allowed to edit warps; values: all, admin, expcore.roles, none + expcore_roles_allow_edit_warp = 'gui/warp-list/edit', --- @setting expcore_roles_allow_edit_warp if expcore.roles is used then this is the required permission + user_can_edit_own_warps = false, --- @settings user_can_edit_own_warps if true then the user who made the warp can edit it regardless of the allow_edit_warp setting + + -- Warp area generation + entities = { --- @setting entities The entities which are created for warp areas {'small-lamp',-3,-2},{'small-lamp',-3,2},{'small-lamp',3,-2},{'small-lamp',3,2}, {'small-lamp',-2,-3},{'small-lamp',2,-3},{'small-lamp',-2,3},{'small-lamp',2,3}, {'small-electric-pole',-3,-3},{'small-electric-pole',3,3},{'small-electric-pole',-3,3},{'small-electric-pole',3,-3} }, - base_tile = 'tutorial-grid', --- @setting base_tile The tile which is used for the warps - tiles = { --- @setting tiles The tiles which are created for warps + base_tile = 'tutorial-grid', --- @setting base_tile The tile which is used for the warp areas + tiles = { --- @setting tiles The tiles which are created for warp areas {-3,-2},{-3,-1},{-3,0},{-3,1},{-3,2},{3,-2},{3,-1},{3,0},{3,1},{3,2}, {-2,-3},{-1,-3},{0,-3},{1,-3},{2,-3},{-2,3},{-1,3},{0,3},{1,3},{2,3} } diff --git a/docs/addons/Advanced-Start.html b/docs/addons/Advanced-Start.html index 8fc6a44a..e06593f6 100644 --- a/docs/addons/Advanced-Start.html +++ b/docs/addons/Advanced-Start.html @@ -348,7 +348,7 @@ generated by LDoc diff --git a/docs/addons/Chat-Popups.html b/docs/addons/Chat-Popups.html index c9ea0f82..7cb0c9b2 100644 --- a/docs/addons/Chat-Popups.html +++ b/docs/addons/Chat-Popups.html @@ -349,7 +349,7 @@ generated by LDoc diff --git a/docs/addons/Chat-Reply.html b/docs/addons/Chat-Reply.html index d6eda160..6c368f68 100644 --- a/docs/addons/Chat-Reply.html +++ b/docs/addons/Chat-Reply.html @@ -376,7 +376,7 @@ generated by LDoc diff --git a/docs/addons/Compilatron.html b/docs/addons/Compilatron.html index 4fafcaa9..135ff83a 100644 --- a/docs/addons/Compilatron.html +++ b/docs/addons/Compilatron.html @@ -585,7 +585,7 @@ generated by LDoc diff --git a/docs/addons/Damage-Popups.html b/docs/addons/Damage-Popups.html index a445fe5a..df0b8737 100644 --- a/docs/addons/Damage-Popups.html +++ b/docs/addons/Damage-Popups.html @@ -349,7 +349,7 @@ generated by LDoc diff --git a/docs/addons/Death-Logger.html b/docs/addons/Death-Logger.html index faadc765..4f94aece 100644 --- a/docs/addons/Death-Logger.html +++ b/docs/addons/Death-Logger.html @@ -404,7 +404,7 @@ generated by LDoc diff --git a/docs/addons/Discord-Alerts.html b/docs/addons/Discord-Alerts.html index e0ecba4b..12bccc87 100644 --- a/docs/addons/Discord-Alerts.html +++ b/docs/addons/Discord-Alerts.html @@ -460,7 +460,7 @@ generated by LDoc diff --git a/docs/addons/Player-Colours.html b/docs/addons/Player-Colours.html index 8a60609c..0682c770 100644 --- a/docs/addons/Player-Colours.html +++ b/docs/addons/Player-Colours.html @@ -404,7 +404,7 @@ generated by LDoc diff --git a/docs/addons/Pollution-Grading.html b/docs/addons/Pollution-Grading.html index 46baddb7..8ecf95bf 100644 --- a/docs/addons/Pollution-Grading.html +++ b/docs/addons/Pollution-Grading.html @@ -320,7 +320,7 @@ generated by LDoc diff --git a/docs/addons/Scorched-Earth.html b/docs/addons/Scorched-Earth.html index c4f4487d..84ea1706 100644 --- a/docs/addons/Scorched-Earth.html +++ b/docs/addons/Scorched-Earth.html @@ -404,7 +404,7 @@ generated by LDoc diff --git a/docs/addons/Spawn-Area.html b/docs/addons/Spawn-Area.html index 6b3002a3..9cd696ab 100644 --- a/docs/addons/Spawn-Area.html +++ b/docs/addons/Spawn-Area.html @@ -376,7 +376,7 @@ generated by LDoc diff --git a/docs/commands/Admin-Chat.html b/docs/commands/Admin-Chat.html index 04b6b9fe..7967ea77 100644 --- a/docs/commands/Admin-Chat.html +++ b/docs/commands/Admin-Chat.html @@ -388,7 +388,7 @@ generated by LDoc diff --git a/docs/commands/Bonus.html b/docs/commands/Bonus.html index 3786a596..f0b1fc7b 100644 --- a/docs/commands/Bonus.html +++ b/docs/commands/Bonus.html @@ -500,7 +500,7 @@ generated by LDoc diff --git a/docs/commands/Cheat-Mode.html b/docs/commands/Cheat-Mode.html index 81523c11..680b91e8 100644 --- a/docs/commands/Cheat-Mode.html +++ b/docs/commands/Cheat-Mode.html @@ -361,7 +361,7 @@ generated by LDoc diff --git a/docs/commands/Clear-Inventory.html b/docs/commands/Clear-Inventory.html index a250f390..7026f517 100644 --- a/docs/commands/Clear-Inventory.html +++ b/docs/commands/Clear-Inventory.html @@ -388,7 +388,7 @@ generated by LDoc diff --git a/docs/commands/Debug.html b/docs/commands/Debug.html index 0af8bb1c..6667e00b 100644 --- a/docs/commands/Debug.html +++ b/docs/commands/Debug.html @@ -365,7 +365,7 @@ generated by LDoc diff --git a/docs/commands/Find.html b/docs/commands/Find.html index 0f1ae48d..e95e5332 100644 --- a/docs/commands/Find.html +++ b/docs/commands/Find.html @@ -360,7 +360,7 @@ generated by LDoc diff --git a/docs/commands/Help.html b/docs/commands/Help.html index 024c376f..deb9aa2a 100644 --- a/docs/commands/Help.html +++ b/docs/commands/Help.html @@ -404,7 +404,7 @@ generated by LDoc diff --git a/docs/commands/Home.html b/docs/commands/Home.html index d4881527..e9b13bfd 100644 --- a/docs/commands/Home.html +++ b/docs/commands/Home.html @@ -458,7 +458,7 @@ generated by LDoc diff --git a/docs/commands/Interface.html b/docs/commands/Interface.html index eeaf7d3d..89212f3b 100644 --- a/docs/commands/Interface.html +++ b/docs/commands/Interface.html @@ -416,7 +416,7 @@ generated by LDoc diff --git a/docs/commands/Jail.html b/docs/commands/Jail.html index 67d43bef..2c670b45 100644 --- a/docs/commands/Jail.html +++ b/docs/commands/Jail.html @@ -611,7 +611,7 @@ generated by LDoc diff --git a/docs/commands/Kill.html b/docs/commands/Kill.html index 967cb7e1..f6e57348 100644 --- a/docs/commands/Kill.html +++ b/docs/commands/Kill.html @@ -389,7 +389,7 @@ generated by LDoc diff --git a/docs/commands/Me.html b/docs/commands/Me.html index fbba050f..59c4534a 100644 --- a/docs/commands/Me.html +++ b/docs/commands/Me.html @@ -360,7 +360,7 @@ generated by LDoc diff --git a/docs/commands/Rainbow.html b/docs/commands/Rainbow.html index f30d335d..6c90fe3f 100644 --- a/docs/commands/Rainbow.html +++ b/docs/commands/Rainbow.html @@ -388,7 +388,7 @@ generated by LDoc diff --git a/docs/commands/Repair.html b/docs/commands/Repair.html index 361a22d7..004ec4bd 100644 --- a/docs/commands/Repair.html +++ b/docs/commands/Repair.html @@ -321,7 +321,7 @@ generated by LDoc diff --git a/docs/commands/Reports.html b/docs/commands/Reports.html index f94af164..2f71921c 100644 --- a/docs/commands/Reports.html +++ b/docs/commands/Reports.html @@ -585,7 +585,7 @@ generated by LDoc diff --git a/docs/commands/Roles.html b/docs/commands/Roles.html index 3bc1f04d..ba0318c7 100644 --- a/docs/commands/Roles.html +++ b/docs/commands/Roles.html @@ -557,7 +557,7 @@ generated by LDoc diff --git a/docs/commands/Spawn.html b/docs/commands/Spawn.html index 257da669..fda9f645 100644 --- a/docs/commands/Spawn.html +++ b/docs/commands/Spawn.html @@ -389,7 +389,7 @@ generated by LDoc diff --git a/docs/commands/Tag.html b/docs/commands/Tag.html index 63606adc..9cf7157a 100644 --- a/docs/commands/Tag.html +++ b/docs/commands/Tag.html @@ -443,7 +443,7 @@ generated by LDoc diff --git a/docs/commands/Teleport.html b/docs/commands/Teleport.html index 472651ba..e9131888 100644 --- a/docs/commands/Teleport.html +++ b/docs/commands/Teleport.html @@ -484,7 +484,7 @@ generated by LDoc diff --git a/docs/commands/Warnings.html b/docs/commands/Warnings.html index a62c9b8e..ac587916 100644 --- a/docs/commands/Warnings.html +++ b/docs/commands/Warnings.html @@ -569,7 +569,7 @@ generated by LDoc diff --git a/docs/configs/Advanced-Start.html b/docs/configs/Advanced-Start.html index 02b2965a..75ce3491 100644 --- a/docs/configs/Advanced-Start.html +++ b/docs/configs/Advanced-Start.html @@ -506,7 +506,7 @@ generated by LDoc diff --git a/docs/configs/Bonuses.html b/docs/configs/Bonuses.html index 2e3966d2..cc4d5595 100644 --- a/docs/configs/Bonuses.html +++ b/docs/configs/Bonuses.html @@ -237,7 +237,7 @@ generated by LDoc diff --git a/docs/configs/Chat-Reply.html b/docs/configs/Chat-Reply.html index 727827bc..d7ae726a 100644 --- a/docs/configs/Chat-Reply.html +++ b/docs/configs/Chat-Reply.html @@ -485,7 +485,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Auth-Admin.html b/docs/configs/Commands-Auth-Admin.html index fd824730..4a48d6da 100644 --- a/docs/configs/Commands-Auth-Admin.html +++ b/docs/configs/Commands-Auth-Admin.html @@ -294,7 +294,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Auth-Roles.html b/docs/configs/Commands-Auth-Roles.html index 4f49a827..ed1c5b7f 100644 --- a/docs/configs/Commands-Auth-Roles.html +++ b/docs/configs/Commands-Auth-Roles.html @@ -320,7 +320,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Auth-Runtime-Disable.html b/docs/configs/Commands-Auth-Runtime-Disable.html index 9aacac5f..e72d1a81 100644 --- a/docs/configs/Commands-Auth-Runtime-Disable.html +++ b/docs/configs/Commands-Auth-Runtime-Disable.html @@ -442,7 +442,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Parse-Roles.html b/docs/configs/Commands-Parse-Roles.html index 64d71e20..f9d62d80 100644 --- a/docs/configs/Commands-Parse-Roles.html +++ b/docs/configs/Commands-Parse-Roles.html @@ -354,7 +354,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Parse.html b/docs/configs/Commands-Parse.html index 574f8aa4..d1d21e74 100644 --- a/docs/configs/Commands-Parse.html +++ b/docs/configs/Commands-Parse.html @@ -338,7 +338,7 @@ see ./expcore/commands.lua for more details

generated by LDoc diff --git a/docs/configs/Compilatron.html b/docs/configs/Compilatron.html index 98043b31..7dc0e1b5 100644 --- a/docs/configs/Compilatron.html +++ b/docs/configs/Compilatron.html @@ -354,7 +354,7 @@ generated by LDoc diff --git a/docs/configs/Death-Logger.html b/docs/configs/Death-Logger.html index 859cf7d9..ab9a69db 100644 --- a/docs/configs/Death-Logger.html +++ b/docs/configs/Death-Logger.html @@ -416,7 +416,7 @@ generated by LDoc diff --git a/docs/configs/Discord-Alerts.html b/docs/configs/Discord-Alerts.html index 4139d6e6..40ee9ed3 100644 --- a/docs/configs/Discord-Alerts.html +++ b/docs/configs/Discord-Alerts.html @@ -237,7 +237,7 @@ generated by LDoc diff --git a/docs/configs/File-Loader.html b/docs/configs/File-Loader.html index 8aa4661f..11aeb9af 100644 --- a/docs/configs/File-Loader.html +++ b/docs/configs/File-Loader.html @@ -240,7 +240,7 @@ generated by LDoc diff --git a/docs/configs/Permission-Groups.html b/docs/configs/Permission-Groups.html index 305e744d..6329eb61 100644 --- a/docs/configs/Permission-Groups.html +++ b/docs/configs/Permission-Groups.html @@ -295,7 +295,7 @@ generated by LDoc diff --git a/docs/configs/Player-List.html b/docs/configs/Player-List.html index 2c9fc83f..2d23727d 100644 --- a/docs/configs/Player-List.html +++ b/docs/configs/Player-List.html @@ -812,7 +812,7 @@ generated by LDoc diff --git a/docs/configs/Pollution-Grading.html b/docs/configs/Pollution-Grading.html index 64d7f6f0..2c6dc312 100644 --- a/docs/configs/Pollution-Grading.html +++ b/docs/configs/Pollution-Grading.html @@ -384,7 +384,7 @@ generated by LDoc diff --git a/docs/configs/Popup-Messages.html b/docs/configs/Popup-Messages.html index 114b8348..bf97ecf9 100644 --- a/docs/configs/Popup-Messages.html +++ b/docs/configs/Popup-Messages.html @@ -414,7 +414,7 @@ generated by LDoc diff --git a/docs/configs/Preset-Player-Colours.html b/docs/configs/Preset-Player-Colours.html index 824291f5..3fd3eca5 100644 --- a/docs/configs/Preset-Player-Colours.html +++ b/docs/configs/Preset-Player-Colours.html @@ -324,7 +324,7 @@ generated by LDoc diff --git a/docs/configs/Repair.html b/docs/configs/Repair.html index e61920c5..82dcaa12 100644 --- a/docs/configs/Repair.html +++ b/docs/configs/Repair.html @@ -414,7 +414,7 @@ generated by LDoc diff --git a/docs/configs/Rockets.html b/docs/configs/Rockets.html index 929fbf4c..a318f0cd 100644 --- a/docs/configs/Rockets.html +++ b/docs/configs/Rockets.html @@ -834,7 +834,7 @@ generated by LDoc diff --git a/docs/configs/Roles.html b/docs/configs/Roles.html index 5c7aabf3..c324a6ac 100644 --- a/docs/configs/Roles.html +++ b/docs/configs/Roles.html @@ -292,7 +292,7 @@ generated by LDoc diff --git a/docs/configs/Science.html b/docs/configs/Science.html index c9c7fd1c..f5dca812 100644 --- a/docs/configs/Science.html +++ b/docs/configs/Science.html @@ -354,7 +354,7 @@ generated by LDoc diff --git a/docs/configs/Scorched-Earth.html b/docs/configs/Scorched-Earth.html index 3c038550..f011372b 100644 --- a/docs/configs/Scorched-Earth.html +++ b/docs/configs/Scorched-Earth.html @@ -388,7 +388,7 @@ generated by LDoc diff --git a/docs/configs/Spawn-Area.html b/docs/configs/Spawn-Area.html index 4395fc07..fac7d663 100644 --- a/docs/configs/Spawn-Area.html +++ b/docs/configs/Spawn-Area.html @@ -744,7 +744,7 @@ generated by LDoc diff --git a/docs/configs/Tasks.html b/docs/configs/Tasks.html index 1bd48171..4e84ef99 100644 --- a/docs/configs/Tasks.html +++ b/docs/configs/Tasks.html @@ -241,16 +241,16 @@ - any_user_can_add_new_task + allow_add_task - user_can_edit_own_tasks + expcore_roles_allow_add_task - only_admins_can_edit + allow_edit_task - edit_tasks_role_permission + expcore_roles_allow_edit_task @@ -264,15 +264,15 @@
- # - any_user_can_add_new_task + # + allow_add_task

-

when false only people with edit permission can make new reports

+

dictates who is allowed to add new tasks; values: all, admin, expcore.roles, none

@@ -291,15 +291,15 @@
- # - user_can_edit_own_tasks + # + expcore_roles_allow_add_task

-

when false only people with edit permission can edit reports

+

if expcore.roles is used then this is the required permission

@@ -318,15 +318,15 @@
- # - only_admins_can_edit + # + allow_edit_task

-

true will hide the edit and delete buttons from non (game) admins

+

dictates who is allowed to edit existing tasks; values: all, admin, expcore.roles, none

@@ -345,15 +345,15 @@
- # - edit_tasks_role_permission + # + expcore_roles_allow_edit_task

-

value used with custom permission system

+

if expcore.roles is used then this is the required permission

@@ -384,7 +384,7 @@ generated by LDoc
diff --git a/docs/configs/Warnings.html b/docs/configs/Warnings.html index 78291b18..09b6a980 100644 --- a/docs/configs/Warnings.html +++ b/docs/configs/Warnings.html @@ -355,7 +355,7 @@ generated by LDoc diff --git a/docs/configs/Warps.html b/docs/configs/Warps.html index c8a87917..0353eba6 100644 --- a/docs/configs/Warps.html +++ b/docs/configs/Warps.html @@ -241,37 +241,46 @@ - recharge_time - - update_smoothing minimum_distance - activation_range - - - spawn_activation_range - - default_icon - user_can_edit_own_warps + bypass_warp_cooldown - any_user_can_add_new_warp + expcore_roles_bypass_warp_cooldown - only_admins_can_edit + cooldown_duraction - edit_warps_role_permission + bypass_warp_proximity - bypass_warp_limits_permission + expcore_roles_bypass_warp_proximity + + + standard_proximity_radius + + + spawn_proximity_radius + + + allow_add_warp + + + expcore_roles_allow_add_warp + + + allow_edit_warp + + + expcore_roles_allow_edit_warp entities @@ -294,33 +303,6 @@
- # - recharge_time -
-
-
-
- -

-

The amount of time in seconds that the player must wait between warps, acts as a balance

- - - - - - - - - - - - - - -
-
-
-
# update_smoothing
@@ -329,7 +311,7 @@

-

Higher is better, the amount of smoothing applied to recharge timer and other gui updates, max is 60

+

the amount of smoothing applied to updates to the cooldown timer, higher is better, max is 60

@@ -356,61 +338,7 @@

-

The minimum distance that must be between warp points, creating new ones is blocked when too close

- - - - - - - - - - - - - - - -
-
-
- # - activation_range -
-
-
-
- -

-

The distance the player must be to a warp in order to use the warp gui, gui can still be viewed but not used

- - - - - - - - - - - - - - -
-
-
-
- # - spawn_activation_range -
-
-
-
- -

-

A second activation range which is used for the forces spawn point

+

the minimum distance that is allowed between warps on the same force

@@ -437,7 +365,7 @@

-

The default icon which is used by warps; must be an item name

+

the default icon that will be used for warps

@@ -456,15 +384,15 @@
- # - user_can_edit_own_warps + # + bypass_warp_cooldown

-

When true the user can always edit warps which they created regardless of other settings

+

dictates who the warp cooldown is applied to; values: all, admin, expcore.roles, none

@@ -483,15 +411,15 @@
- # - any_user_can_add_new_warp + # + expcore_roles_bypass_warp_cooldown

-

When true any user is able to create new warps, however editing may still be restricted

+

if expcore.roles is used then this is the required permission

@@ -510,15 +438,15 @@
- # - only_admins_can_edit + # + cooldown_duraction

-

When true only admins can edit warps

+

the duration of the warp cooldown in seconds

@@ -537,15 +465,15 @@
- # - edit_warps_role_permission + # + bypass_warp_proximity

-

Role permission used by the role system to allow editing warps

+

dictates who the warp proximity is applied to; values: all, admin, expcore.roles, none

@@ -564,15 +492,177 @@
- # - bypass_warp_limits_permission + # + expcore_roles_bypass_warp_proximity

-

Role permission used by the role system to allow bypassing the time and distance restrictions

+

if expcore.roles is used then this is the required permission

+ + + + + + + + + + + + + + +
+
+
+
+ # + standard_proximity_radius +
+
+
+
+ +

+

the minimum distance a player is allowed to be to a warp in order to use it

+ + + + + + + + + + + + + + +
+
+
+
+ # + spawn_proximity_radius +
+
+
+
+ +

+

the minimum distance a player is allowed to be from they spawn point to use warps

+ + + + + + + + + + + + + + +
+
+
+
+ # + allow_add_warp +
+
+
+
+ +

+

dictates who is allowed to add warps; values: all, admin, expcore.roles, none

+ + + + + + + + + + + + + + +
+
+
+
+ # + expcore_roles_allow_add_warp +
+
+
+
+ +

+

if expcore.roles is used then this is the required permission

+ + + + + + + + + + + + + + +
+
+
+
+ # + allow_edit_warp +
+
+
+
+ +

+

dictates who is allowed to edit warps; values: all, admin, expcore.roles, none

+ + + + + + + + + + + + + + +
+
+
+
+ # + expcore_roles_allow_edit_warp +
+
+
+
+ +

+

if expcore.roles is used then this is the required permission

@@ -599,7 +689,7 @@

-

The entities which are created for warps

+

The entities which are created for warp areas

@@ -626,7 +716,7 @@

-

The tile which is used for the warps

+

The tile which is used for the warp areas

@@ -653,7 +743,7 @@

-

The tiles which are created for warps

+

The tiles which are created for warp areas

@@ -684,7 +774,7 @@ generated by LDoc
diff --git a/docs/control/Jail.html b/docs/control/Jail.html index 46633de1..4f02fcb1 100644 --- a/docs/control/Jail.html +++ b/docs/control/Jail.html @@ -1208,7 +1208,7 @@ generated by LDoc
diff --git a/docs/control/Production.html b/docs/control/Production.html index ea5291cb..301380da 100644 --- a/docs/control/Production.html +++ b/docs/control/Production.html @@ -1329,7 +1329,7 @@ generated by LDoc diff --git a/docs/control/Reports.html b/docs/control/Reports.html index 4470dca7..349a872c 100644 --- a/docs/control/Reports.html +++ b/docs/control/Reports.html @@ -1110,7 +1110,7 @@ generated by LDoc diff --git a/docs/control/Rockets.html b/docs/control/Rockets.html index ea2c7aae..2f5efd39 100644 --- a/docs/control/Rockets.html +++ b/docs/control/Rockets.html @@ -984,7 +984,7 @@ generated by LDoc diff --git a/docs/control/Tasks.html b/docs/control/Tasks.html index 41068882..440f1c35 100644 --- a/docs/control/Tasks.html +++ b/docs/control/Tasks.html @@ -998,7 +998,7 @@ Tasks.update_task(task_id,'We need more iron!',game. generated by LDoc diff --git a/docs/control/Warnings.html b/docs/control/Warnings.html index abec17b0..32c13b69 100644 --- a/docs/control/Warnings.html +++ b/docs/control/Warnings.html @@ -1465,7 +1465,7 @@ generated by LDoc diff --git a/docs/control/Warps.html b/docs/control/Warps.html index ebb0dfb5..5a52b7df 100644 --- a/docs/control/Warps.html +++ b/docs/control/Warps.html @@ -1563,7 +1563,7 @@ Warps.make_warp_tag(warp_id) generated by LDoc diff --git a/docs/core/Commands.html b/docs/core/Commands.html index 07dfce01..26e2e30e 100644 --- a/docs/core/Commands.html +++ b/docs/core/Commands.html @@ -1972,7 +1972,7 @@ generated by LDoc diff --git a/docs/core/Common-Library.html b/docs/core/Common-Library.html index 4206d114..6b2cd701 100644 --- a/docs/core/Common-Library.html +++ b/docs/core/Common-Library.html @@ -2746,7 +2746,7 @@ Common.table_insert(tbl,50,tbl2) generated by LDoc diff --git a/docs/core/Gui.html b/docs/core/Gui.html index 09dee1fe..72fc7784 100644 --- a/docs/core/Gui.html +++ b/docs/core/Gui.html @@ -42,21 +42,13 @@

Sections

@@ -217,21 +209,13 @@

Jump to Section

@@ -252,10 +236,7 @@

Gui core

Core Module - Gui - - This file is used to require all the different elements of the gui module - - each module has an outline here but for more details see their separate files in ./gui - - please read the files for more documentation that cant be shown here - - please note there is a rework planned but not started

+- Used to define new gui elements and gui event handlers

@@ -263,6 +244,66 @@ +

Usage

+
-- Defining a button that prints the player's name
+local example_button =
+Gui.element{
+    type = 'button',
+    caption = 'Example Button'
+}
+:on_click(function(player,element,event)
+    player.print(player.name)
+end)
+
-- Defining a button with a custom style
+local example_button =
+Gui.element{
+    type = 'button',
+    caption = 'Example Button'
+}
+:style{
+    height = 25,
+    width = 100
+}
+:on_click(function(player,element,event)
+    player.print(player.name)
+end)
+
-- Defining a button using a custom function
+local example_flow_with_button =
+Gui.element(function(event_trigger,parent)
+    -- Add the flow the button is in
+    local flow =
+    parent.add{
+        name = 'example_flow',
+        type = 'flow'
+    }
+
+    -- Get the players name
+    local player = game.players[parent.player_index]
+    local player_name = player.name
+
+    -- Add the button
+    local element =
+    flow.add{
+        name = event_trigger,
+        type = 'button',
+        caption = 'Example Button: '..player_name
+    }
+
+    -- Set the style of the button
+    local style = element.style
+    style.height = 25
+    style.width = 100]
+    style.font_color = player.color
+
+    -- Return the element
+    return element
+end)
+:on_click(function(player,element,event)
+    player.print(player.name)
+end)
+
-- Drawing an element
+local exmple_button_element = example_button(parent)
+local example_flow_with_button = example_flow_with_button(parent)
@@ -275,840 +316,222 @@ - expcore.gui.core - - - expcore.gui.instances - - - expcore.gui.elements.buttons - - - expcore.gui.elements.checkbox - - - expcore.gui.elements.dropdown - - - expcore.gui.elements.slider - - - expcore.gui.elements.text - - - expcore.gui.elements.elem-button - - - expcore.gui.elements.progress-bar - - - expcore.gui.concepts.toolbar - - - expcore.gui.concepts.left - - - expcore.gui.concepts.center - - - expcore.gui.concepts.popups - - - - - -

Center Guis

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
expcore.gui.concepts.toolbar
utils.game
CenterFrames.get_flow(player)Gets the center flow for a player
CenterFrames.clear_flow(player)Clears the center flow for a player
CenterFrames.draw_frame(player, name)Draws the center frame for a player, if already open then will do nothing
CenterFrames.redraw_frame(player, name)Draws the center frame for a player, if already open then will destroy it and redraw
CenterFrames.toggle_frame(player, name[, state])Toggles if the frame is currently open or not, will open if closed and close if open
CenterFrames.new_frame(permission_name)Creates a new center frame define
CenterFrames._prototype:set_auto_focus([state=true])Sets the frame to be the current active gui when opened and closes all other frames
CenterFrames._prototype:draw_frame(player)Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
CenterFrames._prototype:redraw_frame(player)Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
CenterFrames._prototype:toggle_frame(player)Toggles if the frame is open, if open it will close it and if closed it will open it
CenterFrames._prototype:event_handler([action=update])Creates an event handler that will trigger one of its functions, use with Event.add
- - -

Left Guis

- - - - - - - - - - - - - - + + +
expcore.gui.core
expcore.gui.prototype
expcore.gui.concepts.toolbar
expcore.gui.elements.buttonsutils.event
mod-gui
+ + +

Tables

+ + + - + + - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
utils.gametop_elementsContains the uids of the elements that will show on the top flow and the auth function
utils.eventleft_elementsContains the uids of the elements that will show on the left flow and the open on join function
LeftFrames.get_flow(player)Gets the left frame flow for a playerdefinesTable of all the elements which have been registed with the draw function and event handlers
LeftFrames.get_frame(name, player)Gets one frame from the left flow by its namefile_pathsAn index used for debuging to find the file where different elements where registered
LeftFrames.get_open(player)Gets all open frames for a player, if non are open it will remove the close all button_prototype_elementThe element prototype which is returned from Gui.element
LeftFrames.toggle_frame(name, player[, state])Toggles the visibility of a left frame, or sets its visibility state
LeftFrames.new_frame(permission_name)Creates a new left frame define
LeftFrames._prototype:set_open_by_default([state=true])Sets if the frame is visible when a player joins, can also be a function to return a boolean
LeftFrames._prototype:set_direction(direction)Sets the direction of the frame, either vertical or horizontal
LeftFrames._prototype:_internal_draw(player)Creates the gui for the first time, used internally
LeftFrames._prototype:get_frame(player)Gets the frame for this define from the left frame flow
LeftFrames._prototype:is_open(player)Returns if the player currently has this define visible
LeftFrames._prototype:toggle(player)Toggles the visibility of the left frame
LeftFrames._prototype:update(player)Updates the contents of the left frame, first tries update callback, other wise will clear and redraw
LeftFrames._prototype:update_all([update_offline=false])Updates the frame for all players, see update
LeftFrames._prototype:redraw(player)Redraws the frame by calling on_draw, will always clear the frame
LeftFrames._prototype:redraw_all([update_offline=false])Redraws the frame for all players, see redraw
LeftFrames._prototype:event_handler([action=update])Creates an event handler that will trigger one of its functions, use with Event.add_mt_elementThe prototype metatable applied to new element defines
-

Popups

+

Fields

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
expcore.gui.core
expcore.gui.prototype
utils.game
utils.event
expcore.gui.elements.progress-bar
expcore.gui.elements.buttons
mod-gui
resources.color_presets
utils.global
PopupFrames.get_flow(player)Gets the left flow that contains the popup frames
PopupFrames.open(define_name, player[, open_time], ...)Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
PopupFrames.close_progressProgress bar which when depleted will close the popup frame
PopupFrames.close_buttonA button which can be used to close the gui before the timer runs out
PopupFrames.new_popup([name])Creates a new popup frame define
PopupFrames._prototype:set_default_open_time(amount)Sets the default open time for the popup, will be used if non is provided with open
PopupFrames._prototype:open(player[, open_time], ...)Opens this define for a player, can be given open time and any other params for the draw functionuidThe current highest uid that is being used, will not increase during runtime
-

Toolbar

+

Element Define

- + + - + + - + + - - - - - - - - - - - - - - - - - - - + +
expcore.gui.coreelement(element_define)Base function used to define new elements, can be used with a table or with a function
expcore.gui.elements.buttonsGui._prototype_element:style(style_define)Extension of Gui.element when using the table method, values applied after the element is drawn
expcore.rolesGui._prototype_element:add_to_top_flow([authenticator])Adds an element to be drawn to the top flow when a player joins
utils.event
utils.game
mod-gui
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 returnGui._prototype_element:add_to_left_flow([open_on_join])Adds an element to be drawn to the left flow when a player joins
-

Core

+

Element Events

- + + - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + +
utils.guiGui._prototype_element.on_openedCalled when the player opens a GUI.
utils.gameGui._prototype_element.on_closedCalled when the player closes the GUI they have open.
new_define(prototype[, debug_name])Used to create new element defines from a class prototype, please use the own given by the classGui._prototype_element.on_clickCalled when LuaGuiElement is clicked.
get_define(name[, internal])Gets an element define give the uid, debug name or a copy of the element defineGui._prototype_element.on_confirmedCalled when a LuaGuiElement is confirmed, for example by pressing Enter in a textfield.
categorize_by_player(element)A categorize function to be used with add_store, each player has their own valueGui._prototype_element.on_checked_changedCalled when LuaGuiElement checked state is changed (related to checkboxes and radio buttons).
categorize_by_force(element)A categorize function to be used with add_store, each force has its own valueGui._prototype_element.on_elem_changedCalled when LuaGuiElement element value is changed (related to choose element buttons).
categorize_by_surface(element)A categorize function to be used with add_store, each surface has its own valueGui._prototype_element.on_location_changedCalled when LuaGuiElement element location is changed (related to frames in player.gui.screen).
draw(name, element)Draws a copy of the element define to the parent element, see draw_toGui._prototype_element.on_tab_changedCalled when LuaGuiElement selected tab is changed (related to tabbed-panes).
toggle_enabled(element)Will toggle the enabled state of an elementGui._prototype_element.on_selection_changedCalled when LuaGuiElement selection state is changed (related to drop-downs and listboxes).
toggle_visible(element)Will toggle the visiblity of an elementGui._prototype_element.on_switch_changedCalled when LuaGuiElement switch state is changed (related to switches).
set_padding(element[, up=0][, down=0][, left=0][, right=0])Sets the padding for a gui elementGui._prototype_element.on_text_changeCalled when LuaGuiElement text is changed by the player.
set_padding_style(style[, up=0][, down=0][, left=0][, right=0])Sets the padding for a gui styleGui._prototype_element.on_value_changedCalled when LuaGuiElement slider value is changed (related to the slider element).
+ + +

Top Flow

+ + + + + + - - + + + + + + + + + + + + + + + + +
toggle_top_flowButton which toggles the top flow elements
create_alignment(element[, name][, horizontal_align='right'][, vertical_align='center'])Allows the creation of an alignment flow to place elements intotop_flow_button_styleThe style that should be used for buttons on the top flow
get_top_flow(player)Gets the flow which contains the elements for the top flow
update_top_flow(player)Updates the visible states of all the elements on a players top flow
toggle_top_flow(player[, state])Toggles the visible states of all the elements on a players top flow
+ + +

Left Flow

+ + + + + + + + + + + + + + + + + + + + +
hide_left_flowButton which hides the elements in the left flow
get_left_flow(player)Gets the flow which contains the elements for the left flow
hide_left_flow(player)Hides all left elements for a player
toggle_left_element(player, element_define[, state])Toggles the visible state of all a left element for a player
+ + +

Helper Functions

+ + + + + + + + + + + + + + - + - - + + - - + + - -
get_player_from_element(element)Get the player that owns a gui element
toggle_enabled_state(element[, state])Will toggle the enabled state of an element or set it to the one given
toggle_visible_state(element[, state])Will toggle the visible state of an element or set it to the one given
destroy_if_valid(element)Destroies an element but tests for it being present and valid firstDestory a gui element without causing any errors, likly if the element may have already been removed
create_scroll_table(element, table_size, maximal_height[, name='scroll'])Creates a scroll area with a table inside, table can be any sizealignment(parent[, horizontal_align='right'][, vertical_align='center'][, name='alignment'])Draw a flow that has custom element alignments, default is right align
create_header(element, caption[, tooltip][, right_align][, name='header'])Creates a header section with a label and button areascroll_table(parent, height, column_count[, name='scroll'])Draw a scroll pane that has a table inside of it
- - -

Buttons

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mod-gui
expcore.gui.core
expcore.gui.prototype
Button.new_button([name])Creates a new button element define
Button._prototype:set_sprites(sprite[, hovered_sprite][, clicked_sprite])Adds sprites to a button making it a sprite button
Button._prototype:set_click_filter(filter[, ...])Adds a click / mouse button filter to the button
Button._prototype:set_key_filter(filter[, ...])Adds a control key filter to the button
- - -

Checkboxs

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
expcore.store
utils.game
Checkbox.new_checkbox([name])Creates a new checkbox element define
Checkbox.new_radiobutton([name])Creates a new radiobutton element define, has all functions checkbox has
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._prototype_radiobutton:get_store(category, internal)Gets the stored value of the radiobutton or the option set if present
Checkbox._prototype_radiobutton:set_store(category, value, internal)Sets the stored value of the radiobutton or the option set if present
Checkbox.new_option_set(callback, categorize)Registers a new option set that can be linked to radiobuttons (only one can be true at a time)
Checkbox.draw_option_set(name, element)Draws all radiobuttons that are part of an option set at once (Gui.draw will not work)
Checkbox.reset_radiobuttons(element[, exclude][, recursive=false])Sets all radiobutton in a element to false (unless excluded) and can act recursively
- - -

Dropdowns

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
utils.game
Dropdown.new_dropdown([name])Creates a new dropdown element define
Dropdown.new_list_box([name])Creates a new list box element define
Dropdown._prototype:new_static_options(options[, ...], the)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
- - -

Elem Buttons

- - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
utils.game
ElemButton.new_elem_button([name])Creates a new elem button element define
ElemButton._prototype.set_typeSets 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
- - -

Progress Bars

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
utils.global
utils.game
ProgressBar.set_maximum(element, amount)Sets the maximum value that represents the end value of the progress bar
ProgressBar.increment(element[, amount=1])Increases the value of the progressbar, if a define is given all of its instances have incremented
ProgressBar.decrement(element[, amount=1])Decreases the value of the progressbar, if a define is given all of its instances have decremented
ProgressBar.new_progressbar([name])Creates a new progressbar element define
ProgressBar._prototype:set_default_maximum(amount)Sets the maximum value that represents the end value of the progress bar
ProgressBar._prototype:use_count_down([state=true])Will set the progress bar to start at 1 and trigger when it hits 0
ProgressBar._prototype:increment([amount=1][, category])Increases the value of the progressbar
ProgressBar._prototype:increment_filtered([amount=1], filter)Increases the value of the progressbar, if the filter condition is met, does not work with store
ProgressBar._prototype:decrement([amount=1][, category])Decreases the value of the progressbar
ProgressBar._prototype:decrement_filtered([amount=1], filter)Decreases the value of the progressbar, if the filter condition is met, does not work with store
ProgressBar._prototype:add_element(element[, maximum])Adds an element into the list of instances that will are waiting to complete, does not work with store - note use store if you want persistent data, this only stores the elements not the values which they have
ProgressBar._prototype:reset_element(element)Resets an element, or its store, to be back at the start, either 1 or 0
ProgressBar._prototype:event_counter([filter])Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented
ProgressBar._prototype:event_countdown([filter])Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented
- - -

Sliders

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
expcore.gui.instances
utils.game
Slider.new_slider([name])Creates a new slider element define
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=true])Enables auto draw of the label, the label will share the same parent element as the slider
- - -

Text

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.prototype
utils.game
Text.new_text_field([name])Creates a new text field element define
Text.new_text_box([name])Creates a new text box element define
Text._prototype_box:set_selectable([state=true])Sets the text box to be selectable
Text._prototype_box:set_word_wrap([state=true])Sets the text box to have word wrap
Text._prototype_box:set_read_only([state=true])Sets the text box to be read only
- - -

Instances

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
utils.global
Instances.has_categories(name)Returns if a instance group has a serializer function; must be registered
Instances.is_registered(name)Returns if the given name is a registered instance group
Instances.register(name[, serializer])Registers the name of an instance group to allow for storing element instances
Instances.add_element(name, element)Adds an element to the instance group under the correct category; must be registered
Instances.get_elements_raw(name[, category])Gets all element instances without first removing any invalid ones; used internally and must be registered
Instances.get_valid_elements(name[, category][, callback])Gets all valid element instances and has the option of running a callback on those that are valid
Instances.unregistered_add_element(name, category, element)A version of add_element that does not require the group to be registered
Instances.unregistered_get_elements(name, category[, callback])A version of get_elements that does not require the group to be registered
- - -

Prototype

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
utils.game
expcore.store
expcore.gui.instances
Constructor.event(event_name)Creates a new function to add functions to an event handler
Constructor.extend(new_prototype)Extents a prototype with the base functions of all gui prototypes, no metatables
Constructor.store(callback)Creates a new function which adds a store to a gui define
Constructor.setter(value_type, key[, second_key])Creates a setter function that checks the type when a value is set
Prototype:uid()Gets the uid for the element define
Prototype.debug_nameSets a debug alias for the define
Prototype.set_captionSets the caption for the element define
Prototype.set_tooltipSets the tooltip for the element define
Prototype.set_pre_authenticatorSets an authenticator that blocks the draw function if check fails
Prototype.set_post_authenticatorSets an authenticator that disables the element if check fails
Prototype.on_drawRegisters a callback to the on_draw event
Prototype.on_style_updateRegisters a callback to the on_style_update event
Prototype:set_style(style[, callback])Sets the style for the element define
Prototype:set_embedded_flow(state)Sets the element to be drawn inside a nameless flow, can be given a name using a function
Prototype:raise_event(event_name, ...)Raises a custom event for this define, any number of params can be given
Prototype:draw_to(element)The main function for defines, when called will draw an instance of this define to the given element - what is drawn is based on the data in draw_data which is set using other functions
Prototype:get_store(category)Gets the value in this elements store, category needed if serializer function used
Prototype:set_store(category, value)Sets the value in this elements store, category needed if serializer function used
Prototype:clear_store([category])Sets the value in this elements store to nil, category needed if serializer function used
- - -

Test

- - - - - - - - - - - - - - - - - + +
expcore.gui
expcore.common
resources.color_presets
utils.event
expcore.storeheader(parent, caption[, tooltip][, add_alignment=false][, name='header'])Used to add a header to a frame, this has the option for a custom right alignment flow for buttons
@@ -1122,1187 +545,8 @@
- # - expcore.gui.core -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.instances -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.buttons -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.checkbox -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.dropdown -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.slider -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.text -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.elem-button -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.progress-bar -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.concepts.toolbar -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.concepts.left -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.concepts.center -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.concepts.popups -
-
-
-
- - - - - - - - - - - - - - - -
- -

Center Guis

-
-
-
-
- # - expcore.gui.core -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.prototype -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.concepts.toolbar -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - utils.game -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - CenterFrames.get_flow(player) -
-
-
-
- -

Gets the center flow for a player

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player to get the flow for - -
  • - - -
- - - - - Returns: - - - - - - - - - - -
-
-
-
- # - CenterFrames.clear_flow(player) -
-
-
-
- -

Clears the center flow for a player

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player to clear the flow for - -
  • - - -
- - - - - - - - - - - - - -
-
-
-
- # - CenterFrames.draw_frame(player, name) -
-
-
-
- -

Draws the center frame for a player, if already open then will do nothing

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player that will have the frame drawn - -
  • - - - - - -
  • - - name - - : - - (string) - - the name of the hui that will drawn - -
  • - - -
- - - - - Returns: - - - - - - - - - - -
-
-
-
- # - CenterFrames.redraw_frame(player, name) -
-
-
-
- -

Draws the center frame for a player, if already open then will destroy it and redraw

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player that will have the frame drawn - -
  • - - - - - -
  • - - name - - : - - (string) - - the name of the hui that will drawn - -
  • - - -
- - - - - Returns: - - - - - - - - - - -
-
-
-
- # - CenterFrames.toggle_frame(player, name[, state]) -
-
-
-
- -

Toggles if the frame is currently open or not, will open if closed and close if open

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player that will have the frame toggled - -
  • - - - - - -
  • - - name - - : - - (string) - - the name of the hui that will be toggled - -
  • - - - - - -
  • - - state - - : - - (boolean) - - when set will force a state for the frame - - (optional) -
  • - - -
- - - - - Returns: -
    -
  • - (boolean) - if the frame if no open or closed -
  • -
- - - - - - - - - -
-
-
-
- # - CenterFrames.new_frame(permission_name) -
-
-
-
- -

Creates a new center frame define

-

- - - Parameters: - -
    - - - - - -
  • - - permission_name - - : - - (string) - - the name that can be used with the permission system - -
  • - - -
- - - - - Returns: -
    -
  • - (table) - the new center frame define -
  • -
- - - - - - - - - -
-
-
-
- # - CenterFrames._prototype:set_auto_focus([state=true]) -
-
-
-
- -

Sets the frame to be the current active gui when opened and closes all other frames

-

- - - Parameters: - -
    - - - - - -
  • - - state - - : - - (boolean) - - when true will auto close other frames and set this frame as player.opened - - (default: true) -
  • - - -
- - - - - - - - - - - - - -
-
-
-
- # - CenterFrames._prototype:draw_frame(player) -
-
-
-
- -

Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player to draw the frame for - -
  • - - -
- - - - - Returns: - - - - - - - - - - -
-
-
-
- # - CenterFrames._prototype:redraw_frame(player) -
-
-
-
- -

Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player to draw the frame for - -
  • - - -
- - - - - Returns: - - - - - - - - - - -
-
-
-
- # - CenterFrames._prototype:toggle_frame(player) -
-
-
-
- -

Toggles if the frame is open, if open it will close it and if closed it will open it

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player to draw the frame for - -
  • - - -
- - - - - Returns: -
    -
  • - (boolean) - with the gui frame is now open -
  • -
- - - - - - - - - -
-
-
-
- # - CenterFrames._prototype:event_handler([action=update]) -
-
-
-
- -

Creates an event handler that will trigger one of its functions, use with Event.add

-

- - - Parameters: - -
    - - - - - -
  • - - action - - : - - (string) - - the action to take on this event - - (default: update) -
  • - - -
- - - - - - - - - - - - - -
-
-

Left Guis

-
-
-
-
- # - expcore.gui.core -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.prototype -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.concepts.toolbar -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - expcore.gui.elements.buttons + # + utils.event
@@ -2348,16 +592,21 @@
+
+

Tables

+
- # - utils.game + # + top_elements
+

Contains the uids of the elements that will show on the top flow and the auth function

+

@@ -2376,13 +625,15 @@
- # - utils.event + # + left_elements
+

Contains the uids of the elements that will show on the left flow and the open on join function

+

@@ -2401,14 +652,196 @@
- # - LeftFrames.get_flow(player) + # + defines
-

Gets the left frame flow for a player

+

Table of all the elements which have been registed with the draw function and event handlers

+

+ + + + + + + + + + + + + + +
+
+
+
+ # + file_paths +
+
+
+
+ +

An index used for debuging to find the file where different elements where registered

+

+ + + + + + + + + + + + + + +
+
+
+
+ # + _prototype_element +
+
+
+
+ +

The element prototype which is returned from Gui.element

+

+ + + + + + + + + + + + + + +
+
+
+
+ # + _mt_element +
+
+
+
+ +

The prototype metatable applied to new element defines

+

+ + + Fields: + +
    + + + + + +
  • + + __call + + + + + +
  • + + +
+ + + + + + + + + + + + + +
+
+

Fields

+
+
+
+
+ # + uid +
+
+
+
+ +

The current highest uid that is being used, will not increase during runtime

+

+ + + +
    + + + + + +
  • + + uid + + + + + +
  • + + +
+ + + + + + + + + + + + + +
+
+

Element Define

+
+
+
+
+ # + element(element_define) +
+
+
+
+ +

Base function used to define new elements, can be used with a table or with a function

@@ -2422,143 +855,13 @@
  • - player + element_define : - (LuaPlayer) + (table or function) - the player to get the flow of - -
  • - - - - - - - - Returns: - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames.get_frame(name, player) -
    -
    -
    -
    - -

    Gets one frame from the left flow by its name

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the gui frame to get - -
    • - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to get the frame of - -
    • - - -
    - - - - - Returns: -
      -
    • - (LuaGuiElement) - the frame in the left frame flow with that name -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames.get_open(player) -
    -
    -
    -
    - -

    Gets all open frames for a player, if non are open it will remove the close all button

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to get the flow of + used to define how the element is draw, using a table is the simplist way of doing this
    • @@ -2572,7 +875,7 @@
      • (table) - contains all the open (and registered) frames for the player + the new element define that is used to register events to this element
      @@ -2582,20 +885,53 @@ + Usage: +
      -- Defining an element with a table
      +local example_button =
      +Gui.element{
      +    type = 'button',
      +    caption = 'Example Button'
      +}
      +
      -- Defining an element with a function
      +local example_flow_with_button =
      +Gui.element(function(event_trigger,parent,...)
      +    -- Add the flow the button is in
      +    local flow =
      +    parent.add{
      +        name = 'example_flow',
      +        type = 'flow'
      +    }
      +
      +    -- Add the button
      +    local element =
      +    flow.add{
      +        name = event_trigger,
      +        type = 'button',
      +        caption = 'Example Button'
      +    }
      +
      +    -- Set the style of the button
      +    local style = element.style
      +    style.height = 25
      +    style.width = 100
      +
      +    -- Return the element
      +    return element
      +end)
    - # - LeftFrames.toggle_frame(name, player[, state]) + # + Gui._prototype_element:style(style_define)
    -

    Toggles the visibility of a left frame, or sets its visibility state

    +

    Extension of Gui.element when using the table method, values applied after the element is drawn

    @@ -2609,107 +945,98 @@
  • - name + style_define : - (string) + (table or function) - the name of the gui frame to toggle + used to define how the style is applied, using a table is the simplist way of doing this
  • + + + + + + Returns: +
      +
    • + (table) + the new element define that is used to register events to this element +
    • +
    + + + + + + + + Usage: +
    -- Setting the height and width of the example button
    +local example_button =
    +Gui.element{
    +    type = 'button',
    +    caption = 'Example Button'
    +}
    +:style{
    +    height = 25,
    +    width = 100
    +}
    +
    -- Using a function to set the style
    +local example_button =
    +Gui.element{
    +    type = 'button',
    +    caption = 'Example Button'
    +}
    +:style(function(style,element,...)
    +    local player = game.players[element.player_index]
    +    style.height = 25
    +    style.width = 100
    +    style.font_color = player.color
    +end)
    + + +
    +
    +
    +
    + # + Gui._prototype_element:add_to_top_flow([authenticator]) +
    +
    +
    +
    + +

    Adds an element to be drawn to the top flow when a player joins

    +

    + + + Parameters: + +
      + +
    • - player + authenticator : - (LuaPlayer) + (function) - the player to get the frame of - -
    • - - - - - -
    • - - state - - : - - (boolean) - - when given will be the state that the visibility is set to + called during toggle or update to decide if the element should be visible (optional)
    • -
    - - - - - Returns: -
      -
    • - (boolean) - the new state of the visibility -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames.new_frame(permission_name) -
    -
    -
    -
    - -

    Creates a new left frame define

    -

    - - - Parameters: - -
      - - - - - -
    • - - permission_name - - : - - (string) - - the name that can be used with the permission system - -
    • - -
    @@ -2719,7 +1046,7 @@
    • (table) - the new left frame define + the new element define that is used to register events to this element
    @@ -2729,20 +1056,26 @@ + Usage: +
    -- Adding the example button
    +example_button:add_to_top_flow(function(player)
    +    -- example button will only show when game time is less than 1 minute
    +    return player.online_time < 3600
    +end)
    - # - LeftFrames._prototype:set_open_by_default([state=true]) + # + Gui._prototype_element:add_to_left_flow([open_on_join])
    -

    Sets if the frame is visible when a player joins, can also be a function to return a boolean

    +

    Adds an element to be drawn to the left flow when a player joins

    @@ -2756,118 +1089,15 @@
  • - state + open_on_join : (boolean or function) - the default state of the visibility, can be a function - state param - player LuaPlayer - the player that has joined the game - state param - define_name string - the define name for the frame - state return - boolean - false will hide the frame - - (default: true) -
  • - - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:set_direction(direction) -
    -
    -
    -
    - -

    Sets the direction of the frame, either vertical or horizontal

    -

    - - - Parameters: - -
      - - - - - -
    • - - direction - - : - - (string) - - the direction to have the elements be added to the frame - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:_internal_draw(player) -
    -
    -
    -
    - -

    Creates the gui for the first time, used internally

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to draw the frame to + called during first darw to decide if the element is visible + (optional)
    • @@ -2879,8 +1109,8 @@ Returns:
      • - (LuaGuiElement) - the frame that was made + (table) + the new element define that is used to register events to this element
      @@ -2890,676 +1120,29 @@ - - -
    -
    -
    -
    - # - LeftFrames._prototype:get_frame(player) -
    -
    -
    -
    - -

    Gets the frame for this define from the left frame flow

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to get the frame of - -
    • - - -
    - - - - - Returns: -
      -
    • - (LuaGuiElement) - the frame in the left frame flow for this define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:is_open(player) -
    -
    -
    -
    - -

    Returns if the player currently has this define visible

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to get the frame of - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if it is open/visible -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:toggle(player) -
    -
    -
    -
    - -

    Toggles the visibility of the left frame

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to toggle the frame of - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - the new state of the visibility -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:update(player) -
    -
    -
    -
    - -

    Updates the contents of the left frame, first tries update callback, other wise will clear and redraw

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to update the frame of - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:update_all([update_offline=false]) -
    -
    -
    -
    - -

    Updates the frame for all players, see update

    -

    - - - Parameters: - -
      - - - - - -
    • - - update_offline - - : - - (boolean) - - when true will update the frame for offline players - - (default: false) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:redraw(player) -
    -
    -
    -
    - -

    Redraws the frame by calling on_draw, will always clear the frame

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to update the frame of - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:redraw_all([update_offline=false]) -
    -
    -
    -
    - -

    Redraws the frame for all players, see redraw

    -

    - - - Parameters: - -
      - - - - - -
    • - - update_offline - - : - - (boolean) - - when true will update the frame for offline players - - (default: false) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - LeftFrames._prototype:event_handler([action=update]) -
    -
    -
    -
    - -

    Creates an event handler that will trigger one of its functions, use with Event.add

    -

    - - - Parameters: - -
      - - - - - -
    • - - action - - : - - (string) - - the action to take on this event - - (default: update) -
    • - - -
    - - - - - - - - - - - + Usage: +
    -- Adding the example button
    +example_flow_with_button:add_to_left_flow(true)
    -

    Popups

    +

    Element Events

    - # - expcore.gui.core + # + Gui._prototype_element.on_opened
    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.event -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.elements.progress-bar -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.elements.buttons -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - mod-gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - resources.color_presets -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.global -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - PopupFrames.get_flow(player) -
    -
    -
    -
    - -

    Gets the left flow that contains the popup frames

    +

    Called when the player opens a GUI.

    - Parameters:
      @@ -3567,15 +1150,15 @@ -
    • +
    • - player + handler : - (LuaPlayer) + (function) - the player to get the flow for + the event handler which will be called
    • @@ -3585,13 +1168,6 @@ - Returns: -
        -
      • - (LuaGuiElement) - the left flow that contains the popup frames -
      • -
      @@ -3605,18 +1181,17 @@
      - # - PopupFrames.open(define_name, player[, open_time], ...) + # + Gui._prototype_element.on_closed
      -

      Opens a popup for the player, can give the amount of time it is open as well as params for the draw function

      +

      Called when the player closes the GUI they have open.

      - Parameters:
        @@ -3624,64 +1199,15 @@ -
      • +
      • - define_name + handler : - (string) + (function) - the name of the define that you want to open for the player - -
      • - - - - - -
      • - - player - - : - - (LuaPlayer) - - the player to open the popup for - -
      • - - - - - -
      • - - open_time - - : - - (number) - - the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default - - (optional) -
      • - - - - - -
      • - - ... - - : - - (any) - - the other params that you want to pass to your on_draw event + the event handler which will be called
      • @@ -3691,13 +1217,6 @@ - Returns: -
          -
        • - (LuaGuiElement) - the frame that was drawn, the inner gui flow which contains the content -
        • -
        @@ -3711,17 +1230,39 @@
        - # - PopupFrames.close_progress + # + Gui._prototype_element.on_click
        -

        Progress bar which when depleted will close the popup frame

        +

        Called when LuaGuiElement is clicked.

        + +
          + + + + + +
        • + + handler + + : + + (function) + + the event handler which will be called + +
        • + + +
        + @@ -3738,17 +1279,39 @@
        - # - PopupFrames.close_button + # + Gui._prototype_element.on_confirmed
        -

        A button which can be used to close the gui before the timer runs out

        +

        Called when a LuaGuiElement is confirmed, for example by pressing Enter in a textfield.

        + +
          + + + + + +
        • + + handler + + : + + (function) + + the event handler which will be called + +
        • + + +
        + @@ -3765,18 +1328,17 @@
        - # - PopupFrames.new_popup([name]) + # + Gui._prototype_element.on_checked_changed
        -

        Creates a new popup frame define

        +

        Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons).

        - Parameters:
          @@ -3784,17 +1346,16 @@ -
        • +
        • - name + handler : - (string) + (function) - the optional debug name that can be added + the event handler which will be called - (optional)
        • @@ -3803,13 +1364,6 @@ - Returns: -
            -
          • - (table) - the new popup frame define -
          • -
          @@ -3823,18 +1377,17 @@
          - # - PopupFrames._prototype:set_default_open_time(amount) + # + Gui._prototype_element.on_elem_changed
          -

          Sets the default open time for the popup, will be used if non is provided with open

          +

          Called when LuaGuiElement element value is changed (related to choose element buttons).

          - Parameters:
            @@ -3842,15 +1395,15 @@ -
          • +
          • - amount + handler : - (number) + (function) - the number of ticks, by default, the popup will be open for + the event handler which will be called
          • @@ -3860,13 +1413,6 @@ - Returns: -
              -
            • - (table) - the define to allow for chaining -
            • -
            @@ -3880,18 +1426,17 @@
            - # - PopupFrames._prototype:open(player[, open_time], ...) + # + Gui._prototype_element.on_location_changed
            -

            Opens this define for a player, can be given open time and any other params for the draw function

            +

            Called when LuaGuiElement element location is changed (related to frames in player.gui.screen).

            - Parameters:
              @@ -3899,48 +1444,15 @@ -
            • +
            • - player + handler : - (LuaPlayer) + (function) - the player to open the popup for - -
            • - - - - - -
            • - - open_time - - : - - (number) - - the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default - - (optional) -
            • - - - - - -
            • - - ... - - : - - (any) - - the other params that you want to pass to your on_draw event + the event handler which will be called
            • @@ -3949,41 +1461,6 @@ - - Returns: -
                -
              • - (LuaGuiElement) - the frame that was drawn, the inner gui flow which contains the content -
              • -
              - - - - - - - - - -
            -
    -

    Toolbar

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - @@ -3998,143 +1475,17 @@
    - # - expcore.gui.elements.buttons + # + Gui._prototype_element.on_tab_changed
    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.roles -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.event -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - mod-gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Toolbar.new_button([name]) -
    -
    -
    -
    - -

    Adds a new button to the toolbar

    +

    Called when LuaGuiElement selected tab is changed (related to tabbed-panes).

    - Parameters:
      @@ -4142,73 +1493,15 @@ -
    • +
    • - name + handler : - (string) + (function) - when given allows an alias to the button for the permission system - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the button define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Toolbar.add_button(button) -
    -
    -
    -
    - -

    Adds an existing buttton to the toolbar

    -

    - - - Parameters: - -
      - - - - - -
    • - - button - - : - - (table) - - the button define for the button to be added + the event handler which will be called
    • @@ -4231,18 +1524,17 @@
      - # - Toolbar.update(player) + # + Gui._prototype_element.on_selection_changed
      -

      Updates the player's toolbar with an new buttons or expected change in auth return

      +

      Called when LuaGuiElement selection state is changed (related to drop-downs and listboxes).

      - Parameters:
        @@ -4250,15 +1542,162 @@ -
      • +
      • - player + handler : - (LuaPlayer) + (function) - the player to update the toolbar for + the event handler which will be called + +
      • + + +
      + + + + + + + + + + + + + +
      +
      +
      +
      + # + Gui._prototype_element.on_switch_changed +
      +
      +
      +
      + +

      Called when LuaGuiElement switch state is changed (related to switches).

      +

      + + + +
        + + + + + +
      • + + handler + + : + + (function) + + the event handler which will be called + +
      • + + +
      + + + + + + + + + + + + + +
      +
      +
      +
      + # + Gui._prototype_element.on_text_change +
      +
      +
      +
      + +

      Called when LuaGuiElement text is changed by the player.

      +

      + + + +
        + + + + + +
      • + + handler + + : + + (function) + + the event handler which will be called + +
      • + + +
      + + + + + + + + + + + + + +
      +
      +
      +
      + # + Gui._prototype_element.on_value_changed +
      +
      +
      +
      + +

      Called when LuaGuiElement slider value is changed (related to the slider element).

      +

      + + + +
        + + + + + +
      • + + handler + + : + + (function) + + the event handler which will be called
      • @@ -4279,18 +1718,20 @@
    -

    Core

    +

    Top Flow

    - # - utils.gui + # + toggle_top_flow
    +

    Button which toggles the top flow elements

    +

    @@ -4309,13 +1750,15 @@
    - # - utils.game + # + top_flow_button_style
    +

    The style that should be used for buttons on the top flow

    +

    @@ -4334,14 +1777,74 @@
    - # - new_define(prototype[, debug_name]) + # + get_top_flow(player)
    -

    Used to create new element defines from a class prototype, please use the own given by the class

    +

    Gets the flow which contains the elements for the top flow

    +

    (player)

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to get the flow for + +
    • + + +
    + + + + + Returns: + + + + + + + + + Usage: +
    -- Geting your top element flow
    +local top_flow = Gui.get_top_flow(game.player)
    + + +
    +
    +
    +
    + # + update_top_flow(player) +
    +
    +
    +
    + +

    Updates the visible states of all the elements on a players top flow

    @@ -4355,13 +1858,66 @@
  • - prototype + player : - (table) + (LuaPlayer) - the class prototype that will be used for the element define + the player that you want to update the flow for + +
  • + + + + + + + + + + + + + + + Usage: +
    -- Update your flow
    +Gui.update_top_flow(game.player)
    + + +
    +
    +
    +
    + # + toggle_top_flow(player[, state]) +
    +
    +
    +
    + +

    Toggles the visible states of all the elements on a players top flow

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to toggle the flow for
    • @@ -4371,13 +1927,13 @@
    • - debug_name + state : - (string) + (boolean) - the name that you want to see while debuging + if given then the state will be set to this state (optional)
    • @@ -4391,13 +1947,48 @@ Returns:
      • - (table) - the new element define with all functions accessed via __index metamethod + (boolean) + the new visible state of the top flow
      + + + + + Usage: +
      -- Toggle your flow
      +Gui.toggle_top_flow(game.player)
      +
      -- Open your top flow
      +Gui.toggle_top_flow(game.player,true)
      + + +
    +
    +

    Left Flow

    +
    +
    +
    +
    + # + hide_left_flow +
    +
    +
    +
    + +

    Button which hides the elements in the left flow

    +

    + + + + + + + + @@ -4408,14 +1999,74 @@
    - # - get_define(name[, internal]) + # + get_left_flow(player)
    -

    Gets an element define give the uid, debug name or a copy of the element define

    +

    Gets the flow which contains the elements for the left flow

    +

    (player)

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to get the flow for + +
    • + + +
    + + + + + Returns: + + + + + + + + + Usage: +
    -- Geting your left element flow
    +local left_flow = Gui.get_left_flow(game.player)
    + + +
    +
    +
    +
    + # + hide_left_flow(player) +
    +
    +
    +
    + +

    Hides all left elements for a player

    @@ -4429,13 +2080,66 @@
  • - name + player : - (string or table) + (LuaPlayer) - the uid, debug name or define for the element define to get + the player to hide the elements for + +
  • + + + + + + + + + + + + + + + Usage: +
    -- Hide your left elements
    +Gui.hide_left_flow(game.player)
    + + +
    +
    +
    +
    + # + toggle_left_element(player, element_define[, state]) +
    +
    +
    +
    + +

    Toggles the visible state of all a left element for a player

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to toggle the element for
    • @@ -4445,319 +2149,34 @@
    • - internal + element_define + + : + + (table) + + the element that you want to toggle for the player + +
    • + + + + + +
    • + + state : (boolean) - when true the error trace is one level higher (used internally) + if given then the state will be set to this state (optional)
    • -
    - - - - - Returns: -
      -
    • - (table) - the element define that was found or an error -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - categorize_by_player(element) -
    -
    -
    -
    - -

    A categorize function to be used with add_store, each player has their own value

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that will be converted to a string - -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the player's name who owns this element -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - categorize_by_force(element) -
    -
    -
    -
    - -

    A categorize function to be used with add_store, each force has its own value

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that will be converted to a string - -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the player's force name who owns this element -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - categorize_by_surface(element) -
    -
    -
    -
    - -

    A categorize function to be used with add_store, each surface has its own value

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that will be converted to a string - -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the player's surface name who owns this element -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - draw(name, element) -
    -
    -
    -
    - -

    Draws a copy of the element define to the parent element, see draw_to

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string or table) - - the uid, debug name or define for the element define to draw - -
    • - - - - - -
    • - - element - - : - - (LuaGuiEelement) - - the parent element that it the define will be drawn to - -
    • - - -
    - - - - - Returns: - - - - - - - - - - -
    -
    -
    -
    - # - toggle_enabled(element) -
    -
    -
    -
    - -

    Will toggle the enabled state of an element

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the gui element to toggle - -
    • - -
    @@ -4767,7 +2186,7 @@
    • (boolean) - the new state that the element has + the new visible state of the element
    @@ -4777,20 +2196,28 @@ + Usage: +
    -- Toggle your example button
    +Gui.toggle_top_flow(game.player,example_flow_with_button)
    +
    -- Open your example button
    +Gui.toggle_top_flow(game.player,example_flow_with_button,true)
    +
    +

    Helper Functions

    +
    - # - toggle_visible(element) + # + get_player_from_element(element)
    -

    Will toggle the visiblity of an element

    +

    Get the player that owns a gui element

    @@ -4810,7 +2237,7 @@ (LuaGuiElement) - the gui element to toggle + the element that you want to get the owner of @@ -4823,308 +2250,272 @@ Returns:
    • + (LuaPlayer) + the player that owns this element +
    • +
    + + + + + + + + Usage: +
    -- Geting the owner of an element
    +local player = Gui.get_player_from_element(element)
    + + +
    +
    +
    +
    + # + toggle_enabled_state(element[, state]) +
    +
    +
    +
    + +

    Will toggle the enabled state of an element or set it to the one given

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to toggle the state of + +
    • + + + + + +
    • + + state + + : + (boolean) - the new state that the element has -
    • -
    - - - - - - - - -
    -
    -
    -
    - # - set_padding(element[, up=0][, down=0][, left=0][, right=0]) -
    -
    -
    -
    - -

    Sets the padding for a gui element

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element to set the padding for - -
    • - - - - - -
    • - - up - - : - - (number) - - the amount of padding on the top - - (default: 0) -
    • - - - - - -
    • - - down - - : - - (number) - - the amount of padding on the bottom - - (default: 0) -
    • - - - - - -
    • - - left - - : - - (number) - - the amount of padding on the left - - (default: 0) -
    • - - - - - -
    • - - right - - : - - (number) - - the amount of padding on the right - - (default: 0) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - set_padding_style(style[, up=0][, down=0][, left=0][, right=0]) -
    -
    -
    -
    - -

    Sets the padding for a gui style

    -

    - - - Parameters: - -
      - - - - - -
    • - - style - - : - - (LuaStyle) - - the element to set the padding for - -
    • - - - - - -
    • - - up - - : - - (number) - - the amount of padding on the top - - (default: 0) -
    • - - - - - -
    • - - down - - : - - (number) - - the amount of padding on the bottom - - (default: 0) -
    • - - - - - -
    • - - left - - : - - (number) - - the amount of padding on the left - - (default: 0) -
    • - - - - - -
    • - - right - - : - - (number) - - the amount of padding on the right - - (default: 0) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - create_alignment(element[, name][, horizontal_align='right'][, vertical_align='center']) -
    -
    -
    -
    - -

    Allows the creation of an alignment flow to place elements into

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element to add this alignment into - -
    • - - - - - -
    • - - name - - : - - (string) - - the name to use for the alignment + the state that you want to set (optional)
    • +
    + + + + + Returns: +
      +
    • + (boolean) + the new enabled state that the element has +
    • +
    + + + + + + + + Usage: +
    -- Toggling the the enabled state
    +local new_enabled_state = Gui.toggle_enabled_state(element)
    + + +
    +
    +
    +
    + # + toggle_visible_state(element[, state]) +
    +
    +
    +
    + +

    Will toggle the visible state of an element or set it to the one given

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to toggle the state of + +
    • + + + + + +
    • + + state + + : + + (boolean) + + the state that you want to set + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + the new visible state that the element has +
    • +
    + + + + + + + + Usage: +
    -- Toggling the the visible state
    +local new_visible_state = Gui.toggle_visible_state(element)
    + + +
    +
    +
    +
    + # + destroy_if_valid(element) +
    +
    +
    +
    + +

    Destory a gui element without causing any errors, likly if the element may have already been removed

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to remove + +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + true if the element was valid and has been removed +
    • +
    + + + + + + + + Usage: +
    -- Likely use case for element not existing
    +Gui.destroy_if_valid(element[child_name])
    + + +
    +
    +
    +
    + # + alignment(parent[, horizontal_align='right'][, vertical_align='center'][, name='alignment']) +
    +
    +
    +
    + +

    Draw a flow that has custom element alignments, default is right align

    +

    + + + Parameters: + +
      + + + + + +
    • + + parent + + : + + (LuaGuiElement) + + the parent element that the alignment flow will be added to + +
    • + + @@ -5136,7 +2527,7 @@ (string) - the horizontal alignment of the elements in this flow + the horizontal alignment of the elements in the flow (default: 'right') @@ -5153,12 +2544,29 @@ (string) - the vertical alignment of the elements in this flow + the vertical alignment of the elements in the flow (default: 'center') + + + +
    • + + name + + : + + (string) + + the name of the alignment flow + + (default: 'alignment') +
    • + +
    @@ -5168,7 +2576,7 @@
    • (LuaGuiElement) - the new flow that was created + the alignment flow that was created
    @@ -5178,20 +2586,25 @@ + Usage: +
    -- Adding a right align flow
    +local alignment = Gui.alignment(element,'example_right_alignment')
    +
    -- Adding a horizontal center and top align flow
    +local alignment = Gui.alignment(element,'example_center_top_alignment','center','top')
    - # - destroy_if_valid(element) + # + scroll_table(parent, height, column_count[, name='scroll'])
    -

    Destroies an element but tests for it being present and valid first

    +

    Draw a scroll pane that has a table inside of it

    @@ -5205,70 +2618,13 @@
  • - element + parent : (LuaGuiElement) - the element to be destroied - -
  • - - - - - - - - Returns: -
      -
    • - (boolean) - true if it was destoried -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - create_scroll_table(element, table_size, maximal_height[, name='scroll']) -
    -
    -
    -
    - -

    Creates a scroll area with a table inside, table can be any size

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element to add this scroll into + the parent element that the scroll table will be added to
    • @@ -5278,13 +2634,13 @@
    • - table_size + height : (number) - the number of columns in the table + the maximum height for the scroll pane
    • @@ -5294,13 +2650,13 @@
    • - maximal_height + column_count : (number) - the max hieght of the scroll + the number of columns that the table will have
    • @@ -5316,7 +2672,7 @@ (string) - the name of the scoll element + the name of the scroll pane that is added, the table is always called 'table' (default: 'scroll') @@ -5331,7 +2687,7 @@
      • (LuaGuiElement) - the table that was made + the table that was created
      @@ -5341,20 +2697,23 @@ + Usage: +
      -- Adding a scroll table with max height of 200 and column count of 3
      +local scroll_table = Gui.scroll_table(element,'example_scroll_table',200,3)
    - # - create_header(element, caption[, tooltip][, right_align][, name='header']) + # + header(parent, caption[, tooltip][, add_alignment=false][, name='header'])
    -

    Creates a header section with a label and button area

    +

    Used to add a header to a frame, this has the option for a custom right alignment flow for buttons

    @@ -5368,13 +2727,13 @@
  • - element + parent : (LuaGuiElement) - the element to add this header into + the parent element that the header will be added to
  • @@ -5388,9 +2747,9 @@ : - (localeString) + (string or LocalizedString) - the caption that is used as the title + the caption that will be shown on the header @@ -5404,9 +2763,9 @@ : - (localeString) + (string or LocalizedString) - the tooltip that is shown on the caption + the tooltip that will be shown on the header (optional) @@ -5417,15 +2776,15 @@
  • - right_align + add_alignment : (boolean) - when true will include the right align area + when true an alignment flow will be added for buttons - (optional) + (default: false)
  • @@ -5440,7 +2799,7 @@ (string) - the name of the header area + the name of the header that is being added, the alignment is always called 'alignment' (default: 'header') @@ -5455,7 +2814,7 @@
    • (LuaGuiElement) - the header that was made, or the align area if that was created + either the header or the header alignment if add_alignment is true
    @@ -5465,5478 +2824,15 @@ - - -
    -
    -

    Buttons

    -
    -
    -
    -
    - # - mod-gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Button.new_button([name]) -
    -
    -
    -
    - -

    Creates a new button element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new button element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Button._prototype:set_sprites(sprite[, hovered_sprite][, clicked_sprite]) -
    -
    -
    -
    - -

    Adds sprites to a button making it a sprite button

    -

    - - - Parameters: - -
      - - - - - -
    • - - sprite - - : - - (SpritePath) - - the sprite path for the default sprite for the button - -
    • - - - - - -
    • - - hovered_sprite - - : - - (SpritePath) - - the sprite path for the sprite when the player hovers over the button - - (optional) -
    • - - - - - -
    • - - clicked_sprite - - : - - (SpritePath) - - the sprite path for the sprite when the player clicks the button - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - returns the button define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Button._prototype:set_click_filter(filter[, ...]) -
    -
    -
    -
    - -

    Adds a click / mouse button filter to the button

    -

    - - - Parameters: - -
      - - - - - -
    • - - filter - - : - - (table) - - ?string|table either a of mouse buttons or the first mouse button to filter, with a table true means allowed - -
    • - - - - - -
    • - - ... - - : - - (table) - - when filter is not a you can add the mouse buttons one after each other - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - returns the button define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Button._prototype:set_key_filter(filter[, ...]) -
    -
    -
    -
    - -

    Adds a control key filter to the button

    -

    - - - Parameters: - -
      - - - - - -
    • - - filter - - : - - (table) - - ?string|table either a of control keys or the first control keys to filter, with a table true means allowed - -
    • - - - - - -
    • - - ... - - : - - (table) - - when filter is not a you can add the control keys one after each other - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - returns the button define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -

    Checkboxs

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.store -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Checkbox.new_checkbox([name]) -
    -
    -
    -
    - -

    Creates a new checkbox element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new checkbox element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Checkbox.new_radiobutton([name]) -
    -
    -
    -
    - -

    Creates a new radiobutton element define, has all functions checkbox has

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new button element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - 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)

    -

    - - - Parameters: - -
      - - - - - -
    • - - option_set - - : - - (string) - - the name of the option set to add this element to - -
    • - - - - - -
    • - - option_name - - : - - (string) - - the name of this option that will be used to identify it - -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Checkbox._prototype_radiobutton:get_store(category, internal) -
    -
    -
    -
    - -

    Gets the stored value of the radiobutton or the option set if present

    -

    - - - Parameters: - -
      - - - - - -
    • - - category - - : - - (string) - - [opt] the category to get such as player name or force name - -
    • - - - - - -
    • - - internal - - : - - (boolean) - - used to prevent stackover flow - -
    • - - -
    - - - - - Returns: -
      -
    • - (any) - the value that is stored for this define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Checkbox._prototype_radiobutton:set_store(category, value, internal) -
    -
    -
    -
    - -

    Sets the stored value of the radiobutton or the option set if present

    -

    - - - Parameters: - -
      - - - - - -
    • - - category - - : - - (string) - - [opt] the category to get such as player name or force name - -
    • - - - - - -
    • - - value - - : - - (boolean) - - the value to set for this define, must be valid for its type ie for checkbox etc - -
    • - - - - - -
    • - - internal - - : - - (boolean) - - used to prevent stackover flow - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if the value was set -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Checkbox.new_option_set(callback, categorize) -
    -
    -
    -
    - -

    Registers a new option set that can be linked to radiobuttons (only one can be true at a time)

    -

    - - - Parameters: - -
      - - - - - -
    • - - callback - - : - - (function) - - the update callback when the value of the option set changes - callback param - value string - the new selected option for this option set - callback param - category string - the category that updated if categorize was used - -
    • - - - - - -
    • - - categorize - - : - - (function) - - the function used to convert an element into a string - -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the name of this option set to be passed to add_as_option -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Checkbox.draw_option_set(name, element) -
    -
    -
    -
    - -

    Draws all radiobuttons that are part of an option set at once (Gui.draw will not work)

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the option set to draw the radiobuttons of - -
    • - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the parent element that the radiobuttons will be drawn to - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Checkbox.reset_radiobuttons(element[, exclude][, recursive=false]) -
    -
    -
    -
    - -

    Sets all radiobutton in a element to false (unless excluded) and can act recursively

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the root gui element to start setting radio buttons from - -
    • - - - - - -
    • - - exclude - - : - - (table) - - ?string|table the name of the radiobutton to exclude or a of radiobuttons where true will set the state true - - (optional) -
    • - - - - - -
    • - - recursive - - : - - (number or boolean) - - if true will recur as much as possible, if a will recur that number of times - - (default: false) -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if successful -
    • -
    - - - - - - - - - -
    -
    -

    Dropdowns

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Dropdown.new_dropdown([name]) -
    -
    -
    -
    - -

    Creates a new dropdown element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new dropdown element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Dropdown.new_list_box([name]) -
    -
    -
    -
    - -

    Creates a new list box element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new list box element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Dropdown._prototype:new_static_options(options[, ...], the) -
    -
    -
    -
    - -

    Adds new static options to the dropdown which will trigger the general callback

    -

    - - - Parameters: - -
      - - - - - -
    • - - options - - : - - (table) - - ?string|table either a of option strings or the first option string, with a table values are the options - -
    • - - - - - -
    • - - ... - - : - - (table) - - when options is not a you can add the options one after each other - - (optional) -
    • - - - - - -
    • - - the - - : - - (self) - - define to allow chaining - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - 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)

    -

    - - - Parameters: - -
      - - - - - -
    • - - 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 - -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - 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)

    -

    - - - Parameters: - -
      - - - - - -
    • - - option - - : - - (string) - - the name of the option to trigger the callback on; if not already added then will be added as an option - -
    • - - - - - -
    • - - 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 - -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Dropdown.select_value(element, value) -
    -
    -
    -
    - -

    Selects the option from a dropdown or list box given the value rather than key

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that contains the option - -
    • - - - - - -
    • - - value - - : - - (string) - - the option to select from the dropdown - -
    • - - -
    - - - - - Returns: -
      -
    • - (number) - the key where the value was -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Dropdown.get_selected_value(element) -
    -
    -
    -
    - -

    Returns the currently selected value rather than index

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the gui element that you want to get the value of - -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the value that is currently selected -
    • -
    - - - - - - - - - -
    -
    -

    Elem Buttons

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - ElemButton.new_elem_button([name]) -
    -
    -
    -
    - -

    Creates a new elem button element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new elem button element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - ElemButton._prototype.set_type -
    -
    -
    -
    - -

    Sets the type of the elem button, the type is required so this must be called at least once

    -

    - - - -
      - - - - - -
    • - - type - - : - - (string) - - the type that this elem button is see factorio api - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ElemButton._prototype:set_default(value) -
    -
    -
    -
    - -

    Sets the default value for the elem button, this may be a function or a string

    -

    - - - Parameters: - -
      - - - - - -
    • - - value - - : - - (string or function) - - string a will be a static default and a function will be called when drawn to get the default - -
    • - - -
    - - - - - Returns: -
      -
    • - (the) - element define to allow for chaining -
    • -
    - - - - - - - - - -
    -
    -

    Progress Bars

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.global -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar.set_maximum(element, amount) -
    -
    -
    -
    - -

    Sets the maximum value that represents the end value of the progress bar

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement or string) - - either a gui element or a registered define - -
    • - - - - - -
    • - - amount - - : - - (number) - - the amount to have set as the maximum - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar.increment(element[, amount=1]) -
    -
    -
    -
    - -

    Increases the value of the progressbar, if a define is given all of its instances have incremented

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement or string) - - either a gui element or a registered define - -
    • - - - - - -
    • - - amount - - : - - (number) - - the amount to increase the progressbar by - - (default: 1) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar.decrement(element[, amount=1]) -
    -
    -
    -
    - -

    Decreases the value of the progressbar, if a define is given all of its instances have decremented

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement or string) - - either a gui element or a registered define - -
    • - - - - - -
    • - - amount - - : - - (number) - - the amount to decrease the progressbar by - - (default: 1) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar.new_progressbar([name]) -
    -
    -
    -
    - -

    Creates a new progressbar element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new progressbar element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:set_default_maximum(amount) -
    -
    -
    -
    - -

    Sets the maximum value that represents the end value of the progress bar

    -

    - - - Parameters: - -
      - - - - - -
    • - - amount - - : - - (number) - - the amount to have set as the maximum - -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:use_count_down([state=true]) -
    -
    -
    -
    - -

    Will set the progress bar to start at 1 and trigger when it hits 0

    -

    - - - Parameters: - -
      - - - - - -
    • - - state - - : - - (boolean) - - when true the bar will start filled, to be used with decrease - - (default: true) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:increment([amount=1][, category]) -
    -
    -
    -
    - -

    Increases the value of the progressbar

    -

    - - - Parameters: - -
      - - - - - -
    • - - amount - - : - - (number) - - the amount to increase the progressbar by - - (default: 1) -
    • - - - - - -
    • - - category - - : - - (string) - - the category that is used with a store - - (optional) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:increment_filtered([amount=1], filter) -
    -
    -
    -
    - -

    Increases the value of the progressbar, if the filter condition is met, does not work with store

    -

    - - - Parameters: - -
      - - - - - -
    • - - amount - - : - - (number) - - the amount to increase the progressbar by - - (default: 1) -
    • - - - - - -
    • - - filter - - : - - (function) - - the filter to be used - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:decrement([amount=1][, category]) -
    -
    -
    -
    - -

    Decreases the value of the progressbar

    -

    - - - Parameters: - -
      - - - - - -
    • - - amount - - : - - (number) - - the amount to decrease the progressbar by - - (default: 1) -
    • - - - - - -
    • - - category - - : - - (string) - - the category that is used with a store - - (optional) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:decrement_filtered([amount=1], filter) -
    -
    -
    -
    - -

    Decreases the value of the progressbar, if the filter condition is met, does not work with store

    -

    - - - Parameters: - -
      - - - - - -
    • - - amount - - : - - (number) - - the amount to decrease the progressbar by - - (default: 1) -
    • - - - - - -
    • - - filter - - : - - (function) - - the filter to be used - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:add_element(element[, maximum]) -
    -
    -
    -
    - -

    Adds an element into the list of instances that will are waiting to complete, does not work with store - note use store if you want persistent data, this only stores the elements not the values which they have

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that you want to add into the waiting to complete list - -
    • - - - - - -
    • - - maximum - - : - - (number) - - the maximum for this element if not given the default for this define is used - - (optional) -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:reset_element(element) -
    -
    -
    -
    - -

    Resets an element, or its store, to be back at the start, either 1 or 0

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that you want to reset the progress of - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:event_counter([filter]) -
    -
    -
    -
    - -

    Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented

    -

    - - - Parameters: - -
      - - - - - -
    • - - filter - - : - - (function) - - when given will use filtered increment - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (function) - the event handler -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - ProgressBar._prototype:event_countdown([filter]) -
    -
    -
    -
    - -

    Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented

    -

    - - - Parameters: - -
      - - - - - -
    • - - filter - - : - - (function) - - when given will use filtered decrement - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (function) - the event handler -
    • -
    - - - - - - - - - -
    -
    -

    Sliders

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.instances -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Slider.new_slider([name]) -
    -
    -
    -
    - -

    Creates a new slider element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new slider element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Slider._prototype:set_range([min][, max]) -
    -
    -
    -
    - -

    Sets the range of a slider, if not used will use default values for a slider

    -

    - - - Parameters: - -
      - - - - - -
    • - - min - - : - - (number) - - the minimum value that the slider can take - - (optional) -
    • - - - - - -
    • - - max - - : - - (number) - - the maximum value that the slider can take - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - 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

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the parent element that the label will be drawn to - -
    • - - -
    - - - - - Returns: -
      -
    • - (LuaGuiElement) - the new label element so that styles can be applied -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Slider._prototype:enable_auto_draw_label([state=true]) -
    -
    -
    -
    - -

    Enables auto draw of the label, the label will share the same parent element as the slider

    -

    - - - Parameters: - -
      - - - - - -
    • - - state - - : - - (boolean) - - when false will disable the auto draw of the label - - (default: true) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -

    Text

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.prototype -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Text.new_text_field([name]) -
    -
    -
    -
    - -

    Creates a new text field element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new text field element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Text.new_text_box([name]) -
    -
    -
    -
    - -

    Creates a new text box element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the optional debug name that can be added - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new text box element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Text._prototype_box:set_selectable([state=true]) -
    -
    -
    -
    - -

    Sets the text box to be selectable

    -

    - - - Parameters: - -
      - - - - - -
    • - - state - - : - - (boolean) - - when false will set the state to false - - (default: true) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - table the define to allow for chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Text._prototype_box:set_word_wrap([state=true]) -
    -
    -
    -
    - -

    Sets the text box to have word wrap

    -

    - - - Parameters: - -
      - - - - - -
    • - - state - - : - - (boolean) - - when false will set the state to false - - (default: true) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - table the define to allow for chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Text._prototype_box:set_read_only([state=true]) -
    -
    -
    -
    - -

    Sets the text box to be read only

    -

    - - - Parameters: - -
      - - - - - -
    • - - state - - : - - (boolean) - - when false will set the state to false - - (default: true) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - table the define to allow for chaining -
    • -
    - - - - - - - - - -
    -
    -

    Instances

    -
    -
    -
    -
    - # - utils.global -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Instances.has_categories(name) -
    -
    -
    -
    - -

    Returns if a instance group has a serializer function; must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if there is a serializer function -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Instances.is_registered(name) -
    -
    -
    -
    - -

    Returns if the given name is a registered instance group

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group you are testing - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if the name is registered -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Instances.register(name[, serializer]) -
    -
    -
    -
    - -

    Registers the name of an instance group to allow for storing element instances

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group; must to unique - -
    • - - - - - -
    • - - serializer - - : - - (function) - - function used to turn the element into a string - serializer param - element LuaGuiElement - the gui element to be turned into a string - serializer return - string - the category that the element will be added to like the player's name or force's name - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the name that was added so it can be used as a variable -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Instances.add_element(name, element) -
    -
    -
    -
    - -

    Adds an element to the instance group under the correct category; must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group to add the element to - -
    • - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element to add the the instance group - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Instances.get_elements_raw(name[, category]) -
    -
    -
    -
    - -

    Gets all element instances without first removing any invalid ones; used internally and must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group to get the instances of - -
    • - - - - - -
    • - - category - - : - - (string) - - the category to get the instance from, not needed when no serializer function - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the table of element instances of which some may be invalid -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Instances.get_valid_elements(name[, category][, callback]) -
    -
    -
    -
    - -

    Gets all valid element instances and has the option of running a callback on those that are valid

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group to get the instances of - -
    • - - - - - -
    • - - category - - : - - (string) - - the category to get the instances of, not needed when no serializer function - - (optional) -
    • - - - - - -
    • - - callback - - : - - (function) - - when given the callback will be ran on all valid elements - callback param - element LuaGuiElement - the current valid element - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the table of element instances with all invalid ones removed -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Instances.unregistered_add_element(name, category, element) -
    -
    -
    -
    - -

    A version of add_element that does not require the group to be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group to add the element to - -
    • - - - - - -
    • - - category - - : - - (string or nil) - - the category to add the element to, can be nil but must still be given - -
    • - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element to add to the instance group - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Instances.unregistered_get_elements(name, category[, callback]) -
    -
    -
    -
    - -

    A version of get_elements that does not require the group to be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group to get the instances of - -
    • - - - - - -
    • - - category - - : - - (string or nil) - - the category to get the instances of, can be nil but must still be given - -
    • - - - - - -
    • - - callback - - : - - (function) - - when given will be called on all valid instances - callback param - element LuaGuiElement - the current valid element - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the table of element instances with all invalid ones removed -
    • -
    - - - - - - - - - -
    -
    -

    Prototype

    -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.store -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.instances -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Constructor.event(event_name) -
    -
    -
    -
    - -

    Creates a new function to add functions to an event handler

    -

    - - - Parameters: - -
      - - - - - -
    • - - event_name - - : - - (string) - - the name of the event that callbacks will be added to - -
    • - - -
    - - - - - Returns: -
      -
    • - (function) - the function used to register handlers -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Constructor.extend(new_prototype) -
    -
    -
    -
    - -

    Extents a prototype with the base functions of all gui prototypes, no metatables

    -

    - - - Parameters: - -
      - - - - - -
    • - - new_prototype - - : - - (table) - - the prototype that you want to add the functions to - -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the same prototype but with the new functions added -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Constructor.store(callback) -
    -
    -
    -
    - -

    Creates a new function which adds a store to a gui define

    -

    - - - Parameters: - -
      - - - - - -
    • - - callback - - : - - (function) - - the function called when needing to update the value of an element - -
    • - - -
    - - - - - Returns: -
      -
    • - (function) - the function that will add a store for this define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Constructor.setter(value_type, key[, second_key]) -
    -
    -
    -
    - -

    Creates a setter function that checks the type when a value is set

    -

    - - - Parameters: - -
      - - - - - -
    • - - value_type - - : - - (string) - - the type that the value should be when it is set - -
    • - - - - - -
    • - - key - - : - - (string) - - the key of the define that will be set - -
    • - - - - - -
    • - - second_key - - : - - (string) - - allows for setting of a key in a sub table - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (function) - the function that will check the type and set the value -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype:uid() -
    -
    -
    -
    - -

    Gets the uid for the element define

    -

    - - - - - - Returns: -
      -
    • - (string) - the uid of this element define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype.debug_name -
    -
    -
    -
    - -

    Sets a debug alias for the define

    -

    - - - -
      - - - - - -
    • - - name - - : - - (string) - - the debug name for the element define that can be used to get this element define - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype.set_caption -
    -
    -
    -
    - -

    Sets the caption for the element define

    -

    - - - -
      - - - - - -
    • - - caption - - : - - (string) - - the caption that will be drawn with the element - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype.set_tooltip -
    -
    -
    -
    - -

    Sets the tooltip for the element define

    -

    - - - -
      - - - - - -
    • - - tooltip - - : - - (string) - - the tooltip that will be displayed for this element when drawn - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype.set_pre_authenticator -
    -
    -
    -
    - -

    Sets an authenticator that blocks the draw function if check fails

    -

    - - - -
      - - - - - -
    • - - callback - - : - - (function) - - the function that will be ran to test if the element should be drawn or not - callback param - LuaPlayer player - the player that the element is being drawn to - callback param - string define_name - the name of the define that is being drawn - callback return - boolean - false will stop the element from being drawn - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype.set_post_authenticator -
    -
    -
    -
    - -

    Sets an authenticator that disables the element if check fails

    -

    - - - -
      - - - - - -
    • - - callback - - : - - (function) - - the function that will be ran to test if the element should be enabled or not - callback param - LuaPlayer player - the player that the element is being drawn to - callback param - string define_name - the name of the define that is being drawn - callback return - boolean - false will disable the element - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype.on_draw -
    -
    -
    -
    - -

    Registers a callback to the on_draw event

    -

    - - - -
      - - - - - -
    • - - callback - - : - - (function) - - - callback param - LuaPlayer player - the player that the element was drawn to - callback param - LuaGuiElement element - the element that was drawn - callback param - any ... - any other params passed by the draw_to function - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype.on_style_update -
    -
    -
    -
    - -

    Registers a callback to the on_style_update event

    -

    - - - -
      - - - - - -
    • - - callback - - : - - (function) - - - callback param - LuaStyle style - the style that was changed and/or needs changing - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Prototype:set_style(style[, callback]) -
    -
    -
    -
    - -

    Sets the style for the element define

    -

    - - - Parameters: - -
      - - - - - -
    • - - style - - : - - (string) - - the style that will be used for this element when drawn - -
    • - - - - - -
    • - - callback - - : - - (function) - - function is called when element is drawn to alter its style - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the element define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype:set_embedded_flow(state) -
    -
    -
    -
    - -

    Sets the element to be drawn inside a nameless flow, can be given a name using a function

    -

    - - - Parameters: - -
      - - - - - -
    • - - state - - : - - (boolean or function) - - when true a padless flow is created to contain the element - -
    • - - -
    - - - - - Returns: -
      -
    • - (self) - the element define to allow chaining -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype:raise_event(event_name, ...) -
    -
    -
    -
    - -

    Raises a custom event for this define, any number of params can be given

    -

    - - - Parameters: - -
      - - - - - -
    • - - event_name - - : - - (string) - - the name of the event that you want to raise - -
    • - - - - - -
    • - - ... - - : - - (any) - - any params that you want to pass to the event - -
    • - - -
    - - - - - Returns: -
      -
    • - (number) - the number of handlers that were registered -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype:draw_to(element) -
    -
    -
    -
    - -

    The main function for defines, when called will draw an instance of this define to the given element - what is drawn is based on the data in draw_data which is set using other functions

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element that the define will draw a instance of its self onto - -
    • - - -
    - - - - - Returns: - - - - - - - - - - -
    -
    -
    -
    - # - Prototype:get_store(category) -
    -
    -
    -
    - -

    Gets the value in this elements store, category needed if serializer function used

    -

    - - - Parameters: - -
      - - - - - -
    • - - category - - : - - (string) - - [opt] the category to get such as player name or force name - -
    • - - -
    - - - - - Returns: -
      -
    • - (any) - the value that is stored for this define -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype:set_store(category, value) -
    -
    -
    -
    - -

    Sets the value in this elements store, category needed if serializer function used

    -

    - - - Parameters: - -
      - - - - - -
    • - - category - - : - - (string) - - [opt] the category to get such as player name or force name - -
    • - - - - - -
    • - - value - - : - - (any) - - the value to set for this define, must be valid for its type ie for checkbox etc - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if the value was set -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Prototype:clear_store([category]) -
    -
    -
    -
    - -

    Sets the value in this elements store to nil, category needed if serializer function used

    -

    - - - Parameters: - -
      - - - - - -
    • - - category - - : - - (string) - - the category to get such as player name or force name - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if the value was set -
    • -
    - - - - - - - - - -
    -
    -

    Test

    -
    -
    -
    -
    - # - expcore.gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.common -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - resources.color_presets -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.event -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.store -
    -
    -
    -
    - - - - - - - - - - - - - + Usage: +
    -- Adding a custom header
    +local header_alignment = Gui.header(
    +    element,
    +    'example_header',
    +    'Example Caption',
    +    'Example Tooltip',
    +    true
    +)
    @@ -10955,7 +2851,7 @@ generated by LDoc diff --git a/docs/core/Permissions-Groups.html b/docs/core/Permissions-Groups.html index 00b18e72..dc36167e 100644 --- a/docs/core/Permissions-Groups.html +++ b/docs/core/Permissions-Groups.html @@ -1432,7 +1432,7 @@ generated by LDoc diff --git a/docs/core/Roles.html b/docs/core/Roles.html index 3f2be0c2..25ceecf4 100644 --- a/docs/core/Roles.html +++ b/docs/core/Roles.html @@ -3152,7 +3152,7 @@ generated by LDoc diff --git a/docs/core/Store.html b/docs/core/Store.html index 1d8ad527..fd876dbc 100644 --- a/docs/core/Store.html +++ b/docs/core/Store.html @@ -262,7 +262,7 @@ Store.set(scenario_diffculty,'hard') end) -- When any key in the store is changed this function will trigger -Store.watch(player_scores,function(value,key) +Store.watch(player_scores,function(value,key,old_value) game.print(key..' now has a score of '..value) end) @@ -370,7 +370,7 @@ Store.set(player_scores,game.player,10) Used to trigger watcher functions, this may be used to trigger them if you did not use Store.update or Store.set - raw_trigger(store[, key][, value]) + raw_trigger(store[, key][, value][, old_value]) Used to trigger watcher functions, the value and key are passed directly to the watchers regardless if the value is correct @@ -791,7 +791,7 @@ Store.set(player_scores,game.player,10) end) -- Register the watcher so that when we change the value the message is printed -Store.watch(player_scores,function(value,key) +Store.watch(player_scores,function(value,key,old_value) game.print(key..' now has a score of '..value) end) @@ -1361,7 +1361,7 @@ Store.set(player_scores,game.player,10)
    # - raw_trigger(store[, key][, value]) + raw_trigger(store[, key][, value][, old_value])
    @@ -1426,6 +1426,23 @@ Store.set(player_scores,game.player,10) + + + +
  • + + old_value + + : + + (any) + + the old value that was at this key or store often the same if value is a table, passed directly to the watcher + + (optional) +
  • + + @@ -1445,7 +1462,7 @@ Store.set(player_scores,game.player,10) -- Trigger the watchers with a fake change of diffculty -- This is mostly used internally but it can be useful in other cases -Store.raw_trigger(scenario_diffculty,nil,'normal') +
    Store.raw_trigger(scenario_diffculty,nil,'normal','normal')
    @@ -1464,7 +1481,7 @@ Store.set(player_scores,game.player,10) generated by LDoc diff --git a/docs/core/Sudo.html b/docs/core/Sudo.html index 23573d85..27c2542b 100644 --- a/docs/core/Sudo.html +++ b/docs/core/Sudo.html @@ -544,7 +544,7 @@ generated by LDoc diff --git a/docs/guis/Player-List.html b/docs/guis/Player-List.html index da3e4e7f..0dbdaafd 100644 --- a/docs/guis/Player-List.html +++ b/docs/guis/Player-List.html @@ -626,7 +626,7 @@ generated by LDoc diff --git a/docs/guis/Rocket-Info.html b/docs/guis/Rocket-Info.html index cd01fbd5..3de18001 100644 --- a/docs/guis/Rocket-Info.html +++ b/docs/guis/Rocket-Info.html @@ -629,7 +629,7 @@ generated by LDoc diff --git a/docs/guis/Science-Info.html b/docs/guis/Science-Info.html index 7a48f8dc..5d2fbcd2 100644 --- a/docs/guis/Science-Info.html +++ b/docs/guis/Science-Info.html @@ -247,6 +247,9 @@ expcore.gui + expcore.gui + + utils.event @@ -267,8 +270,20 @@ - science_info - Registers the science info + production_label + Data label that contains the value and the surfix + + + science_pack_base + Adds 4 elements that show the data for a science pack + + + task_list_container + Main task list container for the left flow + + + task_list_toggle + Button on the top flow used to toggle the task list container @@ -297,6 +312,31 @@ + + + + + + + +
    +
    +
    + # + expcore.gui +
    +
    +
    +
    + + + + + + + + + @@ -410,14 +450,95 @@
    - # - science_info + # + production_label
    -

    Registers the science info

    +

    Data label that contains the value and the surfix

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + science_pack_base +
    +
    +
    +
    + +

    Adds 4 elements that show the data for a science pack

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + task_list_container +
    +
    +
    +
    + +

    Main task list container for the left flow

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + task_list_toggle +
    +
    +
    +
    + +

    Button on the top flow used to toggle the task list container

    @@ -449,7 +570,7 @@ generated by LDoc
    diff --git a/docs/guis/Task-List.html b/docs/guis/Task-List.html index 44170d3b..8e546493 100644 --- a/docs/guis/Task-List.html +++ b/docs/guis/Task-List.html @@ -271,27 +271,43 @@ add_new_task - Button in the header to add a new task - - - confirm_edit - Used to save changes to a task - - - cancel_edit - Used to cancel any changes you made to a task - - - discard_task - Removes the task from the list + Button displayed in the ehader bar, used to add a new task edit_task - Opens edit mode for the task + Button displayed next to tasks which the user is can edit, used to start editing a task - task_list - Registers the task list + discard_task + Button displayed next to tasks which the user is can edit, used to delete a task from the list + + + add_task_base + Set of three elements which make up each row of the task table + + + confirm_edit + Button displayed next to tasks which the user is currently editing, used to save changes + + + cancel_edit + Button displayed next to tasks which the user is currently editing, used to discard changes + + + task_editing + Editing state for a task, contrins a text field and the two edit buttons + + + task_label + Default state for a task, contains only a label with the task message + + + task_list_container + Main task list container for the left flow + + + task_list_toggle + Button on the top flow used to toggle the task list container @@ -465,88 +481,7 @@
    -

    Button in the header to add a new task

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - confirm_edit -
    -
    -
    -
    - -

    Used to save changes to a task

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - cancel_edit -
    -
    -
    -
    - -

    Used to cancel any changes you made to a task

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - discard_task -
    -
    -
    -
    - -

    Removes the task from the list

    +

    Button displayed in the ehader bar, used to add a new task

    @@ -573,7 +508,7 @@
    -

    Opens edit mode for the task

    +

    Button displayed next to tasks which the user is can edit, used to start editing a task

    @@ -593,14 +528,203 @@
    - # - task_list + # + discard_task
    -

    Registers the task list

    +

    Button displayed next to tasks which the user is can edit, used to delete a task from the list

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + add_task_base +
    +
    +
    +
    + +

    Set of three elements which make up each row of the task table

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + confirm_edit +
    +
    +
    +
    + +

    Button displayed next to tasks which the user is currently editing, used to save changes

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + cancel_edit +
    +
    +
    +
    + +

    Button displayed next to tasks which the user is currently editing, used to discard changes

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + task_editing +
    +
    +
    +
    + +

    Editing state for a task, contrins a text field and the two edit buttons

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + task_label +
    +
    +
    +
    + +

    Default state for a task, contains only a label with the task message

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + task_list_container +
    +
    +
    +
    + +

    Main task list container for the left flow

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + task_list_toggle +
    +
    +
    +
    + +

    Button on the top flow used to toggle the task list container

    @@ -632,7 +756,7 @@ generated by LDoc
    diff --git a/docs/guis/Warps-List.html b/docs/guis/Warps-List.html index 196ec539..2f4ac049 100644 --- a/docs/guis/Warps-List.html +++ b/docs/guis/Warps-List.html @@ -282,30 +282,10 @@ - zoom_to_map - Used on the name label to allow zoom to map - - - warp_timer - This timer controls when a player is able to warp, eg every 60 seconds - - - goto_warp - When the button is clicked it will teleport the player - - add_new_warp Will add a new warp to the list, checks if the player is too close to an existing one - confirm_edit - Confirms the edit to name or icon of the warp - - - cancel_edit - Cancels the editing changes of the selected warp name or icon - - discard_warp Removes a warp from the list, including the physical area and map tag @@ -314,8 +294,44 @@ Opens edit mode for the warp - warp_list - Registers the warp list + add_warp_base + Set of three elements which make up each row of the warp table + + + confirm_edit + Confirms the edit to name or icon of the warp + + + cancel_edit + Cancels the editing changes of the selected warp name or icon + + + warp_editing + Editing state for a warp, contrins a text field and the two edit buttons + + + warp_label + Default state for a warp, contains only a label with the warp name + + + warp_icon_button + Default state for the warp icon, when pressed teleports the player + + + warp_icon_editing + Editing state for the warp icon, chose elem used to chosse icon + + + warp_timer + This timer controls when a player is able to warp, eg every 60 seconds + + + warp_list_container + Main warp list container for the left flow + + + warp_list_toggle + Button on the top flow used to toggle the warp list container @@ -582,87 +598,6 @@
    - # - zoom_to_map -
    -
    -
    -
    - -

    Used on the name label to allow zoom to map

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - warp_timer -
    -
    -
    -
    - -

    This timer controls when a player is able to warp, eg every 60 seconds

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - goto_warp -
    -
    -
    -
    - -

    When the button is clicked it will teleport the player

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    # add_new_warp
    @@ -680,60 +615,6 @@ - - - - - - - -
    -
    -
    - # - confirm_edit -
    -
    -
    -
    - -

    Confirms the edit to name or icon of the warp

    -

    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - cancel_edit -
    -
    -
    -
    - -

    Cancels the editing changes of the selected warp name or icon

    -

    - - - - - - - - @@ -798,14 +679,257 @@
    - # - warp_list + # + add_warp_base
    -

    Registers the warp list

    +

    Set of three elements which make up each row of the warp table

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + confirm_edit +
    +
    +
    +
    + +

    Confirms the edit to name or icon of the warp

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + cancel_edit +
    +
    +
    +
    + +

    Cancels the editing changes of the selected warp name or icon

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_editing +
    +
    +
    +
    + +

    Editing state for a warp, contrins a text field and the two edit buttons

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_label +
    +
    +
    +
    + +

    Default state for a warp, contains only a label with the warp name

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_icon_button +
    +
    +
    +
    + +

    Default state for the warp icon, when pressed teleports the player

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_icon_editing +
    +
    +
    +
    + +

    Editing state for the warp icon, chose elem used to chosse icon

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_timer +
    +
    +
    +
    + +

    This timer controls when a player is able to warp, eg every 60 seconds

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_list_container +
    +
    +
    +
    + +

    Main warp list container for the left flow

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + warp_list_toggle +
    +
    +
    +
    + +

    Button on the top flow used to toggle the warp list container

    @@ -837,7 +961,7 @@ generated by LDoc
    diff --git a/docs/index.html b/docs/index.html index 4601a828..2b553d42 100644 --- a/docs/index.html +++ b/docs/index.html @@ -57,10 +57,7 @@ Gui Core Module - Gui - - This file is used to require all the different elements of the gui module - - each module has an outline here but for more details see their separate files in ./gui - - please read the files for more documentation that cant be shown here - - please note there is a rework planned but not started +- Used to define new gui elements and gui event handlers Permissions-Groups @@ -514,7 +511,7 @@ see ./expcore/commands.lua for more details generated by LDoc diff --git a/docs/modules/control.html b/docs/modules/control.html index 75103f1b..4fc84050 100644 --- a/docs/modules/control.html +++ b/docs/modules/control.html @@ -351,7 +351,7 @@ generated by LDoc diff --git a/docs/modules/utils.alien_evolution_progress.html b/docs/modules/utils.alien_evolution_progress.html index 51092a84..fdb538e2 100644 --- a/docs/modules/utils.alien_evolution_progress.html +++ b/docs/modules/utils.alien_evolution_progress.html @@ -419,7 +419,7 @@ fraction will decide a chance to spawn. 1 alien for 2 spawner's will have 50% on generated by LDoc diff --git a/docs/modules/utils.core.html b/docs/modules/utils.core.html index 31b33120..c94a85ca 100644 --- a/docs/modules/utils.core.html +++ b/docs/modules/utils.core.html @@ -1164,7 +1164,7 @@ generated by LDoc diff --git a/docs/modules/utils.debug.html b/docs/modules/utils.debug.html index 3d92af43..d9fc0fa5 100644 --- a/docs/modules/utils.debug.html +++ b/docs/modules/utils.debug.html @@ -654,7 +654,7 @@ generated by LDoc diff --git a/docs/modules/utils.dump_env.html b/docs/modules/utils.dump_env.html index e54ef510..1a275d2f 100644 --- a/docs/modules/utils.dump_env.html +++ b/docs/modules/utils.dump_env.html @@ -323,7 +323,7 @@ generated by LDoc diff --git a/docs/modules/utils.event.html b/docs/modules/utils.event.html index 87ca10a6..0613535f 100644 --- a/docs/modules/utils.event.html +++ b/docs/modules/utils.event.html @@ -1292,7 +1292,7 @@ generated by LDoc diff --git a/docs/modules/utils.event_core.html b/docs/modules/utils.event_core.html index e9fcbde4..4714e6ed 100644 --- a/docs/modules/utils.event_core.html +++ b/docs/modules/utils.event_core.html @@ -434,7 +434,7 @@ generated by LDoc diff --git a/docs/modules/utils.math.html b/docs/modules/utils.math.html index 12045d90..24562934 100644 --- a/docs/modules/utils.math.html +++ b/docs/modules/utils.math.html @@ -353,7 +353,7 @@ generated by LDoc diff --git a/docs/modules/utils.recipe_locker.html b/docs/modules/utils.recipe_locker.html index 59d49a86..11b985c3 100644 --- a/docs/modules/utils.recipe_locker.html +++ b/docs/modules/utils.recipe_locker.html @@ -441,7 +441,7 @@ generated by LDoc diff --git a/docs/modules/utils.state_machine.html b/docs/modules/utils.state_machine.html index 68e88fea..0166e736 100644 --- a/docs/modules/utils.state_machine.html +++ b/docs/modules/utils.state_machine.html @@ -752,7 +752,7 @@ generated by LDoc diff --git a/docs/modules/utils.table.html b/docs/modules/utils.table.html index 5ffe1e8b..f5c0e283 100644 --- a/docs/modules/utils.table.html +++ b/docs/modules/utils.table.html @@ -1418,7 +1418,7 @@ generated by LDoc diff --git a/docs/modules/utils.task.html b/docs/modules/utils.task.html index cfc96b04..4d025c24 100644 --- a/docs/modules/utils.task.html +++ b/docs/modules/utils.task.html @@ -651,7 +651,7 @@ generated by LDoc diff --git a/docs/modules/utils.timestamp.html b/docs/modules/utils.timestamp.html index fcf4b838..ffcfd375 100644 --- a/docs/modules/utils.timestamp.html +++ b/docs/modules/utils.timestamp.html @@ -442,7 +442,7 @@ generated by LDoc diff --git a/docs/topics/license.html b/docs/topics/license.html index 1eab766f..6d78546c 100644 --- a/docs/topics/license.html +++ b/docs/topics/license.html @@ -789,7 +789,7 @@ Public License instead of this License. But first, please read generated by LDoc diff --git a/docs/topics/readme.md.html b/docs/topics/readme.md.html index 46789283..488a3235 100644 --- a/docs/topics/readme.md.html +++ b/docs/topics/readme.md.html @@ -228,26 +228,29 @@

    ExpGaming Scenario Repository

    ## Explosive Gaming -

    Explosive Gaming (often ExpGaming) is a server hosting community with a strong focus on Factorio and games that follow similar ideas. Our factorio server are known for hosting large maps with the main goal of being a "mega base" which can produce as much as possible with in our reset schedule. Although these server tend to the more experienced players our server are open to everyone. You can find us through our [website], [discord], [wiki], or in the public games tab in factorio (ExpGaming S1). +

    Explosive Gaming (often ExpGaming) is a server hosting community with a strong focus on Factorio and games that follow similar ideas. Our Factorio server are known for hosting large maps with the main goal of being a "mega base" which can produce as much as possible within our reset schedule. Although these servers tend to attract the more experienced players, our servers are open to everyone. You can find us through our [website], [discord], [wiki], or in the public games tab in Factorio (ExpGaming S1, ExpGaming S2, etc.).

    ## Use and Installation

    1) Download this [git repository](https://github.com/explosivegaming/scenario/archive/master.zip) for the stable release. The dev branch can be found [here](https://github.com/explosivegaming/scenario/archive/dev.zip) for those who want the latest features. See [releases](#releases) for other release branches. -

    2) Extract the downloaded zip file from the branch you downloaded into factorio's scenario directory: +

    2) Extract the downloaded zip file from the branch you downloaded into Factorio's scenario directory: * Windows: `%appdata%\Factorio\scenarios` * Linux: `~/.factorio/scenarios`

    3) Within the scenario you can find `./config/_file_loader.lua` which contains a list of all the modules that will be loaded by the scenario; simply comment out (or remove) features you do not want but note that some modules may load other modules as dependencies even when removed from the list.

    4) More advanced users may want to play with the other configs files within `./config` but please be aware that some of the config files will require a basic understanding of lua while others may just be a list of values. -

    5) Once you have made any config changes that you wish to make open factorio, select play, then start scenario (or host scenario from within multiplayer tab), and select the scenario which will be called `scenario-master` if you have downloaded the latest stable release and have not changed the folder name. -

    6) The scenario will now load all the selected modules and start the map, any errors or exceptions raised in the scenario should not cause a game/server crash so if any features don't work as expected then it may be returning an error in the log, please report these errors to [the issues page](issues). +

    5) Once you have made any config changes that you wish to make open Factorio, select play, then start scenario (or host scenario from within multiplayer tab), and select the scenario which will be called `scenario-master` if you have downloaded the latest stable release and have not changed the folder name. +

    6) The scenario will now load all the selected modules and start the map, any errors or exceptions raised in the scenario should not cause a game/server crash, so if any features do not work as expected then it may be returning an error in the log. +Please report these errors to [the issues page](issues).

    ## Contributing -

    All are welcome to make pull requests and issues for this scenario, if you are in any doubt please ask someone in our [discord]. If you do not know lua and don't feel like learning you can always make a [feature request]. All our docs can be found [here][docs]. Please keep in mind while making code changes: +

    All are welcome to make pull requests and issues for this scenario, if you are in any doubt, please ask someone in our [discord]. If you do not know lua and don't feel like learning you can always make a [feature request]. All our docs can be found [here][docs]. Please keep in mind while making code changes:

    * New features should have the branch names: `feature/feature-name` -* New features are merged into `dev` after it has been completed. -* After a number of features have been added a release branch is made: `release/X.Y.0`; this branch should have no new features and only bug fixes or localization. -* A release is merged into `master` on the following friday in time for the the weekly reset. -* Patches may be named `patch/X.Y.Z` and fill be merged into `master` and `dev` when appropriate. +* New features are merged into `dev` after it has been completed, this can be done through a pull request. +* After a number of features have been added a release branch is made: `release/X.Y.0` +* Bug fixes and localization can be made to the release branch with a pull request rather than into dev. +* A release is merged into `master` on the following friday after it is considered stable. +* Patches may be named `patch/X.Y.Z` and will be merged into `dev` and then `master` when appropriate.

    ## Releases

    | Scenario Version* | Version Name | Factorio Version** | |---|---|---| +| [v5.10][s5.10] | Data Store Rewrite | [v0.17.71][f0.17.71] | | [v5.9][s5.9] | Control Modules and Documentation | [v0.17.63][f0.17.63] | | [v5.8][s5.8] | Home and Chat Bot | [v0.17.47][f0.17.49] | | [v5.7][s5.7] | Warp System | [v0.17.47][f0.17.47] | @@ -265,7 +268,8 @@ | [v0.1][s0.1] | First Tracked Version | [v0.14][f0.14] |

    \* Scenario patch versions have been omitted.

    \*\* Factorio versions show the version they were made for, often the minimum requirement. -

    [s5.9]: https://github.com/explosivegaming/scenario/releases/tag/5.9.0 +

    [s5.10]: https://github.com/explosivegaming/scenario/releases/tag/5.10.0 +[s5.9]: https://github.com/explosivegaming/scenario/releases/tag/5.9.0 [s5.8]: https://github.com/explosivegaming/scenario/releases/tag/5.8.0 [s5.7]: https://github.com/explosivegaming/scenario/releases/tag/5.7.0 [s5.6]: https://github.com/explosivegaming/scenario/releases/tag/5.6.0 @@ -280,7 +284,8 @@ [s2.0]: https://github.com/explosivegaming/scenario/releases/tag/v2.0 [s1.0]: https://github.com/explosivegaming/scenario/releases/tag/v1.0 [s0.1]: https://github.com/explosivegaming/scenario/releases/tag/v0.1 -

    [f0.17.63]: https://wiki.factorio.com/Version_history/0.17.0#0.17.63 +

    [f0.17.71]: https://wiki.factorio.com/Version_history/0.17.0#0.17.71 +[f0.17.63]: https://wiki.factorio.com/Version_history/0.17.0#0.17.63 [f0.17.49]: https://wiki.factorio.com/Version_history/0.17.0#0.17.49 [f0.17.47]: https://wiki.factorio.com/Version_history/0.17.0#0.17.47 [f0.17.44]: https://wiki.factorio.com/Version_history/0.17.0#0.17.44 @@ -333,7 +338,7 @@ generated by LDoc

    diff --git a/expcore/gui.lua b/expcore/gui.lua index 82257d43..eaa22047 100644 --- a/expcore/gui.lua +++ b/expcore/gui.lua @@ -1,284 +1 @@ ---[[-- Core Module - Gui - - This file is used to require all the different elements of the gui module - - each module has an outline here but for more details see their separate files in ./gui - - please read the files for more documentation that cant be shown here - - please note there is a rework planned but not started - @core Gui - @alias Gui -]] - -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core - ---[[ - Core - - Gui.new_define(prototype) --- Used internally to create new element defines from a class prototype - Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to - - Gui.categorize_by_player(element) --- A categorize function to be used with add_store, each player has their own value - Gui.categorize_by_force(element) --- A categorize function to be used with add_store, each force has its own value - Gui.categorize_by_surface(element) --- A categorize function to be used with add_store, each surface has its own value - - Gui.toggle_enabled(element) --- Will toggle the enabled state of an element - Gui.toggle_visible(element) --- Will toggle the visibility of an element - Gui.set_padding(element,up,down,left,right) --- Sets the padding for a gui element - Gui.set_padding_style(style,up,down,left,right) --- Sets the padding for a gui style - Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into - Gui.destroy_if_valid(element) --- Destroys an element but tests for it being present and valid first - Gui.create_scroll_table(element,table_size,maximal_height,name) --- Creates a scroll area with a table inside, table can be any size - Gui.create_header(element,caption,tooltip,right_align,name) --- Creates a header section with a label and button area - - Prototype Constructor - - Constructor.event(event_name) --- Creates a new function to add functions to an event handler - Constructor.extend(new_prototype) --- Extents a prototype with the base functions of all gui prototypes, no metatables - Constructor.store(sync,callback) --- Creates a new function which adds a store to a gui define - Constructor.setter(value_type,key,second_key) --- Creates a setter function that checks the type when a value is set - - Base Prototype - - Prototype:uid() --- Gets the uid for the element define - Prototype:debug_name(value) --- Sets a debug alias for the define - Prototype:set_caption(value) --- Sets the caption for the element define - Prototype:set_tooltip(value) --- Sets the tooltip for the element define - Prototype:set_style(style,callback) --- Sets the style for the element define - Prototype:set_embedded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function - - Prototype:set_pre_authenticator --- Sets an authenticator that blocks the draw function if check fails - Prototype:set_post_authenticator --- Sets an authenticator that disables the element if check fails - - Prototype:raise_event(event_name,...) --- Raises a custom event for this define, any number of params can be given - Prototype:draw_to(element,...) --- The main function for defines, when called will draw an instance of this define to the given element - - Prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used - Prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used - Prototype:clear_store(category) --- Sets the value in this elements store to nil, category needed if categorize function used -]] - -local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances -Gui.new_instance_group = Instances.registers -Gui.get_instances = Instances.get_elements -Gui.add_instance = Instances.get_elements -Gui.update_instances = Instances.apply_to_elements -Gui.classes.instances = Instances ---[[ - Instances.has_categories(name) --- Returns if a instance group has a categorise function; must be registered - Instances.is_registered(name) --- Returns if the given name is a registered instance group - Instances.register(name,categorise) --- Registers the name of an instance group to allow for storing element instances - - Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered - Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered - Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid - - Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered - Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered -]] - -local Button = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons -Gui.new_button = Button.new_button -Gui.classes.button = Button ---[[ - Button.new_button(name) --- Creates a new button element define - - Button._prototype:on_click(player,element) --- Registers a handler for when the button is clicked - Button._prototype:on_left_click(player,element) --- Registers a handler for when the button is clicked with the left mouse button - Button._prototype:on_right_click(player,element) --- Registers a handler for when the button is clicked with the right mouse button - - Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite) --- Adds sprites to a button making it a sprite button - Button._prototype:set_click_filter(filter,...) --- Adds a click / mouse button filter to the button - Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button -]] - -local Checkbox = require 'expcore.gui.elements.checkbox' --- @dep expcore.gui.elements.checkbox -Gui.new_checkbox = Checkbox.new_checkbox -Gui.new_radiobutton = Checkbox.new_radiobutton -Gui.new_radiobutton_option_set = Checkbox.new_option_set -Gui.draw_option_set = Checkbox.draw_option_set -Gui.classes.checkbox = Checkbox ---[[ - Checkbox.new_checkbox(name) --- Creates a new checkbox element define - Checkbox._prototype_checkbox:on_element_update(callback) --- Registers a handler for when an element instance updates - Checkbox._prototype_checkbox:on_store_update(callback) --- Registers a handler for when the stored value updates - - Checkbox.new_radiobutton(name) --- Creates a new radiobutton element define - Checkbox._prototype_radiobutton:on_element_update(callback) --- Registers a handler for when an element instance updates - Checkbox._prototype_radiobutton:on_store_update(callback) --- Registers a handler for when the stored value updates - Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) --- Adds this radiobutton to be an option in the given option set (only one can be true at a time) - - Checkbox.new_option_set(callback,categorize) --- Registers a new option set that can be linked to radiobuttons (only one can be true at a time) - Checkbox.draw_option_set(name,element) --- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work) - - Checkbox.reset_radiobutton(element,exclude,recursive) --- Sets all radiobuttons in a element to false (unless excluded) and can act recursively -]] - -local Dropdown = require 'expcore.gui.elements.dropdown' --- @dep expcore.gui.elements.dropdown -Gui.new_dropdown = Dropdown.new_dropdown -Gui.new_list_box = Dropdown.new_list_box -Gui.classes.dropdown = Dropdown ---[[ - Dropdown.new_dropdown(name) --- Creates a new dropdown element define - Dropdown.new_list_box(name) --- Creates a new list box element define - - Dropdown._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - Dropdown._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - Dropdown._prototype:new_static_options(options,...) --- Adds new static options to the dropdown which will trigger the general callback - Dropdown._prototype:new_dynamic_options(callback) --- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options) - Dropdown._prototype:add_option_callback(option,callback) --- Adds a case specific callback which will only run when that option is selected (general case still triggered) - - Dropdown.select_value(element,value) --- Selects the option from a dropdown or list box given the value rather than key - Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index -]] - -local Slider = require 'expcore.gui.elements.slider' --- @dep expcore.gui.elements.slider -Gui.new_slider = Slider.new_slider -Gui.classes.slider = Slider ---[[ - Slider.new_slider(name) --- Creates a new slider element define - - Slider._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - Slider._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - Slider._prototype:set_range(min,max) --- Sets the range of a slider, if not used will use default values for a slider - Slider._prototype:draw_label(element) --- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player - Slider._prototype:enable_auto_draw_label(state) --- Enables auto draw of the label, the label will share the same parent element as the slider -]] - -local Text = require 'expcore.gui.elements.text' --- @dep expcore.gui.elements.text -Gui.new_text_filed = Text.new_text_field -Gui.new_text_box = Text.new_text_box -Gui.classes.text = Text ---[[ - Text.new_text_field(name) --- Creates a new text field element define - Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates - Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates - - Text.new_text_box(name) --- Creates a new text box element define - Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates - Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates - Text._prototype_box:set_selectable(state) --- Sets the text box to be selectable - Text._prototype_box:set_word_wrap(state) --- Sets the text box to have word wrap - Text._prototype_box:set_read_only(state) --- Sets the text box to be read only -]] - -local ElemButton = require 'expcore.gui.elements.elem-button' --- @dep expcore.gui.elements.elem-button -Gui.new_elem_button = ElemButton.new_elem_button -Gui.classes.elem_button = ElemButton ---[[ - ElemButton.new_elem_button(name) --- Creates a new elem button element define - - ElemButton._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - ElemButton._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - ElemButton._prototype:set_type(type) --- Sets the type of the elem button, the type is required so this must be called at least once - ElemButton._prototype:set_default(value) --- Sets the default value for the elem button, this may be a function or a string -]] - -local ProgressBar = require 'expcore.gui.elements.progress-bar' --- @dep expcore.gui.elements.progress-bar -Gui.new_progressbar = ProgressBar.new_progressbar -Gui.set_progressbar_maximum = ProgressBar.set_maximum -Gui.increment_progressbar = ProgressBar.increment -Gui.decrement_progressbar = ProgressBar.decrement -Gui.classes.progressbar = ProgressBar ---[[ - ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar - ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented - ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decreased - - ProgressBar.new_progressbar(name) --- Creates a new progressbar element define - ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar - ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0 - ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar - ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store - ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar - ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store - ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store - ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0 - - ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element completes (hits 0 or 1) - ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1) - ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggers, can filter which elements are incremented - ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggers, can filter which elements are decremented -]] - -local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar -Gui.new_toolbar_button = Toolbar.new_button -Gui.add_button_to_toolbar = Toolbar.add_button -Gui.update_toolbar = Toolbar.update -Gui.classes.toolbar = Toolbar ---[[ - Toolbar.new_button(name) --- Adds a new button to the toolbar - Toolbar.add_button(button) --- Adds an existing buttton to the toolbar - Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return -]] - -local LeftFrames = require 'expcore.gui.concepts.left' --- @dep expcore.gui.concepts.left -Gui.get_left_frame_flow = LeftFrames.get_flow -Gui.toggle_left_frame = LeftFrames.toggle_frame -Gui.new_left_frame = LeftFrames.new_frame -Gui.classes.left_frames = LeftFrames ---[[ - LeftFrames.get_flow(player) --- Gets the left frame flow for a player - LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name - LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button - LeftFrames.toggle_frame(name,player,state) --- Toggles the visibility of a left frame, or sets its visibility state - - LeftFrames.new_frame(permission_name) --- Creates a new left frame define - LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean - LeftFrames._prototype:set_direction(direction) --- Sets the direction of the frame, either vertical or horizontal - LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow - LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible - LeftFrames._prototype:toggle(player) --- Toggles the visibility of the left frame - - LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw - LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update - LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame - LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw - - LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame - LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it - LeftFrames._prototype:on_player_toggle(player,frame) --- Triggered when the player toggle the left frame - LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add -]] - -local CenterFrames = require 'expcore.gui.concepts.center' --- @dep expcore.gui.concepts.center -Gui.get_center_flow = CenterFrames.get_flow -Gui.toggle_center_frame = CenterFrames.toggle_frame -Gui.draw_center_frame = CenterFrames.draw_frame -Gui.redraw_center_frame = CenterFrames.redraw_frames -Gui.new_center_frame = CenterFrames.new_frame -Gui.classes.center_frames = CenterFrames ---[[ - CenterFrames.get_flow(player) --- Gets the center flow for a player - CenterFrames.clear_flow(player) --- Clears the center flow for a player - CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing - CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destroy it and redraw - CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open - - CenterFrames.new_frame(permission_name) --- Sets the frame to be the current active gui when opened and closes all other frames - CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame - CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames - CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame) - CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame) - CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it - CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add -]] - -local PopupFrames = require 'expcore.gui.concepts.popups' --- @dep expcore.gui.concepts.popups -Gui.get_popup_flow = PopupFrames.get_flow -Gui.open_popup = PopupFrames.open -Gui.new_popup = PopupFrames.new_popup -Gui.classes.popup_frames = PopupFrames ---[[ - PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames - PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function - - PopupFrames.close_progress --- Progress bar which when depleted will close the popup frame - PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out - - PopupFrames.new_popup(name) --- Creates a new popup frame define - PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open - PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function -]] - -return Gui \ No newline at end of file +return require 'expcore.gui.require' \ No newline at end of file diff --git a/expcore/gui/concepts/center.lua b/expcore/gui/concepts/center.lua deleted file mode 100644 index ffbc3f9f..00000000 --- a/expcore/gui/concepts/center.lua +++ /dev/null @@ -1,198 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Center Guis. --- Gui structure define for center gui frames --- @section center - ---[[ ->>>> Functions - CenterFrames.get_flow(player) --- Gets the center flow for a player - CenterFrames.clear_flow(player) --- Clears the center flow for a player - CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing - CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destroy it and redraw - CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open - - CenterFrames.new_frame(permission_name) --- Sets the frame to be the current active gui when opened and closes all other frames - CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame - CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames - CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame) - CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame) - CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it - CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar -local Game = require 'utils.game' --- @dep utils.game - -local CenterFrames = { - _prototype = Prototype.extend{ - on_creation = Prototype.event - } -} - ---- Gets the center flow for a player --- @tparam LuaPlayer player the player to get the flow for --- @treturn LuaGuiElement the center flow -function CenterFrames.get_flow(player) - player = Game.get_player_from_any(player) - return player.gui.center -end - ---- Clears the center flow for a player --- @tparam LuaPlayer player the player to clear the flow for -function CenterFrames.clear_flow(player) - local flow = CenterFrames.get_flow(player) - flow.clear() -end - ---- Draws the center frame for a player, if already open then will do nothing --- @tparam LuaPlayer player the player that will have the frame drawn --- @tparam string name the name of the hui that will drawn --- @treturn LuaGuiElement the new frame that was made -function CenterFrames.draw_frame(player,name) - local define = Gui.get_define(name,true) - if define then - return define:draw_frame(player) - end -end - ---- Draws the center frame for a player, if already open then will destroy it and redraw --- @tparam LuaPlayer player the player that will have the frame drawn --- @tparam string name the name of the hui that will drawn --- @treturn LuaGuiElement the new frame that was made -function CenterFrames.redraw_frame(player,name) - local define = Gui.get_define(name,true) - if define then - return define:draw_frame(player) - end -end - ---- Toggles if the frame is currently open or not, will open if closed and close if open --- @tparam LuaPlayer player the player that will have the frame toggled --- @tparam string name the name of the hui that will be toggled --- @tparam[opt] boolean state when set will force a state for the frame --- @treturn boolean if the frame if no open or closed -function CenterFrames.toggle_frame(player,name,state) - local define = Gui.get_define(name,true) - if define then - if state == true then - define:draw_frame(player) - return true - elseif state == false then - local flow = CenterFrames.get_flow(player) - if flow[define.name..'-frame'] then - flow[define.name..'-frame'].destroy() - end - return false - else - return define:toggle_frame(player) - end - end -end - ---- Creates a new center frame define --- @tparam string permission_name the name that can be used with the permission system --- @treturn table the new center frame define -function CenterFrames.new_frame(permission_name) - local self = Toolbar.new_button(permission_name) - - self:on_click(function(player,element) - self:toggle_frame(player) - end) - - local mt = getmetatable(self) - mt.__index = CenterFrames._prototype - mt.__call = self.event_handler - - Gui.on_custom_close(self.name..'-frame',function(event) - local element = event.element - if element and element.valid then element.destroy() end - end) - - return self -end - ---- Sets the frame to be the current active gui when opened and closes all other frames --- @tparam[opt=true] boolean state when true will auto close other frames and set this frame as player.opened -function CenterFrames._prototype:set_auto_focus(state) - if state == false then - self.auto_focus = false - else - self.auto_focus = true - end -end - ---- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame) --- @tparam LuaPlayer player the player to draw the frame for --- @treturn LuaGuiElement the new frame that was drawn -function CenterFrames._prototype:draw_frame(player) - player = Game.get_player_from_any(player) - local flow = CenterFrames.get_flow(player) - - if flow[self.name..'-frame'] then - return flow[self.name..'-frame'] - end - - if self.auto_focus then - flow.clear() - end - - local frame = flow.add{ - type='frame', - name=self.name..'-frame' - } - - if self.auto_focus then - player.opened = frame - end - - self:raise_event('on_creation',player,frame) - - return frame -end - ---- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame) --- @tparam LuaPlayer player the player to draw the frame for --- @treturn LuaGuiElement the new frame that was drawn -function CenterFrames._prototype:redraw_frame(player) - player = Game.get_player_from_any(player) - local flow = CenterFrames.get_flow(player) - - if flow[self.name..'-frame'] then - flow[self.name..'-frame'].destroy() - end - - return self:draw_frame(player) -end - ---- Toggles if the frame is open, if open it will close it and if closed it will open it --- @tparam LuaPlayer player the player to draw the frame for --- @treturn boolean with the gui frame is now open -function CenterFrames._prototype:toggle_frame(player) - player = Game.get_player_from_any(player) - local flow = CenterFrames.get_flow(player) - - if flow[self.name..'-frame'] then - flow[self.name..'-frame'].destroy() - return false - else - self:draw_frame(player) - return true - end -end - ---- Creates an event handler that will trigger one of its functions, use with Event.add --- @tparam[opt=update] string action the action to take on this event -function CenterFrames._prototype:event_handler(action) - action = action or 'update' - return function(event) - local player = Game.get_player_by_index(event.player_index) - self[action](self,player) - end -end - -return CenterFrames \ No newline at end of file diff --git a/expcore/gui/concepts/left.lua b/expcore/gui/concepts/left.lua deleted file mode 100644 index e827f36a..00000000 --- a/expcore/gui/concepts/left.lua +++ /dev/null @@ -1,322 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Left Guis. --- Gui structure define for left frames --- @section left - ---[[ ->>>> Example formating - - -- first we add config that relates to the button on the toolbar, all normal button functions are present - local left_frame = - Gui.new_left_frame('test-left-frame') - :set_caption('Test Left Gui') - :set_post_authenticator(function(player,button_name) - return global.show_test_gui - end) - - -- then we add the config for the left frame, on_draw should draw the gui from an empty frame, on_update should take a frame from on_draw on edit it - :set_open_by_default() - :on_draw(function(_player,frame) - for _,player in pairs(game.connected_players) do - frame.add{ - type='label', - caption=player.name - } - end - end) - - -- now we can use the action factory to call events on the gui, actions are: 'update', 'update_all', 'redraw', 'redraw_all' - Event.add(defines.events.on_player_joined_game,left_frame 'update_all') - Event.add(defines.events.on_player_left_game,left_frame 'update_all') - ->>>> Functions - LeftFrames.get_flow(player) --- Gets the left frame flow for a player - LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name - LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button - LeftFrames.toggle_frame(name,player,state) --- Toggles the visibility of a left frame, or sets its visibility state - - LeftFrames.new_frame(permission_name) --- Creates a new left frame define - LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean - LeftFrames._prototype:set_direction(direction) --- Sets the direction of the frame, either vertical or horizontal - LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow - LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible - LeftFrames._prototype:toggle(player) --- Toggles the visibility of the left frame - - LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw - LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update - LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame - LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw - - LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame - LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it - LeftFrames._prototype:on_player_toggle(player,frame) --- Is triggered when the player presses the toggle button - LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar -local Buttons = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons -local mod_gui = require 'mod-gui' --- @dep mod-gui -local Game = require 'utils.game' --- @dep utils.game -local Event = require 'utils.event' --- @dep utils.event - -local LeftFrames = { - frames={}, - _prototype=Prototype.extend{ - on_creation = Prototype.event, - on_update = Prototype.event, - on_player_toggle = Prototype.event - } -} -setmetatable(LeftFrames._prototype, { - __index = Buttons._prototype -}) - ---- Gets the left frame flow for a player --- @tparam LuaPlayer player the player to get the flow of --- @treturn LuaGuiElement the left frame flow for the player -function LeftFrames.get_flow(player) - player = Game.get_player_from_any(player) - return mod_gui.get_frame_flow(player) -end - ---- Gets one frame from the left flow by its name --- @tparam string name the name of the gui frame to get --- @tparam LuaPlayer player the player to get the frame of --- @treturn LuaGuiElement the frame in the left frame flow with that name -function LeftFrames.get_frame(name,player) - local define = LeftFrames.frames[name] - if not define then - return error('Left Frame '..name..' is not defined.',2) - end - return define:get_frame(player) -end - ---- Gets all open frames for a player, if non are open it will remove the close all button --- @tparam LuaPlayer player the player to get the flow of --- @treturn table contains all the open (and registered) frames for the player -function LeftFrames.get_open(player) - local open = {} - local flow = LeftFrames.get_flow(player) - - for _,define in pairs(LeftFrames.frames) do - if define:is_open(player) then - table.insert(open,define) - end - end - - flow[LeftFrames.toggle_button.name].visible = #open ~= 0 - - return open -end - ---- Toggles the visibility of a left frame, or sets its visibility state --- @tparam string name the name of the gui frame to toggle --- @tparam LuaPlayer player the player to get the frame of --- @tparam[opt] boolean state when given will be the state that the visibility is set to --- @treturn boolean the new state of the visibility -function LeftFrames.toggle_frame(name,player,state) - local define = LeftFrames.frames[name] - if not define then - return error('Left Frame '..name..' is not defined.',2) - end - - local frame = LeftFrames.get_frame(name,player) - if state ~= nil then - frame.visible = state - else - Gui.toggle_visible(frame) - end - - LeftFrames.get_open(player) - - return frame.visible -end - ---- Creates a new left frame define --- @tparam string permission_name the name that can be used with the permission system --- @treturn table the new left frame define -function LeftFrames.new_frame(permission_name) - local self = Toolbar.new_button(permission_name) - - local mt = getmetatable(self) - mt.__index = LeftFrames._prototype - mt.__call = self.event_handler - - self:on_click(function(player,_element) - local visible = self:toggle(player) - local frame = self:get_frame(player) - self:raise_event('on_player_toggle',player,frame,visible) - end) - - LeftFrames.frames[self.name] = self - - return self -end - ---- Sets if the frame is visible when a player joins, can also be a function to return a boolean --- @tparam[opt=true] ?boolean|function state the default state of the visibility, can be a function --- state param - player LuaPlayer - the player that has joined the game --- state param - define_name string - the define name for the frame --- state return - boolean - false will hide the frame -function LeftFrames._prototype:set_open_by_default(state) - if state == false then - self.open_by_default = false - elseif state == nil then - self.open_by_default = true - else - self.open_by_default = state - end - return self -end - ---- Sets the direction of the frame, either vertical or horizontal --- @tparam string direction the direction to have the elements be added to the frame -function LeftFrames._prototype:set_direction(direction) - self.direction = direction - return self -end - ---- Creates the gui for the first time, used internally --- @tparam LuaPlayer player the player to draw the frame to --- @treturn LuaGuiElement the frame that was made -function LeftFrames._prototype:_internal_draw(player) - local flow = LeftFrames.get_flow(player) - local frame = flow.add{ - type='frame', - name=self.name..'-frame', - direction=self.direction - } - - self:raise_event('on_creation',player,frame) - - if not self.open_by_default then - frame.visible = false - elseif type(self.open_by_default) == 'function' then - if not self.open_by_default(player,self.name) then - frame.visible = false - end - end - - if not Toolbar.allowed(player,self.name) then - frame.visible = false - end - - return frame -end - ---- Gets the frame for this define from the left frame flow --- @tparam LuaPlayer player the player to get the frame of --- @treturn LuaGuiElement the frame in the left frame flow for this define -function LeftFrames._prototype:get_frame(player) - local flow = LeftFrames.get_flow(player) - if flow[self.name..'-frame'] and flow[self.name..'-frame'].valid then - return flow[self.name..'-frame'] - else - return self:_internal_draw(player) - end -end - ---- Returns if the player currently has this define visible --- @tparam LuaPlayer player the player to get the frame of --- @treturn boolean true if it is open/visible -function LeftFrames._prototype:is_open(player) - local frame = self:get_frame(player) - return frame and frame.visible or false -end - ---- Toggles the visibility of the left frame --- @tparam LuaPlayer player the player to toggle the frame of --- @treturn boolean the new state of the visibility -function LeftFrames._prototype:toggle(player) - local frame = self:get_frame(player) - Gui.toggle_visible(frame) - LeftFrames.get_open(player) - return frame.visible -end - ---- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw --- @tparam LuaPlayer player the player to update the frame of -function LeftFrames._prototype:update(player) - local frame = self:get_frame(player) - if self:raise_event('on_update',player,frame) == 0 then - frame.clear() - self:raise_event('on_creation',player,frame) - end -end - ---- Updates the frame for all players, see update --- @tparam[opt=false] boolean update_offline when true will update the frame for offline players -function LeftFrames._prototype:update_all(update_offline) - local players = update_offline == true and game.players or game.connected_players - for _,player in pairs(players) do - self:update(player) - end -end - ---- Redraws the frame by calling on_draw, will always clear the frame --- @tparam LuaPlayer player the player to update the frame of -function LeftFrames._prototype:redraw(player) - local frame = self:get_frame(player) - frame.clear() - self:raise_event('on_creation',player,frame) -end - ---- Redraws the frame for all players, see redraw --- @tparam[opt=false] boolean update_offline when true will update the frame for offline players -function LeftFrames._prototype:redraw_all(update_offline) - local players = update_offline == true and game.players or game.connected_players - for _,player in pairs(players) do - self:redraw(player) - end -end - ---- Creates an event handler that will trigger one of its functions, use with Event.add --- @tparam[opt=update] string action the action to take on this event -function LeftFrames._prototype:event_handler(action) - action = action or 'update' - return function(event) - local player - if event and event.player_index then - player = Game.get_player_by_index(event.player_index) - end - self[action](self,player) - end -end - -LeftFrames.toggle_button = -Buttons.new_button() -:set_tooltip{'expcore-gui.left-button-tooltip'} -:set_caption('<') -:on_click(function(player,element) - for _,define in pairs(LeftFrames.frames) do - local frame = LeftFrames.get_frame(define.name,player) - frame.visible = false - define:raise_event('on_player_toggle',player,frame,false) - end - element.visible = false -end) - -Event.add(defines.events.on_player_created,function(event) - local player = Game.get_player_by_index(event.player_index) - local flow = LeftFrames.get_flow(player) - - local close_button = LeftFrames.toggle_button(flow) - Gui.set_padding(close_button) - local style = close_button.style - style.width = 18 - style.height = 36 - style.font = 'default-small-bold' - - for _,define in pairs(LeftFrames.frames) do - define:_internal_draw(player) - end - - LeftFrames.get_open(player) -end) - -return LeftFrames \ No newline at end of file diff --git a/expcore/gui/concepts/popups.lua b/expcore/gui/concepts/popups.lua deleted file mode 100644 index bda932b3..00000000 --- a/expcore/gui/concepts/popups.lua +++ /dev/null @@ -1,230 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Popups. --- Gui structure define for popup gui --- @section popups - ---[[ ->>>> Functions - PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames - PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function - - PopupFrames.close_progress --- Progress bar which when depleted will close the popup frame - PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out - - PopupFrames.new_popup(name) --- Creates a new popup frame define - PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open - PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Game = require 'utils.game' --- @dep utils.game -local Event = require 'utils.event' --- @dep utils.event -local ProgressBar = require 'expcore.gui.elements.progress-bar' --- @dep expcore.gui.elements.progress-bar -local Button = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons -local mod_gui = require 'mod-gui' --- @dep mod-gui -local Color = require 'resources.color_presets' --- @dep resources.color_presets -local Global = require 'utils.global' --- @dep utils.global - -local PopupFrames = { - paused_popups={}, - popup_flow_name = Gui.uid_name(), - main_frame_name = Gui.uid_name(), - close_frame_name = Gui.uid_name(), - _prototype = Prototype.extend{ - on_creation = Prototype.event - } -} -Global.register(PopupFrames.paused_popups,function(tbl) - PopupFrames.paused_popups = tbl -end) - ---- Sets the state of the element in the paused list, nil or true --- @tparam LuaGuiElement element the element to set the state of --- @tparam[opt] boolean state the state to set it to, true will pause the the progress bar -local function set_paused_state(element,state) - local name = element.player_index..':'..element.index - PopupFrames.paused_popups[name] = state -end - ---- Gets the state of the element in the paused list, nil or true --- @tparam LuaGuiElement element the element to get the state of -local function get_paused_state(element) - local name = element.player_index..':'..element.index - return PopupFrames.paused_popups[name] -end - ---- Gets the left flow that contains the popup frames --- @tparam LuaPlayer player the player to get the flow for --- @treturn LuaGuiElement the left flow that contains the popup frames -function PopupFrames.get_flow(player) - player = Game.get_player_from_any(player) - local flow = mod_gui.get_frame_flow(player) - return flow[PopupFrames.popup_flow_name] -end - ---- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function --- @tparam string define_name the name of the define that you want to open for the player --- @tparam LuaPlayer player the player to open the popup for --- @tparam[opt] number open_time the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default --- @tparam any ... the other params that you want to pass to your on_draw event --- @treturn LuaGuiElement the frame that was drawn, the inner gui flow which contains the content -function PopupFrames.open(define_name,player,open_time,...) - local define = Gui.get_define(define_name,true) - player = Game.get_player_from_any(player) - return define:open(player,open_time,...) -end - ---- Closes the popup, is called by progress bar and close button --- @tparam LuaGuiElement element either the progress bar or the close button -local function close_popup(element) - local frame = element.parent.parent.parent - if not frame or not frame.valid then return end - set_paused_state(element.parent[PopupFrames.close_progress:uid()]) - frame.destroy() -end - ---- Progress bar which when depleted will close the popup frame -PopupFrames.close_progress = -ProgressBar.new_progressbar() -:use_count_down() -:set_tooltip('Pause/Resume Auto-close') -:on_complete(function(player,element) - close_popup(element) -end) - ---- A button which can be used to close the gui before the timer runs out -PopupFrames.close_button = -Button.new_button() -:set_sprites('utility/close_white') -:set_tooltip('Close Popup') -:on_click(function(player,element) - close_popup(element) -end) - ---- When the progress bar is clicked it will pause its progress, or resume if previously paused -Gui.on_click(PopupFrames.close_progress:uid(),function(event) - local element = event.element - if get_paused_state(element) then - set_paused_state(element) - else - set_paused_state(element,true) - end -end) - ---- When the parent flow of the progress bar is clicked it will pause its progress, or resume if previously paused -Gui.on_click(PopupFrames.close_frame_name,function(event) - local element = event.element[PopupFrames.close_progress:uid()] - if get_paused_state(element) then - set_paused_state(element) - else - set_paused_state(element,true) - end -end) - ---- Creates a new popup frame define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new popup frame define -function PopupFrames.new_popup(name) - local self = Gui.new_define(PopupFrames._prototype,name) - self.draw_data.type = 'flow' - self.draw_data.direction = 'vertical' - - local mt = getmetatable(self) - mt.__call = function(tbl,player,open_time,...) - return tbl:open(player,open_time,...) - end - - self:on_draw(function(player,element,maximum,...) - -- main content frame - local frame = element.add{ - type='flow', - name=PopupFrames.main_frame_name - } - frame.style.horizontally_stretchable = true - - -- flow for progress bar and close button - local close_flow = element.add{ - type='flow', - name=PopupFrames.close_frame_name - } - close_flow.style.horizontally_stretchable = true - - -- progress bar, when 0 then a static full one is drawn - local progress_style - if maximum == 0 then - progress_style = close_flow.add{ - type='progressbar', - tooltip='No Auto-close', - value=1 - }.style - else - progress_style = PopupFrames.close_progress(close_flow,maximum).style - end - progress_style.top_padding = 6 - progress_style.bottom_padding = 3 - progress_style.height = 11 - progress_style.color = Color.grey - - -- close button, will close the popup when clicked - local close_button = PopupFrames.close_button(close_flow) - Gui.set_padding(close_button) - local close_button_style = close_button.style - close_button_style.width = 20 - close_button_style.height = 20 - - -- event trigger to draw the gui content - self:raise_event('on_creation',player,frame,...) - end) - - return self -end - ---- Sets the default open time for the popup, will be used if non is provided with open --- @tparam number amount the number of ticks, by default, the popup will be open for --- @treturn table the define to allow for chaining -function PopupFrames._prototype:set_default_open_time(amount) - self.default_open_time = amount - return self -end - ---- Opens this define for a player, can be given open time and any other params for the draw function --- @tparam LuaPlayer player the player to open the popup for --- @tparam[opt] number open_time the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default --- @tparam any ... the other params that you want to pass to your on_draw event --- @treturn LuaGuiElement the frame that was drawn, the inner gui flow which contains the content -function PopupFrames._prototype:open(player,open_time,...) - open_time = open_time or self.default_open_time or 0 - player = Game.get_player_from_any(player) - - local flow = PopupFrames.get_flow(player) - local frame = flow.add{ - type='frame', - style='blurry_frame' - } - - Gui.set_padding(frame,3,3,4,4) - return self:draw_to(frame,open_time,...)[PopupFrames.main_frame_name] -end - ---- When player is first created the popup flow is added to they left flow -Event.add(defines.events.on_player_created,function(event) - local player = Game.get_player_by_index(event.player_index) - local flow = mod_gui.get_frame_flow(player) - - flow.add{ - type='flow', - direction='vertical', - name=PopupFrames.popup_flow_name - } -end) - ---- Every tick any, not paused, progress bars will go down by one tick -Event.add(defines.events.on_tick,PopupFrames.close_progress:event_countdown(function(element) - return not get_paused_state(element) -end)) - -return PopupFrames \ No newline at end of file diff --git a/expcore/gui/concepts/toolbar.lua b/expcore/gui/concepts/toolbar.lua deleted file mode 100644 index 10a8d971..00000000 --- a/expcore/gui/concepts/toolbar.lua +++ /dev/null @@ -1,114 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Toolbar. --- Gui structure for the toolbar (top left) --- @section toolbar - ---[[ ->>>> Example format - -- this is the same as any other button define, this just automatically draws it - -- you can use add_button if you already defined the button - local toolbar_button = - Toolbar.new_button('print-click') - :on_click(function(player,_element) - player.print('You clicked a button!') - end) - ->>>> Functions - Toolbar.new_button(name) --- Adds a new button to the toolbar - Toolbar.add_button(button) --- Adds an existing buttton to the toolbar - Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Buttons = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons -local Roles = require 'expcore.roles' --- @dep expcore.roles -local Event = require 'utils.event' --- @dep utils.event -local Game = require 'utils.game' --- @dep utils.game -local mod_gui = require 'mod-gui' --- @dep mod-gui - -local Toolbar = { - permission_names = {}, - buttons = {} -} - -function Toolbar.allowed(player,define_name) - local permission_name = Toolbar.permission_names[define_name] or define_name - return Roles.player_allowed(player,permission_name) -end - -function Toolbar.permission_alias(define_name,permission_name) - Toolbar.permission_names[define_name] = permission_name -end - ---- Adds a new button to the toolbar --- @tparam[opt] string name when given allows an alias to the button for the permission system --- @treturn table the button define -function Toolbar.new_button(name) - local button = - Buttons.new_button() - :set_post_authenticator(Toolbar.allowed) - :set_style(mod_gui.button_style,function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - end) - Toolbar.add_button(button) - Toolbar.permission_alias(button.name,name) - return button -end - ---- Adds an existing buttton to the toolbar --- @tparam table button the button define for the button to be added -function Toolbar.add_button(button) - table.insert(Toolbar.buttons,button) - Gui.allow_player_to_toggle_top_element_visibility(button.name) - Gui.on_player_show_top(button.name,function(event) - if not button.post_authenticator(event.player,button.name) then - event.element.visible = false - end - end) - if not button.post_authenticator then - button:set_post_authenticator(function() return true end) - end -end - ---- Updates the player's toolbar with an new buttons or expected change in auth return --- @tparam LuaPlayer player the player to update the toolbar for -function Toolbar.update(player) - local top = Gui.get_top_element_flow(player) - if not top then return end - local visible = top[Gui.top_toggle_button_name].caption == '<' - for _,button in pairs(Toolbar.buttons) do - local element - if top[button.name] then element = top[button.name] - else element = button:draw_to(top) end - if button.post_authenticator(player,button.name) then - element.visible = visible - element.enabled = true - else - element.visible = false - element.enabled = false - end - end -end - ---- When there is a new player they will have the toolbar update -Event.add(defines.events.on_player_created,function(event) - local player = Game.get_player_by_index(event.player_index) - Toolbar.update(player) -end) - ---- When a player gets a new role they will have the toolbar updated -Event.add(Roles.events.on_role_assigned,function(event) - local player = Game.get_player_by_index(event.player_index) - Toolbar.update(player) -end) - ---- When a player loses a role they will have the toolbar updated -Event.add(Roles.events.on_role_unassigned,function(event) - local player = Game.get_player_by_index(event.player_index) - Toolbar.update(player) -end) - -return Toolbar \ No newline at end of file diff --git a/expcore/gui/core.lua b/expcore/gui/core.lua deleted file mode 100644 index 1fd93480..00000000 --- a/expcore/gui/core.lua +++ /dev/null @@ -1,368 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Core. --- Core gui file for making element defines and element classes (use require 'expcore.gui') --- see utils.gui for event handlering --- see expcore.gui.test for examples for element defines --- @section core - ---[[ ->>>> 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. - ->>>> Basic prototype functions (see expcore.gui.prototype) - Using a class defination you can create a new element dinfation in our examples we will be using the checkbox. - - local checkbox_example = Gui.new_checkbox() - - Although all class definations are stored in Gui.classes the main function used to make new element defination are - made aviable in the top level gui module. All functions which return a new element defination will accept a name argument - which is a name which is used while debuging and is not required to be used (has not been used in examples) - - Every element define will accept a caption and tooltip (although some may not show) and to do this you would use the two - set function provided for the element defines: - - checkbox_example:set_caption('Example Checkbox') - checkbox_example:set_tooltip('Example checkbox') - - Each element define can have event handlers set, for our example checkbox we only have access to on_change which will trigger - when the state of the checkbox changes; if we want to assign handlers using the utils.gui methods then we can get the uid by calling - the uid function on the element define; however, each element can only have one handler (of each event) so it is not possible to use - Gui.on_checked_state_changed and on_change at the same time in our example. - - checkbox_example:on_change(function(player,element,value) - player.print('Example checkbox is now: '..tostring(value)) - end) - - local checkbox_example_uid = checkbox_example:uid() - Gui.on_click(checkbox_example_uid,function(event) - event.player.print('You clicked the example checkbox!') - end) - - Finally you will want to draw your element defines for which you can call deirectly on the deinfe or use Gui.draw to do; when Gui.draw is - used it can be given either the element define, the define's uid or the debug name of the define (if set): - - checkbox_example:draw_to(parent_element) - Gui.draw(checkbox_example_uid,parent_element) - ->>>> Using authenticators with draw - When an element is drawn to its parent it can always be used but if you want to limit who can use it then you can use an authenticator. There - are two types which can be used: post and pre; using a pre authenticator will mean that the draw function is stoped before the element is added - to the parent element while using a post authenticator will draw the element to the parent but will disable the element from interaction. Both may - be used if you have use for such. - - -- unless global.checkbox_example_allow_pre_auth is true then the checkbox will not be drawn - checkbox_example:set_pre_authenticator(function(player,define_name) - player.print('Example checkbox pre auth callback ran') - return global.checkbox_example_allow_pre_auth - end) - - -- unless global.checkbox_example_allow_post_auth is true then the checkbox will be drawn but deactiveated (provided pre auth returns true) - checkbox_example:set_post_authenticator(function(player,define_name) - player.print('Example checkbox pre auth callback ran') - return global.checkbox_example_allow_post_auth - end) - ->>>> Using store (see expcore.gui.prototype and expcore.gui.instances) - A powerful assept of this gui system is allowing an automatic store for the state of a gui element, this means that when a gui is closed and re-opened - the elements which have a store will retain they value even if the element was previously destroied. The store is not limited to only per player and can - be catergorised by any method you want such as one that is shared between all players or by all players on a force. Using a method that is not limited to - one player means that when one player changes the state of the element it will be automaticlly updated for all other player (even if the element is already drawn) - and so this is a powerful and easy way to sync gui elements. - - -- note the example below is the same as checkbox_example:add_store(Gui.categorize_by_player) - checkbox_example:add_store(function(element) - local player = Game.get_player_by_index(element.player_index) - return player.force.name - end) - - Of course this tool is not limited to only player interactions; the current satate of a define can be gotten using a number of methods and the value can - even be updated by the script and have all instances of the element define be updated. When you use a category then we must give a category to the get - and set functions; in our case we used Gui.categorize_by_player which uses the player's name as the category which is why 'Cooldude2606' is given as a argument, - if we did not set a function for add_store then all instances for all players have the same value and so a category is not required. - - checkbox_example:get_store('Cooldude2606') - Gui.get_store(name,'Cooldude2606') - - checkbox_example:set_store('Cooldude2606',true) - Gui.set_store(name,'Cooldude2606',true) - - These methods use the Store module which means that if you have the need to access these sotre location (for example if you want to add a watch function) then - you can get the store location of any define using checkbox_example.store - - Important note about event handlers: when the store is updated it will also trigger the event handlers (such as on_element_update) for that define but only - for the valid instances of the define which means if a player does not have the element drawn on a gui then it will not trigger the events; if you want a - trigger for all updates then you can use on_store_update however you will be required to parse the category which may or may not be a - player name (depends what store categorize function you use) - ->>>> Example formating - - local checkbox_example = - Gui.new_checkbox() - :set_caption('Example Checkbox') - :set_tooltip('Example checkbox') - :add_store(Gui.categorize_by_player) - :on_element_update(function(player,element,value) - player.print('Example checkbox is now: '..tostring(value)) - end) - ->>>> Functions - Gui.new_define(prototype) --- Used internally to create new element defines from a class prototype - Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to - - Gui.categorize_by_player(element) --- A categorize function to be used with add_store, each player has their own value - Gui.categorize_by_force(element) --- A categorize function to be used with add_store, each force has its own value - Gui.categorize_by_surface(element) --- A categorize function to be used with add_store, each surface has its own value - - Gui.toggle_enabled(element) --- Will toggle the enabled state of an element - Gui.toggle_visible(element) --- Will toggle the visiblity of an element - Gui.set_padding(element,up,down,left,right) --- Sets the padding for a gui element - Gui.set_padding_style(style,up,down,left,right) --- Sets the padding for a gui style - Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into - Gui.destroy_if_valid(element) --- Destroies an element but tests for it being present and valid first - Gui.create_scroll_table(element,table_size,maximal_height,name) --- Creates a scroll area with a table inside, table can be any size - Gui.create_header(element,caption,tooltip,right_align,name) --- Creates a header section with a label and button area -]] -local Gui = require 'utils.gui' --- @dep utils.gui -local Game = require 'utils.game' --- @dep utils.game - -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 - ---- Used to create new element defines from a class prototype, please use the own given by the class --- @tparam table prototype the class prototype that will be used for the element define --- @tparam[opt] string debug_name the name that you want to see while debuging --- @treturn table the new element define with all functions accessed via __index metamethod -function Gui.new_define(prototype,debug_name) - local name = Gui.uid_name() - local define = setmetatable({ - debug_name = debug_name, - name = name, - events = {}, - draw_data = { - name = name - } - },{ - __index = prototype, - __call = function(self,...) - return self:draw_to(...) - end - }) - Gui.defines[define.name] = define - return define -end - ---- Gets an element define give the uid, debug name or a copy of the element define --- @tparam ?string|table name the uid, debug name or define for the element define to get --- @tparam[opt] boolean internal when true the error trace is one level higher (used internally) --- @treturn table the element define that was found or an error -function Gui.get_define(name,internal) - if type(name) == 'table' then - if name.name and Gui.defines[name.name] then - return Gui.defines[name.name] - end - end - - local define = Gui.defines[name] - - if not define and Gui.names[name] then - return Gui.defines[Gui.names[name]] - - elseif not define then - return error('Invalid name for element define, name not found.',internal and 3 or 2) or nil - - end - - return define -end - ---- A categorize function to be used with add_store, each player has their own value --- @tparam LuaGuiElement element the element that will be converted to a string --- @treturn string the player's name who owns this element -function Gui.categorize_by_player(element) - local player = Game.get_player_by_index(element.player_index) - return player.name -end - ---- A categorize function to be used with add_store, each force has its own value --- @tparam LuaGuiElement element the element that will be converted to a string --- @treturn string the player's force name who owns this element -function Gui.categorize_by_force(element) - local player = Game.get_player_by_index(element.player_index) - return player.force.name -end - ---- A categorize function to be used with add_store, each surface has its own value --- @tparam LuaGuiElement element the element that will be converted to a string --- @treturn string the player's surface name who owns this element -function Gui.categorize_by_surface(element) - local player = Game.get_player_by_index(element.player_index) - return player.surface.name -end - ---- Draws a copy of the element define to the parent element, see draw_to --- @tparam ?string|table name the uid, debug name or define for the element define to draw --- @tparam LuaGuiEelement element the parent element that it the define will be drawn to --- @treturn LuaGuiElement the new element that was created -function Gui.draw(name,element,...) - local define = Gui.get_define(name,true) - return define:draw_to(element,...) -end - ---- Will toggle the enabled state of an element --- @tparam LuaGuiElement element the gui element to toggle --- @treturn boolean the new state that the element has -function Gui.toggle_enabled(element) - if not element or not element.valid then return end - if not element.enabled then - element.enabled = true - else - element.enabled = false - end - return element.enabled -end - ---- Will toggle the visiblity of an element --- @tparam LuaGuiElement element the gui element to toggle --- @treturn boolean the new state that the element has -function Gui.toggle_visible(element) - if not element or not element.valid then return end - if not element.visible then - element.visible = true - else - element.visible = false - end - return element.visible -end - ---- Sets the padding for a gui element --- @tparam LuaGuiElement element the element to set the padding for --- @tparam[opt=0] number up the amount of padding on the top --- @tparam[opt=0] number down the amount of padding on the bottom --- @tparam[opt=0] number left the amount of padding on the left --- @tparam[opt=0] number right the amount of padding on the right -function Gui.set_padding(element,up,down,left,right) - local style = element.style - style.top_padding = up or 0 - style.bottom_padding = down or 0 - style.left_padding = left or 0 - style.right_padding = right or 0 -end - ---- Sets the padding for a gui style --- @tparam LuaStyle style the element to set the padding for --- @tparam[opt=0] number up the amount of padding on the top --- @tparam[opt=0] number down the amount of padding on the bottom --- @tparam[opt=0] number left the amount of padding on the left --- @tparam[opt=0] number right the amount of padding on the right -function Gui.set_padding_style(style,up,down,left,right) - style.top_padding = up or 0 - style.bottom_padding = down or 0 - style.left_padding = left or 0 - style.right_padding = right or 0 -end - ---- Allows the creation of an alignment flow to place elements into --- @tparam LuaGuiElement element the element to add this alignment into --- @tparam[opt] string name the name to use for the alignment --- @tparam[opt='right'] string horizontal_align the horizontal alignment of the elements in this flow --- @tparam[opt='center'] string vertical_align the vertical alignment of the elements in this flow --- @treturn LuaGuiElement the new flow that was created -function Gui.create_alignment(element,name,horizontal_align,vertical_align) - local flow = element.add{name=name,type='flow'} - local style = flow.style - Gui.set_padding(flow,1,1,2,2) - style.horizontal_align = horizontal_align or 'right' - style.vertical_align = vertical_align or 'center' - style.horizontally_stretchable =style.horizontal_align ~= 'center' - style.vertically_stretchable = style.vertical_align ~= 'center' - return flow -end - ---- Destroies an element but tests for it being present and valid first --- @tparam LuaGuiElement element the element to be destroied --- @treturn boolean true if it was destoried -function Gui.destroy_if_valid(element) - if element and element.valid then - element.destroy() - return true - end -end - ---- Creates a scroll area with a table inside, table can be any size --- @tparam LuaGuiElement element the element to add this scroll into --- @tparam number table_size the number of columns in the table --- @tparam number maximal_height the max hieght of the scroll --- @tparam[opt='scroll'] string name the name of the scoll element --- @treturn LuaGuiElement the table that was made -function Gui.create_scroll_table(element,table_size,maximal_height,name) - local list_scroll = - element.add{ - name=name or 'scroll', - type='scroll-pane', - direction='vertical', - horizontal_scroll_policy='never', - vertical_scroll_policy='auto-and-reserve-space' - } - Gui.set_padding(list_scroll,1,1,2,2) - list_scroll.style.horizontally_stretchable = true - list_scroll.style.maximal_height = maximal_height - - local list_table = - list_scroll.add{ - name='table', - type='table', - column_count=table_size - } - Gui.set_padding(list_table) - list_table.style.horizontally_stretchable = true - list_table.style.vertical_align = 'center' - list_table.style.cell_padding = 0 - - return list_table -end - ---- Creates a header section with a label and button area --- @tparam LuaGuiElement element the element to add this header into --- @tparam localeString caption the caption that is used as the title --- @tparam[opt] localeString tooltip the tooltip that is shown on the caption --- @tparam[opt] boolean right_align when true will include the right align area --- @tparam[opt='header'] string name the name of the header area --- @treturn LuaGuiElement the header that was made, or the align area if that was created -function Gui.create_header(element,caption,tooltip,right_align,name) - local header = - element.add{ - name=name or 'header', - type='frame', - style='subheader_frame' - } - Gui.set_padding(header,2,2,4,4) - header.style.horizontally_stretchable = true - header.style.use_header_filler = false - - header.add{ - type='label', - style='heading_1_label', - caption=caption, - tooltip=tooltip - } - - return right_align and Gui.create_alignment(header,'header-align') or header -end - -return Gui \ No newline at end of file diff --git a/expcore/gui/core_defines.lua b/expcore/gui/core_defines.lua new file mode 100644 index 00000000..8ae38fbe --- /dev/null +++ b/expcore/gui/core_defines.lua @@ -0,0 +1,87 @@ +--[[-- Core Module - Gui +- Gui defines that are used internally by the gui system +@module Gui +]] + +local Gui = require 'expcore.gui.prototype' +local Event = require 'utils.event' --- @dep utils.event + +--- Core Defines. +-- @section coreDefines + +--- Button which toggles the top flow elements, version which shows inside the top flow when top flow is visible +-- @element hide_top_flow +local hide_top_flow = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/preset', + style = 'tool_button', + tooltip = {'gui_util.button_tooltip'} +} +:style{ + padding = -2, + width = 18, + height = 36 +} +:on_click(function(player,_,_) + Gui.toggle_top_flow(player) +end) +Gui.core_defines.hide_top_flow = hide_top_flow + +--- Button which toggles the top flow elements, version which shows inside the left flow when top flow is hidden +-- @element show_top_flow +local show_top_flow = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/preset', + style = 'tool_button', + tooltip = {'gui_util.button_tooltip'} +} +:style{ + padding = -2, + width = 18, + height = 20 +} +:on_click(function(player,_,_) + Gui.toggle_top_flow(player) +end) +Gui.core_defines.show_top_flow = show_top_flow + +--- Button which hides the elements in the left flow, shows inside the left flow when frames are visible +-- @element hide_left_flow +local hide_left_flow = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/close_black', + style = 'tool_button', + tooltip = {'expcore-gui.left-button-tooltip'} +} +:style{ + padding = -3, + width = 18, + height = 20 +} +:on_click(function(player,_,_) + Gui.hide_left_flow(player) +end) +Gui.core_defines.hide_left_flow = hide_left_flow + +--- Draw the core elements when a player joins the game +Event.add(defines.events.on_player_created,function(event) + local player = game.players[event.player_index] + + -- Draw the top flow + local top_flow = Gui.get_top_flow(player) + hide_top_flow(top_flow) + Gui.update_top_flow(player) + + -- Draw the left flow + local left_flow = Gui.get_left_flow(player) + local button_flow = left_flow.add{ type = 'flow', name = 'gui_core_buttons', direction = 'vertical' } + local show_top = show_top_flow(button_flow) + local hide_left = hide_left_flow(button_flow) + show_top.visible = false + hide_left.visible = false + Gui.draw_left_flow(player) + +end) \ No newline at end of file diff --git a/expcore/gui/defines.lua b/expcore/gui/defines.lua new file mode 100644 index 00000000..d062078c --- /dev/null +++ b/expcore/gui/defines.lua @@ -0,0 +1,218 @@ +--[[-- Core Module - Gui +- Common defines that are used by other modules, non of these are used internally +@module Gui +]] + +local Gui = require 'expcore.gui.prototype' + +--- Defines. +-- @section defines + +--[[-- Draw a flow used to align its child elements, default is right align +@element Gui.alignment +@tparam LuaGuiElement parent the parent element to which the alignment will be added +@tparam[opt='alignment'] string name the name of the alignment flow which is added +@tparam[opt='right'] string horizontal_align the horizontal alignment of the elements in the flow +@tparam[opt='center'] string vertical_align the vertical alignment of the elements in the flow +@treturn LuaGuiElement the alignment flow that was created + +@usage-- Adding a right align flow +local alignment = Gui.alignment(element,'example_right_alignment') + +@usage-- Adding a horizontal center and top align flow +local alignment = Gui.alignment(element,'example_center_top_alignment','center','top') + +]] +Gui.alignment = +Gui.element(function(_,parent,name,_,_) + return parent.add{ + name = name or 'alignment', + type = 'flow', + } +end) +:style(function(style,_,_,horizontal_align,vertical_align) + style.padding = {1,2} + style.vertical_align = vertical_align or 'center' + style.horizontal_align = horizontal_align or 'right' + style.vertically_stretchable = style.vertical_align ~= 'center' + style.horizontally_stretchable = style.horizontal_align ~= 'center' +end) + +--[[-- Draw a scroll pane that has a table inside of it +@element Gui.scroll_table +@tparam LuaGuiElement parent the parent element to which the scroll table will be added +@tparam number height the maximum height for the scroll pane +@tparam number column_count the number of columns that the table will have +@tparam[opt='scroll'] string name the name of the scroll pane that is added, the table is always called "table" +@treturn LuaGuiElement the table that was created + +@usage-- Adding a scroll table with max height of 200 and column count of 3 +local scroll_table = Gui.scroll_table(element,200,3) + +]] +Gui.scroll_table = +Gui.element(function(_,parent,height,column_count,name) + -- Draw the scroll + local scroll_pane = + parent.add{ + name = name or 'scroll', + type = 'scroll-pane', + direction = 'vertical', + horizontal_scroll_policy = 'never', + vertical_scroll_policy = 'auto', + style = 'scroll_pane_under_subheader' + } + + -- Set the style of the scroll pane + local scroll_style = scroll_pane.style + scroll_style.padding = {1,3} + scroll_style.maximal_height = height + scroll_style.horizontally_stretchable = true + + -- Draw the table + local scroll_table = + scroll_pane.add{ + type = 'table', + name = 'table', + column_count = column_count + } + + -- Return the scroll table + return scroll_table +end) +:style{ + padding = 0, + cell_padding = 0, + vertical_align = 'center', + horizontally_stretchable = true +} + +--[[-- Used to add a frame with the header style, has the option for a right alignment flow for buttons +@element Gui.header +@tparam LuaGuiElement parent the parent element to which the header will be added +@tparam ?string|Concepts.LocalizedString caption the caption that will be shown on the header +@tparam[opt] ?string|Concepts.LocalizedString tooltip the tooltip that will be shown on the header +@tparam[opt=false] boolean add_alignment when true an alignment flow will be added to the header +@tparam[opt='header'] string name the name of the header that is being added, the alignment is always called "alignment" +@treturn LuaGuiElement either the header or the header alignment if add_alignment is true + +@usage-- Adding a custom header with a label +local header = Gui.header( + element, + 'Example Caption', + 'Example Tooltip' +) + +]] +Gui.header = +Gui.element(function(_,parent,caption,tooltip,add_alignment,name) + -- Draw the header + local header = + parent.add{ + name = name or 'header', + type = 'frame', + style = 'subheader_frame' + } + + -- Change the style of the header + local style = header.style + style.padding = {2,4} + style.use_header_filler = false + style.horizontally_stretchable = true + + -- Draw the caption label + if caption then + header.add{ + name = 'header_label', + type = 'label', + style = 'heading_1_label', + caption = caption, + tooltip = tooltip + } + end + + -- Return either the header or the added alignment + return add_alignment and Gui.alignment(header) or header +end) + +--[[-- Used to add a frame with the footer style, has the option for a right alignment flow for buttons +@element Gui.footer +@tparam LuaGuiElement parent the parent element to which the footer will be added +@tparam ?string|Concepts.LocalizedString caption the caption that will be shown on the footer +@tparam[opt] ?string|Concepts.LocalizedString tooltip the tooltip that will be shown on the footer +@tparam[opt=false] boolean add_alignment when true an alignment flow will be added to the footer +@tparam[opt='footer'] string name the name of the footer that is being added, the alignment is always called "alignment" +@treturn LuaGuiElement either the footer or the footer alignment if add_alignment is true + +@usage-- Adding a custom footer with a label +local footer = Gui.footer( + element, + 'Example Caption', + 'Example Tooltip' +) + +]] +Gui.footer = +Gui.element(function(_,parent,caption,tooltip,add_alignment,name) + -- Draw the header + local footer = + parent.add{ + name = name or 'footer', + type = 'frame', + style = 'subfooter_frame' + } + + -- Change the style of the footer + local style = footer.style + style.padding = {2,4} + style.use_header_filler = false + style.horizontally_stretchable = true + + -- Draw the caption label + if caption then + footer.add{ + name = 'footer_label', + type = 'label', + style = 'heading_1_label', + caption = caption, + tooltip = tooltip + } + end + + -- Return either the footer or the added alignment + return add_alignment and Gui.alignment(footer) or footer +end) + +--[[-- Used for left frames to give them a nice boarder +@element Gui.container +@tparam LuaGuiElement parent the parent element to which the container will be added +@tparam string name the name that you want to give to the outer frame, often just event_trigger +@tparam number width the minimal width that the frame will have + +@usage-- Adding a container as a base +local container = Gui.container(parent,'my_container',200) + +]] +Gui.container = +Gui.element(function(_,parent,name,_) + -- Draw the external container + local frame = + parent.add{ + name = name, + type = 'frame' + } + + -- Return the container + return frame.add{ + name = 'container', + type = 'frame', + direction = 'vertical', + style = 'window_content_frame_packed' + } +end) +:style(function(style,element,_,width) + style.vertically_stretchable = false + local frame_style = element.parent.style + frame_style.padding = 2 + frame_style.minimal_width = width +end) \ No newline at end of file diff --git a/expcore/gui/elements/buttons.lua b/expcore/gui/elements/buttons.lua deleted file mode 100644 index aa06f58b..00000000 --- a/expcore/gui/elements/buttons.lua +++ /dev/null @@ -1,128 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Buttons. --- Gui class define for buttons and sprite buttons --- @section Buttons - ---[[ ->>>> Functions - Button.new_button(name) --- Creates a new button element define - - Button._prototype:on_click(player,element) --- Registers a handler for when the button is clicked - Button._prototype:on_left_click(player,element) --- Registers a handler for when the button is clicked with the left mouse button - Button._prototype:on_right_click(player,element) --- Registers a handler for when the button is clicked with the right mouse button - - Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite) --- Adds sprites to a button making it a sprite button - Button._prototype:set_click_filter(filter,...) --- Adds a click / mouse button filter to the button - Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button - - Other functions present from expcore.gui.core -]] -local mod_gui = require 'mod-gui' --- @dep mod-gui -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype - -local Button = { - _prototype=Prototype.extend{ - on_raw_click = Prototype.event, - on_click = Prototype.event, - on_left_click = Prototype.event, - on_right_click = Prototype.event, - } -} - ---- Creates a new button element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new button element define -function Button.new_button(name) - - local self = Gui.new_define(Button._prototype,name) - self.draw_data.type = 'button' - self.draw_data.style = mod_gui.button_style - - Gui.on_click(self.name,function(event) - local mouse_button = event.button - local keys = {alt=event.alt,control=event.control,shift=event.shift} - local player,element = event.player,event.element - event.keys = keys - - self:raise_event('on_raw_click',event) - - if self.post_authenticator then - if not self.post_authenticator(event.player,self.name) then return end - end - - if mouse_button == defines.mouse_button_type.left then - self:raise_event('on_left_click',player,element) - elseif mouse_button == defines.mouse_button_type.right and self.events.on_right_click then - self:raise_event('on_right_click',player,element) - end - - if self.mouse_button_filter and not self.mouse_button_filter[mouse_button] then return end - if self.key_button_filter then - for key,state in pairs(self.key_button_filter) do - if state and not keys[key] then return end - end - end - - self:raise_event('on_click',player,element) - end) - - return self -end - ---- Adds sprites to a button making it a sprite button --- @tparam SpritePath sprite the sprite path for the default sprite for the button --- @tparam[opt] SpritePath hovered_sprite the sprite path for the sprite when the player hovers over the button --- @tparam[opt] SpritePath clicked_sprite the sprite path for the sprite when the player clicks the button --- @treturn self returns the button define to allow chaining -function Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite) - self.draw_data.type = 'sprite-button' - self.draw_data.sprite = sprite - self.draw_data.hovered_sprite = hovered_sprite - self.draw_data.clicked_sprite = clicked_sprite - return self -end - ---- Adds a click / mouse button filter to the button --- @tparam table filter ?string|table either a of mouse buttons or the first mouse button to filter, with a table true means allowed --- @tparam[opt] table ... when filter is not a you can add the mouse buttons one after each other --- @treturn self returns the button define to allow chaining -function Button._prototype:set_click_filter(filter,...) - if type(filter) == 'string' then - filter = {[filter]=true} - for _,v in pairs({...}) do - filter[v] = true - end - end - - for k,v in pairs(filter) do - if type(v) == 'string' then - filter[k] = defines.mouse_button_type[v] - end - end - - self.mouse_button_filter = filter - return self -end - ---- Adds a control key filter to the button --- @tparam table filter ?string|table either a of control keys or the first control keys to filter, with a table true means allowed --- @tparam[opt] table ... when filter is not a you can add the control keys one after each other --- @treturn self returns the button define to allow chaining -function Button._prototype:set_key_filter(filter,...) - if type(filter) == 'string' then - filter = {[filter]=true} - for _,v in pairs({...}) do - filter[v] = true - end - end - - self.key_button_filter = filter - return self -end - -return Button \ No newline at end of file diff --git a/expcore/gui/elements/checkbox.lua b/expcore/gui/elements/checkbox.lua deleted file mode 100644 index ce9b2a8a..00000000 --- a/expcore/gui/elements/checkbox.lua +++ /dev/null @@ -1,247 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Checkboxs. --- Gui class define for checkbox and radiobuttons --- @section checkboxs - ---[[ ->>>> Using an option set - An option set is a set of radio buttons where only one of them can be active at a time, this means that when one - is clicked all the other ones are set to false, an option set must be defined before hand and will always store - its state but is not limited by how it can categorize the store. - - First you must register the store with a name and a update callback, and an optional function for categorize: - - local example_option_set = - Gui.new_option_set('example-option-set',function(value,category) - game.print('Example options set '..category..' is now: '..tostring(value)) - end,Gui.categorize_by_player) - - Then you must register some radiobutton defines and include them in the option set: - - local example_option_one = - Gui.new_radiobutton() - :set_caption('Option One') - :add_as_option(example_option_set,'One') - - local example_option_two = - Gui.new_radiobutton() - :set_caption('Option Two') - :add_as_option(example_option_set,'Two') - - Note that these radiobuttons can still have on_element_update events but this may result in a double trigger of events as - the option set update is always triggered; also add_store cant be used as the option set acts as the store however get - and set store will still work but will effect the option set rather than the individual radiobuttons. - ->>>> Functions - Checkbox.new_checkbox(name) --- Creates a new checkbox element define - Checkbox._prototype_checkbox:on_element_update(callback) --- Registers a handler for when an element instance updates - Checkbox._prototype_checkbox:on_store_update(callback) --- Registers a handler for when the stored value updates - - Checkbox.new_radiobutton(name) --- Creates a new radiobutton element define - Checkbox._prototype_radiobutton:on_element_update(callback) --- Registers a handler for when an element instance updates - Checkbox._prototype_radiobutton:on_store_update(callback) --- Registers a handler for when the stored value updates - Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) --- Adds this radiobutton to be an option in the given option set (only one can be true at a time) - - Checkbox.new_option_set(name,callback,categorize) --- Registers a new option set that can be linked to radiobutton (only one can be true at a time) - Checkbox.draw_option_set(name,element) --- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work) - - Checkbox.reset_radiobutton(element,exclude,recursive) --- Sets all radiobutton in a element to false (unless excluded) and can act recursively - - Other functions present from expcore.gui.core -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Store = require 'expcore.store' --- @dep expcore.store -local Game = require 'utils.game' --- @dep utils.game - ---- Store call for store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam boolean value the new state of the checkbox -local function store_update(define,element,value) - element.state = value - local player = Game.get_player_by_index(element.player_index) - define:raise_event('on_element_update',player,element,value) -end - -local Checkbox = { - option_sets={}, - option_categorize={}, - _prototype_checkbox=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - }, - _prototype_radiobutton=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - } -} - ---- Creates a new checkbox element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new checkbox element define -function Checkbox.new_checkbox(name) - - local self = Gui.new_define(Checkbox._prototype_checkbox,name) - self.draw_data.type = 'checkbox' - self.draw_data.state = false - - self:on_draw(function(player,element) - if self.store then - local state = self:get_store(element,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] - self:set_store(element,value) - - elseif self.store then - local value = element.state - self:set_store(element,value) - - else - self:raise_event('on_element_update',event.player,element,element.state) - - end - end) - - return self -end - ---- Creates a new radiobutton element define, has all functions checkbox has --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new button element define -function Checkbox.new_radiobutton(name) - local self = Checkbox.new_checkbox(name) - self.draw_data.type = 'radiobutton' - - local mt = getmetatable(self) - mt.__index = Checkbox._prototype_radiobutton - - return self -end - ---- Adds this radiobutton to be an option in the given option set (only one can be true at a time) --- @tparam string option_set the name of the option set to add this element to --- @tparam string option_name the name of this option that will be used to identify it --- @treturn self the define to allow chaining -function Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) - self.option_set = option_set - self.option_name = option_name or self.name - - Checkbox.option_sets[option_set][self.option_name] = self.name - Checkbox.option_sets[option_set][self.name] = self.option_name - - self:add_store(Checkbox.option_categorize[option_set]) - - return self -end - ---- Gets the stored value of the radiobutton or the option set if present --- @tparam string category[opt] the category to get such as player name or force name --- @tparam boolean internal used to prevent stackover flow --- @treturn any the value that is stored for this define -function Checkbox._prototype_radiobutton:get_store(category,internal) - if not self.store then return end - local location = not internal and self.option_set or self.store - return Store.get(location,category) -end - ---- Sets the stored value of the radiobutton or the option set if present --- @tparam string category[opt] the category to get such as player name or force name --- @tparam boolean value the value to set for this define, must be valid for its type ie for checkbox etc --- @tparam boolean internal used to prevent stackover flow --- @treturn boolean true if the value was set -function Checkbox._prototype_radiobutton:set_store(category,value,internal) - if not self.store then return end - local location = not internal and self.option_set or self.store - return Store.set(location,category,value) -end - ---- Registers a new option set that can be linked to radiobuttons (only one can be true at a time) --- @tparam function callback the update callback when the value of the option set changes --- callback param - value string - the new selected option for this option set --- callback param - category string - the category that updated if categorize was used --- @tparam function categorize the function used to convert an element into a string --- @treturn string the name of this option set to be passed to add_as_option -function Checkbox.new_option_set(callback,categorize) - local name = Store.register(categorize) - - Store.watch(name,function(value,category) - local options = Checkbox.option_sets[name] - for opt_name,define_name in pairs(options) do - if Gui.defines[define_name] then - local define = Gui.get_define(define_name) - local state = opt_name == value - define:set_store(category,state,true) - end - end - callback(value,category) - end) - - Checkbox.option_categorize[name] = categorize - Checkbox.option_sets[name] = {} - - return name -end - ---- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work) --- @tparam string name the name of the option set to draw the radiobuttons of --- @tparam LuaGuiElement element the parent element that the radiobuttons will be drawn to -function Checkbox.draw_option_set(name,element) - if not Checkbox.option_sets[name] then return end - local options = Checkbox.option_sets[name] - - for _,option in pairs(options) do - if Gui.defines[option] then - Gui.defines[option]:draw_to(element) - end - end - -end - ---- Sets all radiobutton in a element to false (unless excluded) and can act recursively --- @tparam LuaGuiElement element the root gui element to start setting radio buttons from --- @tparam[opt] table exclude ?string|table the name of the radiobutton to exclude or a of radiobuttons where true will set the state true --- @tparam[opt=false] ?number|boolean recursive if true will recur as much as possible, if a will recur that number of times --- @treturn boolean true if successful -function Checkbox.reset_radiobuttons(element,exclude,recursive) - if not element or not element.valid then return end - exclude = type(exclude) == 'table' and exclude or exclude ~= nil and {[exclude]=true} or {} - recursive = type(recursive) == 'number' and recursive-1 or recursive - - for _,child in pairs(element.children) do - if child and child.valid and child.type == 'radiobutton' then - local state = exclude[child.name] or false - local define = Gui.defines[child.name] - - if define then - local category = define.categorize and define.categorize(child) or state - define:set_store(category,state) - - else - child.state = state - - end - - elseif child.children and (type(recursive) == 'number' and recursive >= 0 or recursive == true) then - Checkbox.reset_radiobutton(child,exclude,recursive) - - end - end - - return true -end - -return Checkbox \ No newline at end of file diff --git a/expcore/gui/elements/dropdown.lua b/expcore/gui/elements/dropdown.lua deleted file mode 100644 index ae6857c0..00000000 --- a/expcore/gui/elements/dropdown.lua +++ /dev/null @@ -1,184 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Dropdowns. --- Gui class define for dropdowns and list box --- @section dropdowns - ---[[ ->>>> Functions - Dropdown.new_dropdown(name) --- Creates a new dropdown element define - Dropdown.new_list_box(name) --- Creates a new list box element define - - Dropdown._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - Dropdown._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - Dropdown._prototype:new_static_options(options,...) --- Adds new static options to the dropdown which will trigger the general callback - Dropdown._prototype:new_dynamic_options(callback) --- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options) - Dropdown._prototype:add_option_callback(option,callback) --- Adds a case specific callback which will only run when that option is selected (general case still triggered) - - Dropdown.select_value(element,value) --- Selects the option from a dropdown or list box given the value rather than key - Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index - - Other functions present from expcore.gui.core -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Game = require 'utils.game' --- @dep utils.game - -local select_value ---- Store call for store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam string value the new option for the dropdown -local function store_update(define,element,value) - select_value(element,value) - local player = Game.get_player_by_index(element.player_index) - define:raise_event('on_element_update',player,element,value) - - if define.option_callbacks and define.option_callbacks[value] then - define.option_callbacks[value](player,element,value) - end -end - -local Dropdown = { - _prototype=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - } -} - ---- Creates a new dropdown element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new dropdown element define -function Dropdown.new_dropdown(name) - - local self = Gui.new_define(Dropdown._prototype,name) - self.draw_data.type = 'drop-down' - - self:on_draw(function(player,element) - if self.dynamic_options then - local dynamic_options = self.dynamic_options(player,element) - local items = element.items - for _,v in pairs(dynamic_options) do - table.insert(items,v) - end - element.items = items - end - - if self.store then - local value = self:get_store(element) - 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 - self:set_store(element,value) - - else - local player = event.player - local option_callbacks = self.option_callbacks - self:raise_event('on_element_update',player,element,value) - if option_callbacks and option_callbacks[value] then - option_callbacks[value](player,element,value) - end - - end - - end) - - return self -end - ---- Creates a new list box element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new list box element define -function Dropdown.new_list_box(name) - local self = Dropdown.new_dropdown(name) - self.draw_data.type = 'list-box' - - return self -end - ---- Adds new static options to the dropdown which will trigger the general callback --- @tparam table options ?string|table either a of option strings or the first option string, with a table values are the options --- @tparam[opt] table ... when options is not a you can add the options one after each other --- @tparam self the define to allow chaining -function Dropdown._prototype:new_static_options(options,...) - if type(options) == 'string' then - options = {options} - for _,v in pairs({...}) do - table.insert(options,v) - end - end - - self.options = options - self.draw_data.items = options - return self -end -Dropdown._prototype.add_options = Dropdown._prototype.new_static_options - ---- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options) --- @tparam function callback the function that will run to get the options for the dropdown --- callback param - player LuaPlayer - the player that the element is being drawn to --- callback param - element LuaGuiElement - the element that is being drawn --- callback return - table - the values of this table will be appended to the static options of the dropdown --- @treturn self the define to allow chaining -function Dropdown._prototype:new_dynamic_options(callback) - if type(callback) ~= 'function' then - return error('Dynamic options callback must be a function',2) - end - self.dynamic_options = callback - return self -end -Dropdown._prototype.add_dynamic = Dropdown._prototype.new_dynamic_options - ---- Adds a case specific callback which will only run when that option is selected (general case still triggered) --- @tparam string option the name of the option to trigger the callback on; if not already added then will be added as an option --- @tparam function callback the function that will be called when that option is selected --- callback param - player LuaPlayer - the player who owns the gui element --- callback param - element LuaGuiElement - the element which is being effected --- callback param - value string - the new option that has been selected --- @treturn self the define to allow chaining -function Dropdown._prototype:add_option_callback(option,callback) - if not self.option_callbacks then self.option_callbacks = {} end - if not self.options then self.options = {} end - - self.option_callbacks[option] = callback - if not table.contains(self.options,option) then - table.insert(self.options,option) - end - - return self -end - ---- Selects the option from a dropdown or list box given the value rather than key --- @tparam LuaGuiElement element the element that contains the option --- @tparam string value the option to select from the dropdown --- @treturn number the key where the value was -function Dropdown.select_value(element,value) - for k,item in pairs(element.items) do - if item == value then - element.selected_index = k - return k - end - end -end -select_value = Dropdown.select_value - ---- Returns the currently selected value rather than index --- @tparam LuaGuiElement element the gui element that you want to get the value of --- @treturn string the value that is currently selected -function Dropdown.get_selected_value(element) - local index = element.selected_index - return element.items[index] -end - -return Dropdown \ No newline at end of file diff --git a/expcore/gui/elements/elem-button.lua b/expcore/gui/elements/elem-button.lua deleted file mode 100644 index 8b2b2b3c..00000000 --- a/expcore/gui/elements/elem-button.lua +++ /dev/null @@ -1,96 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Elem Buttons. --- Gui class defines for elem buttons --- @section elem-buttons - ---[[ ->>>> Functions - ElemButton.new_elem_button(name) --- Creates a new elem button element define - - ElemButton._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - ElemButton._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - ElemButton._prototype:set_type(type) --- Sets the type of the elem button, the type is required so this must be called at least once - ElemButton._prototype:set_default(value) --- Sets the default value for the elem button, this may be a function or a string - - Other functions present from expcore.gui.core -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Game = require 'utils.game' --- @dep utils.game - ---- Store call for store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam string value the new value for the elem button -local function store_update(define,element,value) - element.elem_value = value - local player = Game.get_player_by_index(element.player_index) - define:raise_event('on_element_update',player,element,value) -end - -local ElemButton = { - _prototype=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - } -} - ---- Creates a new elem button element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new elem button element define -function ElemButton.new_elem_button(name) - - local self = Gui.new_define(ElemButton._prototype,name) - self.draw_data.type = 'choose-elem-button' - - self:on_draw(function(player,element) - if type(self.default) == 'function' then - element.elem_value = self.default(player,element) - end - - if self.store then - local value = self:get_store(element) - 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 - self:set_store(element,value) - - else - self:raise_event('on_element_update',event.player,element,value) - - end - - end) - - return self -end - ---- Sets the type of the elem button, the type is required so this must be called at least once --- @tparam string type the type that this elem button is see factorio api --- @treturn the element define to allow for chaining -ElemButton._prototype.set_type = Prototype.setter('string','draw_data','elem_type') - ---- Sets the default value for the elem button, this may be a function or a string --- @tparam ?string|function value string a will be a static default and a function will be called when drawn to get the default --- @treturn the element define to allow for chaining -function ElemButton._prototype:set_default(value) - self.default = value - if type(value) ~= 'function' then - self.draw_data[self.draw_data.elem_type] = value - end - return self -end - -return ElemButton \ No newline at end of file diff --git a/expcore/gui/elements/progress-bar.lua b/expcore/gui/elements/progress-bar.lua deleted file mode 100644 index 0e096d42..00000000 --- a/expcore/gui/elements/progress-bar.lua +++ /dev/null @@ -1,387 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Progress Bars. --- Gui element define for progress bars --- @section progress-bars - ---[[ ->>>> Functions - ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar - ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances have incremented - ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances have decremented - - ProgressBar.new_progressbar(name) --- Creates a new progressbar element define - ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar - ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0 - ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar - ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store - ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar - ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store - ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store - ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0 - - ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element completes (hits 0 or 1) - ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1) - ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented - ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Global = require 'utils.global' --- @dep utils.global -local Game = require 'utils.game' --- @dep utils.game - ---- Event call for when the value is outside the range 0-1 --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event -local function event_call(define,element) - local player = Game.get_player_by_index(element.player_index) - define:raise_event('on_complete',player,element,function() - define:add_element(element) - define:reset_element(element) - end) -end - ---- Store call for store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam number value the new value for the progress bar -local function store_update(define,element,value) - if value then - element.value = value - if define.count_down and value <= 0 - or not define.count_down and value >= 1 then - event_call(define,element) - end - end -end - -local ProgressBar = { - unregistered={}, -- elements with no callbacks - independent={}, -- elements with a link to a define - _prototype=Prototype.extend{ - on_complete = Prototype.event, - on_store_complete = Prototype.event, - add_store = Prototype.store(store_update) - } -} - -Global.register({ - unregistered = ProgressBar.unregistered, - independent = ProgressBar.independent -},function(tbl) - ProgressBar.unregistered = tbl.unregistered - ProgressBar.independent = tbl.independent -end) - ---- Gets the define data, cant use Gui.get_define as it would error --- @tparam ?table|string define the define to get --- @treturn table the define or nil -local function get_define(define) - if type(define) == 'table' then - if define.name and Gui.defines[define.name] then - return Gui.defines[define.name] - end - end - - return Gui.defines[define] -end - ---- Gets the element data, used when there is no define --- @tparam LuaGuiElement element the element to get the data of --- @treturn table the element data similar to define -local function get_element(element) - if not element.valid then return end - local name = element.player_index..':'..element.index - - if ProgressBar.unregistered[name] then - return ProgressBar.unregistered[name] - end -end - ---- Sets the maximum value that represents the end value of the progress bar --- @tparam ?LuaGuiElement|string element either a gui element or a registered define --- @tparam number amount the amount to have set as the maximum -function ProgressBar.set_maximum(element,amount) - amount = amount > 0 and amount or error('amount must be greater than 0') - - local define = get_define(element) - if define then - define:set_default_maximum(amount) - - else - local element_data = get_element(element) - - if element_data then - element_data.maximum = amount - - else - local name = element.player_index..':'..element.index - ProgressBar.unregistered[name] = { - element=element, - maximum=amount or 1 - } - - end - - end -end - ---- Increases the value of the progressbar, if a define is given all of its instances have incremented --- @tparam ?LuaGuiElement|string element either a gui element or a registered define --- @tparam[opt=1] number amount the amount to increase the progressbar by -function ProgressBar.increment(element,amount) - amount = type(amount) == 'number' and amount or 1 - - local define = get_define(element) - if define then - define:increment(amount) - - else - local element_data = get_element(element) - - if element_data then - local real_amount = amount/element_data.maximum - element.value = element.value + real_amount - - if element.value >= 1 then - local name = element.player_index..':'..element.index - ProgressBar.unregistered[name] = nil - return true - end - end - - end -end - ---- Decreases the value of the progressbar, if a define is given all of its instances have decremented --- @tparam ?LuaGuiElement|string element either a gui element or a registered define --- @tparam[opt=1] number amount the amount to decrease the progressbar by -function ProgressBar.decrement(element,amount) - amount = type(amount) == 'number' and amount or 1 - - local define = get_define(element) - if define then - define:decrement(amount) - - else - local element_data = get_element(element) - - if element_data then - local real_amount = amount/element_data.maximum - element.value = element.value - real_amount - - if element.value <= 0 then - local name = element.player_index..':'..element.index - ProgressBar.unregistered[name] = nil - return true - end - end - - end -end - ---- Creates a new progressbar element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new progressbar element define -function ProgressBar.new_progressbar(name) - - local self = Gui.new_define(ProgressBar._prototype,name) - self.draw_data.type = 'progressbar' - - self:on_draw(function(player,element,maximum) - if self.store then - local value = self:get_store(element) - if not value then - value = self.count_down and 1 or 0 - self:set_store(element,value) - end - element.value = value - - else - if self.count_down then - element.value = 1 - end - - if not ProgressBar.independent[self.name] then - ProgressBar.independent[self.name] = {} - end - - table.insert(ProgressBar.independent[self.name],{ - element = element, - maximum = maximum - }) - - end - - end) - - return self -end - ---- Sets the maximum value that represents the end value of the progress bar --- @tparam number amount the amount to have set as the maximum --- @treturn table the define to allow chaining -function ProgressBar._prototype:set_default_maximum(amount) - amount = amount > 0 and amount or error('amount must be greater than 0') - self.default_maximum = amount - return self -end - ---- Will set the progress bar to start at 1 and trigger when it hits 0 --- @tparam[opt=true] boolean state when true the bar will start filled, to be used with decrease --- @treturn table the define to allow chaining -function ProgressBar._prototype:use_count_down(state) - if state == false then - self.count_down = false - else - self.count_down = true - end - return self -end - ---- Main logic for changing the value of a progress bar, this only applies when its a registered define --- @tparam table self the define that is being changed --- @tparam number amount the amount which it is being changed by, may be negative --- @tparam[opt] string category the category to use with store --- @tparam[opt] function filter when given the filter must return true for the value of the element to be changed -local function change_value_prototype(self,amount,category,filter) - - local function reset_store() - local value = self.count_down and 1 or 0 - self:set_store(category,value) - end - - if self.store then - local value = self:get_store(category) or self.count_down and 1 or 0 - local maximum = self.default_maximum or 1 - local new_value = value + (amount/maximum) - - self:set_store(category,new_value) - - if self.count_down and new_value <= 0 - or not self.count_down and new_value >= 1 then - self:clear_store(category) - self:raise_event('on_store_complete',category,reset_store) - return - end - - return - end - - if ProgressBar.independent[self.name] then - for key,element_data in pairs(ProgressBar.independent[self.name]) do - local element = element_data.element - if not element or not element.valid then - ProgressBar.independent[self.name][key] = nil - - else - if not filter or filter(element) then - local maximum = element_data.maximum or self.default_maximum or 1 - element.value = element.value + (amount/maximum) - - if self.count_down and element.value <= 0 - or not self.count_down and element.value >= 1 then - ProgressBar.independent[self.name][key] = nil - event_call(self,element) - end - end - - end - end - end - -end - ---- Increases the value of the progressbar --- @tparam[opt=1] number amount the amount to increase the progressbar by --- @tparam[opt] string category the category that is used with a store -function ProgressBar._prototype:increment(amount,category) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,amount,category) -end - ---- Increases the value of the progressbar, if the filter condition is met, does not work with store --- @tparam[opt=1] number amount the amount to increase the progressbar by --- @tparam function filter the filter to be used -function ProgressBar._prototype:increment_filtered(amount,filter) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,amount,nil,filter) -end - ---- Decreases the value of the progressbar --- @tparam[opt=1] number amount the amount to decrease the progressbar by --- @tparam[opt] string category the category that is used with a store -function ProgressBar._prototype:decrement(amount,category) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,-amount,category) -end - ---- Decreases the value of the progressbar, if the filter condition is met, does not work with store --- @tparam[opt=1] number amount the amount to decrease the progressbar by --- @tparam function filter the filter to be used -function ProgressBar._prototype:decrement_filtered(amount,filter) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,-amount,nil,filter) -end - ---- Adds an element into the list of instances that will are waiting to complete, does not work with store --- note use store if you want persistent data, this only stores the elements not the values which they have --- @tparam LuaGuiElement element the element that you want to add into the waiting to complete list --- @tparam[opt] number maximum the maximum for this element if not given the default for this define is used -function ProgressBar._prototype:add_element(element,maximum) - if self.store then return end - if not ProgressBar.independent[self.name] then - ProgressBar.independent[self.name] = {} - end - table.insert(ProgressBar.independent[self.name],{ - element = element, - maximum = maximum - }) -end - ---- Resets an element, or its store, to be back at the start, either 1 or 0 --- @tparam LuaGuiElement element the element that you want to reset the progress of -function ProgressBar._prototype:reset_element(element) - if not element or not element.valid then return end - local value = self.count_down and 1 or 0 - if self.store then - self:set_store(element,value) - else - element.value = value - end -end - ---- Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented --- @tparam[opt] function filter when given will use filtered increment --- @treturn function the event handler -function ProgressBar._prototype:event_counter(filter) - if type(filter) == 'function' then - return function() - self:increment_filtered(1,filter) - end - else - return function() - self:increment() - end - end -end - ---- Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented --- @tparam[opt] function filter when given will use filtered decrement --- @treturn function the event handler -function ProgressBar._prototype:event_countdown(filter) - if type(filter) == 'function' then - return function() - self:decrement_filtered(1,filter) - end - else - return function() - self:decrement() - end - end -end - -return ProgressBar \ No newline at end of file diff --git a/expcore/gui/elements/slider.lua b/expcore/gui/elements/slider.lua deleted file mode 100644 index e8099b06..00000000 --- a/expcore/gui/elements/slider.lua +++ /dev/null @@ -1,173 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Sliders. --- Gui class define for sliders --- @section sliders - ---[[ ->>>> Functions - Slider.new_slider(name) --- Creates a new slider element define - - Slider._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - Slider._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - Slider._prototype:set_range(min,max) --- Sets the range of a slider, if not used will use default values for a slider - Slider._prototype:draw_label(element) --- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player - Slider._prototype:enable_auto_draw_label(state) --- Enables auto draw of the label, the label will share the same parent element as the slider - - Other functions present from expcore.gui.core -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances -local Game = require 'utils.game' --- @dep utils.game - ---- Event call for on_value_changed and store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam number value the new value for the slider -local function event_call(define,element,value) - local player = Game.get_player_by_index(element.player_index) - - local min,max = element.get_slider_minimum(),element.get_slider_maximum() - local delta = max-min - local percent = delta == 0 and 0 or (value-min)/delta - - define:raise_event('on_element_update',player,element,value,percent) - - local category = player.name - if define.categorize then - category = define.categorize(element) - end - - Instances.unregistered_get_elements(define.name..'-label',category,function(label) - label.caption = tostring(math.round(value,2)) - end) -end - ---- Store call for store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam number value the new value for the slider -local function store_update(define,element,value) - element.slider_value = value - event_call(define,element,value) -end - -local Slider = { - _prototype=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - } -} - ---- Creates a new slider element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new slider element define -function Slider.new_slider(name) - - local self = Gui.new_define(Slider._prototype,name) - self.draw_data.type = 'slider' - - self:on_draw(function(player,element) - local min,max = element.get_slider_minimum(),element.get_slider_maximum() - - if type(self.min) == 'function' then - min = self.min(player,element) - end - - if type(self.max) == 'function' then - max = self.max(player,element) - end - - element.set_slider_minimum_maximum(min,max) - - if self.store then - local value = self:get_store(element) - 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 - self:set_store(element,value) - - else - event_call(self,element,value) - - end - - end) - - return self -end - ---- Sets the range of a slider, if not used will use default values for a slider --- @tparam[opt] number min the minimum value that the slider can take --- @tparam[opt] number max the maximum value that the slider can take --- @treturn self the define to allow chaining -function Slider._prototype:set_range(min,max) - self.min = min - self.max = max - - if type(min) == 'number' then - self.draw_data.minimum_value = min - end - - if type(max) == 'number' then - self.draw_data.maximum_value = max - end - - return self -end - ---- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player --- @tparam LuaGuiElement element the parent element that the label will be drawn to --- @treturn LuaGuiElement the new label element so that styles can be applied -function Slider._prototype:draw_label(element) - local name = self.name..'-label' - if element[name] then return end - - local value = 0 - if self.store then - value = self:get_store(element) or 0 - end - - local new_element = element.add{ - name=name, - type='label', - caption=tostring(math.round(value,2)) - } - - local categorise = self.categorise or Gui.categorize_by_player - local category = categorise(new_element) - - Instances.unregistered_add_element(name,category,new_element) - - return new_element -end - ---- Enables auto draw of the label, the label will share the same parent element as the slider --- @tparam[opt=true] boolean state when false will disable the auto draw of the label --- @treturn self the define to allow chaining -function Slider._prototype:enable_auto_draw_label(state) - if state == false then - self.auto_label = false - else - self.auto_label = true - end - return self -end - -return Slider \ No newline at end of file diff --git a/expcore/gui/elements/text.lua b/expcore/gui/elements/text.lua deleted file mode 100644 index 56709ede..00000000 --- a/expcore/gui/elements/text.lua +++ /dev/null @@ -1,145 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Text. --- Gui class define for text fields and text boxes --- @section text - ---[[ ->>>> Functions - Text.new_text_field(name) --- Creates a new text field element define - Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates - Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates - - Text.new_text_box(name) --- Creates a new text box element define - Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates - Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates - Text._prototype_box:set_selectable(state) --- Sets the text box to be selectable - Text._prototype_box:set_word_wrap(state) --- Sets the text box to have word wrap - Text._prototype_box:set_read_only(state) --- Sets the text box to be read only - - Other functions present from expcore.gui.core -]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core -local Prototype = require 'expcore.gui.prototype' --- @dep expcore.gui.prototype -local Game = require 'utils.game' --- @dep utils.game - ---- Store call for store update --- @tparam table define the define that this is acting on --- @tparam LuaGuiElement element the element that triggered the event --- @tparam string value the new text for the text field -local function store_update(define,element,value) - element.text = value - local player = Game.get_player_by_index(element.player_index) - define:raise_event('on_element_update',player,element,value) -end - -local Text = { - _prototype_field=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - }, - _prototype_box=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(store_update) - } -} - ---- Creates a new text field element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new text field element define -function Text.new_text_field(name) - - local self = Gui.new_define(Text._prototype_field,name) - self.draw_data.type = 'textfield' - - self:on_draw(function(player,element) - if self.selectable then - element.selectable = true - end - - if self.word_wrap then - element.word_wrap = true - end - - if self.read_only then - element.read_only = true - end - - if self.store then - local value = self:get_store(element) - 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 - self:set_store(element,value) - - else - self:raise_event('on_element_update',event.player,element,value) - - end - - end) - - return self -end - ---- Creates a new text box element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new text box element define -function Text.new_text_box(name) - local self = Text.new_text_field(name) - self.draw_data.type = 'text-box' - - local mt = getmetatable(self) - mt.__index = Text._prototype_box - - return self -end - ---- Sets the text box to be selectable --- @tparam[opt=true] boolean state when false will set the state to false --- @treturn self table the define to allow for chaining -function Text._prototype_box:set_selectable(state) - if state == false then - self.selectable = false - else - self.selectable = true - end - return self -end - ---- Sets the text box to have word wrap --- @tparam[opt=true] boolean state when false will set the state to false --- @treturn self table the define to allow for chaining -function Text._prototype_box:set_word_wrap(state) - if state == false then - self.word_wrap = false - else - self.word_wrap = true - end - return self -end - ---- Sets the text box to be read only --- @tparam[opt=true] boolean state when false will set the state to false --- @treturn self table the define to allow for chaining -function Text._prototype_box:set_read_only(state) - if state == false then - self.read_only = false - else - self.read_only = true - end - return self -end - -return Text \ No newline at end of file diff --git a/expcore/gui/helper_functions.lua b/expcore/gui/helper_functions.lua new file mode 100644 index 00000000..c303fb15 --- /dev/null +++ b/expcore/gui/helper_functions.lua @@ -0,0 +1,91 @@ +--[[-- Core Module - Gui +- Functions used to help with the use of guis +@module Gui +]] + +local Gui = require 'expcore.gui.prototype' + +--- Helper Functions. +-- @section helperFunctions + +--[[-- Get the player that owns a gui element +@tparam LuaGuiElement element the element to get the owner of +@treturn LuaPlayer the player that owns this element + +@usage-- Geting the owner of an element +local player = Gui.get_player_from_element(element) + +]] +function Gui.get_player_from_element(element) + if not element or not element.valid then return end + return game.players[element.player_index] +end + +--[[-- Will toggle the enabled state of an element or set it to the one given +@tparam LuaGuiElement element the element to toggle/set the enabled state of +@tparam[opt] boolean state with given will set the state, else state will be toggled +@treturn boolean the new enabled state that the element has + +@usage-- Toggling the the enabled state +local new_enabled_state = Gui.toggle_enabled_state(element) + +]] +function Gui.toggle_enabled_state(element,state) + if not element or not element.valid then return end + if state == nil then state = not element.enabled end + element.enabled = state + return state +end + +--[[-- Will toggle the visible state of an element or set it to the one given +@tparam LuaGuiElement element the element to toggle/set the visible state of +@tparam[opt] boolean state with given will set the state, else state will be toggled +@treturn boolean the new visible state that the element has + +@usage-- Toggling the the visible state +local new_visible_state = Gui.toggle_visible_state(element) + +]] +function Gui.toggle_visible_state(element,state) + if not element or not element.valid then return end + if state == nil then state = not element.visible end + element.visible = state + return state +end + +--[[-- Destory a gui element without causing any errors, often because the element was already removed +@tparam LuaGuiElement element the element that you want to remove +@treturn boolean true if the element was valid and has been removed + +@usage-- Remove a child element if it exists +Gui.destroy_if_valid(element[child_name]) + +]] +function Gui.destroy_if_valid(element) + if not element or not element.valid then return false end + element.destroy() + return true +end + +--[[-- Returns a table to be used as the style for a sprite buttons, produces a sqaure button +@tparam number size the size that you want the button to be +@tparam[opt=-2] number padding the padding that you want on the sprite +@tparam[opt] table style any extra style settings that you want to have +@treturn table the style table to be used with element_define:style() + +@usage-- Adding a sprite button with size 20 +local button = +Gui.element{ + type = 'sprite-button', + sprite = 'entity/inserter' +} +:style(Gui.sprite_style(20)) + +]] +function Gui.sprite_style(size,padding,style) + style = style or {} + style.padding = padding or -2 + style.height = size + style.width = size + return style +end \ No newline at end of file diff --git a/expcore/gui/instances.lua b/expcore/gui/instances.lua deleted file mode 100644 index 2db7273e..00000000 --- a/expcore/gui/instances.lua +++ /dev/null @@ -1,235 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias Prototype -]] - ---- Instances. --- This file is a breakout from core which forcues on instance management of defines --- @section instances - ---[[ ->>>> Using registered instance groups - The main use of this module is to register a group of elements referred here as "instances of an element define" in which - is meant that you define the name of a group of drawn elements that are really just multiple versions of a single element. - For example this might be that you have one label in multiple places (either for one player or many) and you want to update - the caption of all of them at once; this is where this module comes it. - - First you must register the way that the instances are stored and under what name, using Instances.register you will give the - name of the collective group of instances followed by an optional serializer function which allows variants to be stored under one - name (like one for each force or player) - - -- serializer works in the same way as store serializer - -- so the function will world here but no value is stored only gui elements - Instances.register('score',Gui.categorize_by_force) - - Then when you draw the new element to a gui you will want to add the element to the group: - - Instances.add_element('score',new_element) - - Then when you want to get the instances you have two options; Instances.get_elements or Instances.apply_to_elements when you want loop - over the elements it is more efficient to use apply_to_elements: - - Instances.get_elements('score','player') -- returns all elements that were added with the 'player' category - Instances.apply_to_elements('score','player',function(element) -- runs the function on every valid element - element.caption = 0 - end) - - Note that if you don't give a serializer function then you don't need to give a category when getting the elements. - ->>>> Using unregistered instance groups - When using a registered group and the functions that go with them it is much simpler to use and more importantly includes error checking - for valid instance group names; the down side is that the group must be registered which can only be done during start-up and not during runtime. - To counter this there are two functions similar to those above in order to add and get instances but may lead to errors not being noticed due to - the error internal error checking being skipped to allow it to work. - - The main difference between the two groups of functions is that the category must always be present even if is nil; example below shows how a - instance group would work when registered vs unregistered: - - -- Registered with category - Instances.register('score',Gui.categorize_by_force) -- force_store will return the force name of an element - Instances.add_element('score',new_element) -- the new element is added to the category based on in force - Instances.apply_to_elements('score','player',function(element) - element.caption = '0' - end) -- gets all instances from the player force and sets the caption to 0 - - -- Unregistered with category - Instances.unregistered_add_element('score','player',new_element) -- adds the new element to the player category - Instances.unregistered_apply_to_elements('score','player',function(element) - element.caption = '0' - end) -- gets all instances from the player force and sets the caption to 0 - - -- Registered without category; note that category can just be ignored - Instances.register('score') -- all instances will be under one group with no categories - Instances.add_element('score',new_element) -- adds the new element to the instance list - Instances.apply_to_elements('score',function(element) - element.caption = '0' - end) -- gets all instances and sets the element caption to 0 - - -- Unregistered without category; note that category must be given as nil - Instances.unregistered_add_element('score',nil,new_element) -- adds the new element to a single group with no categories - Instances.unregistered_apply_to_elements('score',nil,function(element) - element.caption = '0' - end) -- gets all instances and sets the element caption to 0 - ->>>> Functions - Instances.has_categories(name) --- Returns if a instance group has a serializer function; must be registered - Instances.is_registered(name) --- Returns if the given name is a registered instance group - Instances.register(name,serializer) --- Registers the name of an instance group to allow for storing element instances - - Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered - Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered - Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid - - Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered - Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered -]] -local Global = require 'utils.global' --- @dep utils.global - -local Instances = { - serializer={}, - data={} -} -Global.register(Instances.data,function(tbl) - Instances.data = tbl -end) - ---- Returns if a instance group has a serializer function; must be registered --- @tparam string name the name of the instance group --- @treturn boolean true if there is a serializer function -function Instances.has_categories(name) - return type(Instances.serializer[name]) == 'function' -end - ---- Returns if the given name is a registered instance group --- @tparam string name the name of the instance group you are testing --- @treturn boolean true if the name is registered -function Instances.is_registered(name) - return Instances.serializer[name] ~= nil -end - ---- Registers the name of an instance group to allow for storing element instances --- @tparam string name the name of the instance group; must to unique --- @tparam[opt] function serializer function used to turn the element into a string --- serializer param - element LuaGuiElement - the gui element to be turned into a string --- serializer return - string - the category that the element will be added to like the player's name or force's name --- @treturn string the name that was added so it can be used as a variable -function Instances.register(name,serializer) - if _LIFECYCLE ~= _STAGE.control then - return error('Can only be called during the control stage', 2) - end - - if Instances.serializer[name] then - return error('Instances for '..name..' already exist.',2) - end - - serializer = type(serializer) == 'function' and serializer or true - - Instances.data[name] = {} - Instances.serializer[name] = serializer - - return name -end - ---- Adds an element to the instance group under the correct category; must be registered --- @tparam string name the name of the instance group to add the element to --- @tparam LuaGuiElement element the element to add the the instance group -function Instances.add_element(name,element) - if not Instances.serializer[name] then - return error('Invalid name for instance group: '..name,2) - end - - if Instances.has_categories(name) then - local category = Instances.serializer[name](element) - if not Instances.data[name][category] then Instances.data[name][category] = {} end - table.insert(Instances.data[name][category],element) - else - table.insert(Instances.data[name],element) - end -end - ---- Gets all element instances without first removing any invalid ones; used internally and must be registered --- @tparam string name the name of the instance group to get the instances of --- @tparam[opt] string category the category to get the instance from, not needed when no serializer function --- @treturn table the table of element instances of which some may be invalid -function Instances.get_elements_raw(name,category) - if not Instances.serializer[name] then - return error('Invalid name for instance group: '..name,2) - end - - if Instances.has_categories(name) then - return Instances.data[name][category] or {} - else - return Instances.data[name] - end -end - ---- Gets all valid element instances and has the option of running a callback on those that are valid --- @tparam string name the name of the instance group to get the instances of --- @tparam[opt] string category the category to get the instances of, not needed when no serializer function --- @tparam[opt] function callback when given the callback will be ran on all valid elements --- callback param - element LuaGuiElement - the current valid element --- @treturn table the table of element instances with all invalid ones removed -function Instances.get_valid_elements(name,category,callback) - if not Instances.serializer[name] then - return error('Invalid name for instance group: '..name,2) - end - - category = category or callback - local elements = Instances.get_elements_raw(name,category) - local serializer = Instances.has_categories(name) - - for key,element in pairs(elements) do - if not element or not element.valid then - elements[key] = nil - else - if serializer and callback then callback(element) - elseif category then category(element) end - end - end - - return elements -end -Instances.get_elements = Instances.get_valid_elements -Instances.apply_to_elements = Instances.get_valid_elements - ---- A version of add_element that does not require the group to be registered --- @tparam string name the name of the instance group to add the element to --- @tparam ?string|nil category the category to add the element to, can be nil but must still be given --- @tparam LuaGuiElement element the element to add to the instance group -function Instances.unregistered_add_element(name,category,element) - if not Instances.data[name] then Instances.data[name] = {} end - if category then - if not Instances.data[name][category] then Instances.data[name][category] = {} end - table.insert(Instances.data[name][category],element) - else - table.insert(Instances.data[name],element) - end -end - ---- A version of get_elements that does not require the group to be registered --- @tparam string name the name of the instance group to get the instances of --- @tparam ?string|nil category the category to get the instances of, can be nil but must still be given --- @tparam[opt] function callback when given will be called on all valid instances --- callback param - element LuaGuiElement - the current valid element --- @treturn table the table of element instances with all invalid ones removed -function Instances.unregistered_get_elements(name,category,callback) - local elements = Instances.data[name] - if elements and category then - elements = elements[category] - end - - if not elements then return {} end - - for key,element in pairs(elements) do - if not element or not element.valid then - elements[key] = nil - else - if callback then callback(element) end - end - end - - return elements -end -Instances.unregistered_apply_to_elements = Instances.runtime_get_elements - -return Instances \ No newline at end of file diff --git a/expcore/gui/left_flow.lua b/expcore/gui/left_flow.lua new file mode 100644 index 00000000..f41d8419 --- /dev/null +++ b/expcore/gui/left_flow.lua @@ -0,0 +1,270 @@ +--[[-- Core Module - Gui +- Used to define new gui elements and gui event handlers +@module Gui +]] + +local Gui = require 'expcore.gui.prototype' +local mod_gui = require 'mod-gui' --- @dep mod-gui + +local hide_left_flow = Gui.core_defines.hide_left_flow.name + +--- Left Flow. +-- @section leftFlow + +-- Triggered when a user changed the visibility of a left flow element by clicking a button +Gui.events.on_visibility_changed_by_click = 'on_visibility_changed_by_click' + +--- Contains the uids of the elements that will shown on the left flow and their join functions +-- @table left_elements +Gui.left_elements = {} + +--[[-- Gets the flow refered to as the left flow, each player has one left flow +@function Gui.get_left_flow(player) +@tparam LuaPlayer player the player that you want to get the left flow for +@treturn LuaGuiElement the left element flow + +@usage-- Geting your left flow +local left_flow = Gui.get_left_flow(game.player) + +]] +Gui.get_left_flow = mod_gui.get_frame_flow + +--[[-- Sets an element define to be drawn to the left flow when a player joins, includes optional check +@tparam[opt] ?boolean|function open_on_join called during first darw to decide if the element should be visible +@treturn table the new element define that is used to register events to this element + +@usage-- Adding the example button +example_flow_with_button:add_to_left_flow(true) + +]] +function Gui._prototype_element:add_to_left_flow(open_on_join) + Gui.left_elements[self.name] = open_on_join or false + return self +end + +--[[-- Styles a top flow button depending on the state given +@tparam LuaGuiElement the button element to style +@tparam boolean state The state the button is in + +@usage-- Sets the button to the visible style +Gui.left_toolbar_button_style(button, true) + +@usage-- Sets the button to the hidden style +Gui.left_toolbar_button_style(button, false) + +]] +function Gui.left_toolbar_button_style(button, state) + if state then + button.style = Gui.top_flow_button_visible_style + else + button.style = Gui.top_flow_button_style + end + button.style.minimal_width = 36 + button.style.height = 36 + button.style.padding = -2 +end + +--[[-- Creates a button on the top flow which will toggle the given element define, the define must exist in the left flow +@tparam string sprite the sprite that you want to use on the button +@tparam ?string|Concepts.LocalizedString tooltip the tooltip that you want the button to have +@tparam table element_define the element define that you want to have toggled by this button, define must exist on the left flow +@tparam[opt] function authenticator used to decide if the button should be visible to a player + +@usage-- Add a button to toggle a left element +local toolbar_button = +Gui.left_toolbar_button('entity/inserter', 'Nothing to see here', example_flow_with_button, function(player) + return player.admin +end) + +]] +function Gui.left_toolbar_button(sprite,tooltip,element_define,authenticator) + local button = Gui.element{ + type = 'sprite-button', + sprite = sprite, + tooltip = tooltip, + style = Gui.top_flow_button_style + } + :style{ + minimal_width = 36, + height = 36, + padding = -2 + } + :add_to_top_flow(authenticator) + + -- Add on_click handler to handle click events comming from the player + button:on_click(function(player,_,_) + local top_flow = Gui.get_top_flow(player) + local element = top_flow[button.name] + local visibility_state = Gui.toggle_left_element(player, element_define) + + -- Raise custom event that tells listening elements if the element has changed visibility by a player clicking + -- Used in warp gui to handle the keep open logic + button:raise_custom_event{ + name = Gui.events.on_visibility_changed_by_click, + element = element, + state = visibility_state + } + end) + + -- Add property to the left flow element with the name of the button + -- This is for the ability to reverse lookup the button from the left flow element + element_define.toolbar_button = button.name + return button +end + +--[[-- Draw all the left elements onto the left flow, internal use only with on join +@tparam LuaPlayer player the player that you want to draw the elements for + +@usage Draw all the left elements +Gui.draw_left_flow(player) + +]] +function Gui.draw_left_flow(player) + local left_flow = Gui.get_left_flow(player) + local hide_button = left_flow.gui_core_buttons[hide_left_flow] + local show_hide_button = false + + for name, open_on_join in pairs(Gui.left_elements) do + -- Draw the element to the left flow + local left_element = Gui.defines[name](left_flow) + + -- Check if it should be open by default + local visible = type(open_on_join) == 'boolean' and open_on_join or false + if type(open_on_join) == 'function' then + local success, err = pcall(open_on_join, player) + if not success then + error('There as been an error with an open on join hander for a gui element:\n\t'..err) + end + visible = err + end + + -- Set the visible state of the element + left_element.visible = visible + show_hide_button = show_hide_button or visible + + -- Get the assosiated element define + local element_define = Gui.defines[name] + local top_flow = Gui.get_top_flow(player) + + -- Check if the the element has a button attached + if element_define.toolbar_button then + -- Check if the topflow contains the button + local button = top_flow[element_define.toolbar_button] + if button then + -- Style the button + Gui.left_toolbar_button_style(button, visible) + end + end + end + + hide_button.visible = show_hide_button +end + +--[[-- Update the visible state of the hide button, can be used to check if any frames are visible +@tparam LuaPlayer player the player to update the left flow for +@treturn boolean true if any left element is visible + +@usage-- Check if any left elements are visible +local visible = Gui.update_left_flow(player) + +]] +function Gui.update_left_flow(player) + local left_flow = Gui.get_left_flow(player) + local hide_button = left_flow.gui_core_buttons[hide_left_flow] + for name, _ in pairs(Gui.left_elements) do + local left_element = left_flow[name] + if left_element.visible then + hide_button.visible = true + return true + end + end + hide_button.visible = false + return false +end + +--[[-- Hides all left elements for a player +@tparam LuaPlayer player the player to hide the elements for + +@usage-- Hide your left elements +Gui.hide_left_flow(game.player) + +]] +function Gui.hide_left_flow(player) + local top_flow = Gui.get_top_flow(player) + local left_flow = Gui.get_left_flow(player) + local hide_button = left_flow.gui_core_buttons[hide_left_flow] + + -- Set the visible state of all elements in the flow + hide_button.visible = false + for name,_ in pairs(Gui.left_elements) do + left_flow[name].visible = false + + -- Check if the the element has a toobar button attached + local element_define = Gui.defines[name] + if element_define.toolbar_button then + -- Check if the topflow contains the button + local button = top_flow[element_define.toolbar_button] + if button then + -- Style the button + Gui.left_toolbar_button_style(button, false) + -- Get the button define from the reverse lookup on the element + local button_define = Gui.defines[element_define.toolbar_button] + -- Raise the custom event if all of the top checks have passed + button_define:raise_custom_event{ + name = Gui.events.on_visibility_changed_by_click, + element = button, + state = false + } + end + end + end +end + +--[[-- Get the element define that is in the left flow, use in events without an element refrence +@tparam LuaPlayer player the player that you want to get the element for +@tparam table element_define the element that you want to get +@treturn LuaGuiElement the gui element linked to this define for this player + +@usage-- Get your left element +local frame = Gui.get_left_element(game.player, example_flow_with_button) + +]] +function Gui.get_left_element(player,element_define) + local left_flow = Gui.get_left_flow(player) + return left_flow[element_define.name] +end + +--[[-- Toggles the visible state of a left element for a given player, can be used to set the visible state +@tparam LuaPlayer player the player that you want to toggle the element for +@tparam table element_define the element that you want to toggle +@tparam[opt] boolean state with given will set the state, else state will be toggled +@treturn boolean the new visible state of the element + +@usage-- Toggle your example button +Gui.toggle_top_flow(game.player, example_flow_with_button) + +@usage-- Show your example button +Gui.toggle_top_flow(game.player, example_flow_with_button, true) + +]] +function Gui.toggle_left_element(player,element_define,state) + local left_flow = Gui.get_left_flow(player) + local top_flow = Gui.get_top_flow(player) + + -- Set the visible state + local element = left_flow[element_define.name] + if state == nil then state = not element.visible end + element.visible = state + Gui.update_left_flow(player) + + -- Check if the the element has a button attached + if element_define.toolbar_button then + -- Check if the topflow contains the button + local button = top_flow[element_define.toolbar_button] + if button then + -- Style the button + Gui.left_toolbar_button_style(button, state) + end + end + return state +end \ No newline at end of file diff --git a/expcore/gui/prototype.lua b/expcore/gui/prototype.lua index 790375aa..3c648c31 100644 --- a/expcore/gui/prototype.lua +++ b/expcore/gui/prototype.lua @@ -1,300 +1,414 @@ --[[-- Core Module - Gui - @module Gui - @alias Prototype +- Used to simplify gui creation using factory functions called element defines +@core Gui +@alias Gui + +@usage-- To draw your element you only need to call the factory function +-- You are able to pass any other arguments that are used in your custom functions but the first is always the parent element +local example_button_element = example_button(parent_element) + +@usage-- Making a factory function for a button with the caption "Example Button" +-- This method has all the same features as LuaGuiElement.add +local example_button = +Gui.element{ + type = 'button', + caption = 'Example Button' +} + +@usage-- Making a factory function for a button which is contained within a flow +-- This method is for when you still want to register event handlers but cant use the table method +local example_flow_with_button = +Gui.element(function(event_trigger,parent,...) + -- ... shows that all other arguments from the factory call are passed to this function + -- Here we are adding a flow which we will then later add a button to + local flow = + parent.add{ -- paraent is the element which is passed to the factory function + name = 'example_flow', + type = 'flow' + } + + -- Now we add the button to the flow that we created earlier + local element = + flow.add{ + name = event_trigger, -- event_trigger should be the name of any elements you want to trigger your event handlers + type = 'button', + caption = 'Example Button' + } + + -- You must return a new element, this is so styles can be applied and returned to the caller + -- You may return any of your elements that you added, consider the context in which it will be used for which should be returned + return element +end) + +@usage-- Styles can be added to any element define, simplest way mimics LuaGuiElement.style[key] = value +local example_button = +Gui.element{ + type = 'button', + caption = 'Example Button', + style = 'forward_button' -- factorio styles can be applied here +} +:style{ + height = 25, -- same as element.style.height = 25 + width = 100 -- same as element.style.width = 25 +} + +@usage-- Styles can also have a custom function when the style is dynamic and depends on other factors +-- Use this method if your style is dynamic and depends on other factors +local example_button = +Gui.element{ + type = 'button', + caption = 'Example Button', + style = 'forward_button' -- factorio styles can be applied here +} +:style(function(style,element,...) + -- style is the current style object for the elemenent + -- element is the element that is being changed + -- ... shows that all other arguments from the factory call are passed to this function + local player = game.players[element.player_index] + style.height = 25 + style.width = 100 + style.font_color = player.color +end) + +@usage-- You are able to register event handlers to your elements, these can be factorio events or custom ones +-- All events are checked to be valid before raising any handlers, this means element.valid = true and player.valid = true +Gui.element{ + type = 'button', + caption = 'Example Button' +} +:on_click(function(player,element,event) + -- player is the player who interacted with the element to cause the event + -- element is a refrence to the element which caused the event + -- event is a raw refrence to the event data if player and element are not enough + player.print('Clicked: '..element.name) +end) + +@usage-- Example from core_defines, Gui.core_defines.hide_left_flow, called like: hide_left_flow(parent_element) +--- Button which hides the elements in the left flow, shows inside the left flow when frames are visible +-- @element hide_left_flow +local hide_left_flow = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/close_black', + style = 'tool_button', + tooltip = {'expcore-gui.left-button-tooltip'} +} +:style{ + padding = -3, + width = 18, + height = 20 +} +:on_click(function(player,_,_) + Gui.hide_left_flow(player) +end) + +@usage-- Eample from defines, Gui.alignment, called like: Gui.alignment(parent, name, horizontal_align, vertical_align) +-- Notice how _ are used to blank arguments that are not needed in that context and how they line up with above +Gui.alignment = +Gui.element(function(_,parent,name,_,_) + return parent.add{ + name = name or 'alignment', + type = 'flow', + } +end) +:style(function(style,_,_,horizontal_align,vertical_align) + style.padding = {1,2} + style.vertical_align = vertical_align or 'center' + style.horizontal_align = horizontal_align or 'right' + style.vertically_stretchable = style.vertical_align ~= 'center' + style.horizontally_stretchable = style.horizontal_align ~= 'center' +end) + ]] ---- Prototype. --- Used to create new gui prototypes see elements and concepts --- @section prototype +local Event = require 'utils.event' --- @dep utils.event ---[[ - >>>> Functions - Constructor.event(event_name) --- Creates a new function to add functions to an event handler - Constructor.extend(new_prototype) --- Extents a prototype with the base functions of all gui prototypes, no metatables - Constructor.store(sync,callback) --- Creates a new function which adds a store to a gui define - Constructor.setter(value_type,key,second_key) --- Creates a setter function that checks the type when a value is set +local Gui = { + --- The current highest uid that is being used by a define, will not increase during runtime + -- @field uid + uid = 0, + --- String indexed table used to avoid conflict with custom event names, similar to how defines.events works + -- @table events + events = {}, + --- Uid indexed array that stores all the factory functions that were defined, no new values will be added during runtime + -- @table defines + defines = {}, + --- An string indexed table of all the defines which are used by the core of the gui system, used for internal refrence + -- @table core_defines + core_defines = {}, + --- Used to store the file names where elements were defined, this can be useful to find the uid of an element, mostly for debuging + -- @table file_paths + file_paths = {}, + --- Used to store extra infomation about elements as they get defined such as the params used and event handlers registered to them + -- @table debug_info + debug_info = {}, + --- The prototype used to store the functions of an element define + -- @table _prototype_element + _prototype_element = {}, + --- The prototype metatable applied to new element defines + -- @table _mt_element + _mt_element = { + __call = function(self,parent,...) + local element = self._draw(self.name,parent,...) + if self._style then self._style(element.style,element,...) end + return element + end + } +} - Prototype:uid() --- Gets the uid for the element define - Prototype:debug_name(value) --- Sets a debug alias for the define - Prototype:set_caption(value) --- Sets the caption for the element define - Prototype:set_tooltip(value) --- Sets the tooltip for the element define - Prototype:set_style(style,callback) --- Sets the style for the element define - Prototype:set_embedded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function +Gui._mt_element.__index = Gui._prototype_element - Prototype:set_pre_authenticator --- Sets an authenticator that blocks the draw function if check fails - Prototype:set_post_authenticator --- Sets an authenticator that disables the element if check fails +--- Element Define. +-- @section elementDefine - Prototype:raise_event(event_name,...) --- Raises a custom event for this define, any number of params can be given - Prototype:draw_to(element,...) --- The main function for defines, when called will draw an instance of this define to the given element +--[[-- Used to define new elements for your gui, can be used like LuaGuiElement.add or a custom function +@tparam ?table|function element_define the define information for the gui element, same data as LuaGuiElement.add, or a custom function may be used +@treturn table the new element define, this can be considered a factory for the element which can be called to draw the element to any other element + +@usage-- Using element defines like LuaGuiElement.add +-- This returns a factory function to draw a button with the caption "Example Button" +local example_button = +Gui.element{ + type = 'button', + caption = 'Example Button' +} + +@usage-- Using element defines with a custom factory function +-- This method can be used if you still want to be able register event handlers but it is too complex to be compatible with LuaGuiElement.add +local example_flow_with_button = +Gui.element(function(event_trigger,parent,...) + -- ... shows that all other arguments from the factory call are passed to this function + -- parent is the element which was passed to the factory function where you should add your new element + -- here we are adding a flow which we will then later add a button to + local flow = + parent.add{ + name = 'example_flow', + type = 'flow' + } + + -- event_trigger should be the name of any elements you want to trigger your event handlers, such as on_click or on_state_changed + -- now we add the button to the flow that we created earlier + local element = + flow.add{ + name = event_trigger, + type = 'button', + caption = 'Example Button' + } + + -- you must return your new element, this is so styles can be applied and returned to the caller + -- you may return any of your elements that you add, consider the context in which it will be used for what should be returned + return element +end) - Prototype:get_store(category) --- Gets the value in this elements store, category needed if serializer function used - Prototype:set_store(category,value) --- Sets the value in this elements store, category needed if serializer function used - Prototype:clear_store(category) --- Sets the value in this elements store to nil, category needed if serializer function used ]] -local Game = require 'utils.game' --- @dep utils.game -local Store = require 'expcore.store' --- @dep expcore.store -local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances +function Gui.element(element_define) + -- Set the metatable to allow access to register events + local element = setmetatable({}, Gui._mt_element) -local Constructor = {} -local Prototype = {} + -- Increment the uid counter + local uid = Gui.uid + 1 + Gui.uid = uid + local name = tostring(uid) + element.name = name + Gui.debug_info[name] = { draw = 'None', style = 'None', events = {} } ---- Creates a new function to add functions to an event handler --- @tparam string event_name the name of the event that callbacks will be added to --- @treturn function the function used to register handlers -function Constructor.event(event_name) - --- Adds a callback as a handler for an event - -- @tparam table self the gui define being acted on - -- @tparam function callback the function that will be added as a handler for the event - -- @treturn table self returned to allowing chaining of functions - return function(self,callback) - if type(callback) ~= 'function' then - return error('Event callback for '..event_name..' must be a function',2) + -- Add the defination function + if type(element_define) == 'table' then + Gui.debug_info[name].draw = element_define + element_define.name = name + element._draw = function(_,parent) + return parent.add(element_define) end - - local handlers = self.events[event_name] - if not handlers then - handlers = {} - self.events[event_name] = handlers - end - - handlers[#handlers+1] = callback - return self - end -end - ---- Extents a prototype with the base functions of all gui prototypes, no metatables --- @tparam table new_prototype the prototype that you want to add the functions to --- @treturn table the same prototype but with the new functions added -function Constructor.extend(new_prototype) - for key,value in pairs(Prototype) do - if type(value) == 'table' then - new_prototype[key] = table.deepcopy(value) - else - new_prototype[key] = value - end - end - for key,value in pairs(new_prototype) do - if value == Constructor.event then - new_prototype[key] = Constructor.event(key) - end - end - return new_prototype -end - ---- Creates a new function which adds a store to a gui define --- @tparam function callback the function called when needing to update the value of an element --- @treturn function the function that will add a store for this define -function Constructor.store(callback) - --- Adds a store for the define that is shared between all instances of the define in the same category, serializer is a function that returns a string - -- @tparam self table the gui define being acted on - -- @tparam[opt] function serializer function used to determine the category of a LuaGuiElement, when omitted all share one single category - -- serializer param - LuaGuiElement element - the element that needs to be converted - -- serializer return - string - a deterministic string that references to a category such as player name or force name - -- @treturn self the element define to allow chaining - return function(self,serializer) - if self.store then return end - serializer = serializer or function() return '' end - - self.store = Store.register(serializer) - - Instances.register(self.name,serializer) - - Store.watch(self.store,function(value,category) - self:raise_event('on_store_update',value,category) - - if Instances.is_registered(self.name) then - Instances.apply_to_elements(self.name,category,function(element) - callback(self,element,value) - end) - end - end) - - return self - end -end - ---- Creates a setter function that checks the type when a value is set --- @tparam string value_type the type that the value should be when it is set --- @tparam string key the key of the define that will be set --- @tparam[opt] string second_key allows for setting of a key in a sub table --- @treturn function the function that will check the type and set the value -function Constructor.setter(value_type,key,second_key) - local display_message = 'Gui define '..key..' must be of type '..value_type - if second_key then - display_message = 'Gui define '..second_key..' must be of type '..value_type - end - - local locale = false - if value_type == 'locale-string' then - locale = true - value_type = 'table' - end - - return function(self,value) - local v_type = type(value) - if v_type ~= value_type and (not locale or v_type ~= 'string') then - error(display_message,2) - end - - if second_key then - self[key][second_key] = value - else - self[key] = value - end - - return self - end -end - ---- Gets the uid for the element define --- @treturn string the uid of this element define -function Prototype:uid() - return self.name -end - ---- Sets a debug alias for the define --- @tparam string name the debug name for the element define that can be used to get this element define --- @treturn self the element define to allow chaining -Prototype.debug_name = Constructor.setter('string','debug_name') - ---- Sets the caption for the element define --- @tparam string caption the caption that will be drawn with the element --- @treturn self the element define to allow chaining -Prototype.set_caption = Constructor.setter('locale-string','draw_data','caption') - ---- Sets the tooltip for the element define --- @tparam string tooltip the tooltip that will be displayed for this element when drawn --- @treturn self the element define to allow chaining -Prototype.set_tooltip = Constructor.setter('locale-string','draw_data','tooltip') - ---- Sets an authenticator that blocks the draw function if check fails --- @tparam function callback the function that will be ran to test if the element should be drawn or not --- callback param - LuaPlayer player - the player that the element is being drawn to --- callback param - string define_name - the name of the define that is being drawn --- callback return - boolean - false will stop the element from being drawn --- @treturn self the element define to allow chaining -Prototype.set_pre_authenticator = Constructor.setter('function','pre_authenticator') - ---- Sets an authenticator that disables the element if check fails --- @tparam function callback the function that will be ran to test if the element should be enabled or not --- callback param - LuaPlayer player - the player that the element is being drawn to --- callback param - string define_name - the name of the define that is being drawn --- callback return - boolean - false will disable the element --- @treturn self the element define to allow chaining -Prototype.set_post_authenticator = Constructor.setter('function','post_authenticator') - ---- Registers a callback to the on_draw event --- @tparam function callback --- callback param - LuaPlayer player - the player that the element was drawn to --- callback param - LuaGuiElement element - the element that was drawn --- callback param - any ... - any other params passed by the draw_to function -Prototype.on_draw = Constructor.event('on_draw') - ---- Registers a callback to the on_style_update event --- @tparam function callback --- callback param - LuaStyle style - the style that was changed and/or needs changing -Prototype.on_style_update = Constructor.event('on_style_update') - ---- Sets the style for the element define --- @tparam string style the style that will be used for this element when drawn --- @tparam[opt] function callback function is called when element is drawn to alter its style --- @treturn self the element define to allow chaining -function Prototype:set_style(style,callback) - self.draw_data.style = style - if callback then - self:on_style_update(callback) - end - return self -end - ---- Sets the element to be drawn inside a nameless flow, can be given a name using a function --- @tparam ?boolean|function state when true a padless flow is created to contain the element --- @treturn self the element define to allow chaining -function Prototype:set_embedded_flow(state) - if state == false or type(state) == 'function' then - self.embedded_flow = state else - self.embedded_flow = true + Gui.debug_info[name].draw = 'Function' + element._draw = element_define + end + + -- Add the define to the base module + local file_path = debug.getinfo(2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) + Gui.file_paths[name] = file_path + Gui.defines[name] = element + + -- Return the element so event handers can be accessed + return element +end + +--[[-- Used to extent your element define with a style factory, this style will be applied to your element when created, can also be a custom function +@tparam ?table|function style_define style table where each key and value pair is treated like LuaGuiElement.style[key] = value, a custom function can be used +@treturn table the element define is returned to allow for event handlers to be registered + +@usage-- Using the table method of setting the style +local example_button = +Gui.element{ + type = 'button', + caption = 'Example Button', + style = 'forward_button' -- factorio styles can be applied here +} +:style{ + height = 25, -- same as element.style.height = 25 + width = 100 -- same as element.style.width = 25 +} + +@usage-- Using the function method to set the style +-- Use this method if your style is dynamic and depends on other factors +local example_button = +Gui.element{ + type = 'button', + caption = 'Example Button', + style = 'forward_button' -- factorio styles can be applied here +} +:style(function(style,element,...) + -- style is the current style object for the elemenent + -- element is the element that is being changed + -- ... shows that all other arguments from the factory call are passed to this function + local player = game.players[element.player_index] + style.height = 25 + style.width = 100 + style.font_color = player.color +end) + +]] +function Gui._prototype_element:style(style_define) + -- Add the defination function + if type(style_define) == 'table' then + Gui.debug_info[self.name].style = style_define + self._style = function(style) + for key,value in pairs(style_define) do + style[key] = value + end + end + else + Gui.debug_info[self.name].style = 'Function' + self._style = style_define + end + + -- Return the element so event handers can be accessed + return self +end + +--[[-- Set the handler which will be called for a custom event, only one handler can be used per event per element +@tparam string event_name the name of the event you want to handler to be called on, often from Gui.events +@tparam function handler the handler that you want to be called when the event is raised +@treturn table the element define so more handleres can be registered + +@usage-- Register a handler to "my_custom_event" for this element +element_deinfe:on_custom_event('my_custom_event', function(event) + event.player.print(player.name) +end) + +]] +function Gui._prototype_element:on_custom_event(event_name,handler) + table.insert(Gui.debug_info[self.name].events,event_name) + Gui.events[event_name] = event_name + self[event_name] = handler + return self +end + +--[[-- Raise the handler which is attached to an event; external use should be limited to custom events +@tparam table event the event table passed to the handler, must contain fields: name, element +@treturn table the element define so more events can be raised + +@usage Raising a custom event +element_define:raise_custom_event{ + name = 'my_custom_event', + element = element +} + +]] +function Gui._prototype_element:raise_custom_event(event) + -- Check the element is valid + local element = event.element + if not element or not element.valid then + return self + end + + -- Get the event handler for this element + local handler = self[event.name] + if not handler then + return self + end + + -- Get the player for this event + local player_index = event.player_index or element.player_index + local player = game.players[player_index] + if not player or not player.valid then + return self + end + event.player = player + + local success, err = pcall(handler,player,element,event) + if not success then + error('There as been an error with an event handler for a gui element:\n\t'..err) end return self end ---- Raises a custom event for this define, any number of params can be given --- @tparam string event_name the name of the event that you want to raise --- @tparam any ... any params that you want to pass to the event --- @treturn number the number of handlers that were registered -function Prototype:raise_event(event_name,...) - local handlers = self.events[event_name] - if handlers then - for _,handler in pairs(handlers) do - handler(...) - end +-- This function is used to link element define events and the events from the factorio api +local function event_handler_factory(event_name) + Event.add(event_name, function(event) + local element = event.element + if not element or not element.valid then return end + local element_define = Gui.defines[element.name] + element_define:raise_custom_event(event) + end) + + return function(self,handler) + table.insert(Gui.debug_info[self.name].events,debug.getinfo(1, "n").name) + self[event_name] = handler + return self end - return handlers and #handlers or 0 end ---- The main function for defines, when called will draw an instance of this define to the given element --- what is drawn is based on the data in draw_data which is set using other functions --- @tparam LuaGuiElement element the element that the define will draw a instance of its self onto --- @treturn LuaGuiElement the new element that was drawn -function Prototype:draw_to(element,...) - local name = self.name - if element[name] then return end - local player = Game.get_player_by_index(element.player_index) +--- Element Events. +-- @section elementEvents - if self.pre_authenticator then - if not self.pre_authenticator(player,self.name) then return end - end +--- Called when the player opens a GUI. +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_opened = event_handler_factory(defines.events.on_gui_opened) - if self.embedded_flow then - local embedded_name - if type(self.embedded_flow) == 'function' then - embedded_name = self.embedded_flow(element,...) - end - element = element.add{type='flow',name=embedded_name} - element.style.padding = 0 - end +--- Called when the player closes the GUI they have open. +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_closed = event_handler_factory(defines.events.on_gui_closed) - local new_element = element.add(self.draw_data) +--- Called when LuaGuiElement is clicked. +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_click = event_handler_factory(defines.events.on_gui_click) - self:raise_event('on_style_update',new_element.style) +--- Called when a LuaGuiElement is confirmed, for example by pressing Enter in a textfield. +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_confirmed = event_handler_factory(defines.events.on_gui_confirmed) - if self.post_authenticator then - new_element.enabled = self.post_authenticator(player,self.name) - end +--- Called when LuaGuiElement checked state is changed (related to checkboxes and radio buttons). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_checked_changed = event_handler_factory(defines.events.on_gui_checked_state_changed) - if Instances.is_registered(self.name) then - Instances.add_element(self.name,new_element) - end +--- Called when LuaGuiElement element value is changed (related to choose element buttons). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_elem_changed = event_handler_factory(defines.events.on_gui_elem_changed) - self:raise_event('on_draw',player,new_element,...) +--- Called when LuaGuiElement element location is changed (related to frames in player.gui.screen). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_location_changed = event_handler_factory(defines.events.on_gui_location_changed) - return new_element -end +--- Called when LuaGuiElement selected tab is changed (related to tabbed-panes). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_tab_changed = event_handler_factory(defines.events.on_gui_selected_tab_changed) ---- Gets the value in this elements store, category needed if serializer function used --- @tparam string category[opt] the category to get such as player name or force name --- @treturn any the value that is stored for this define -function Prototype:get_store(category) - if not self.store then return end - return Store.get(self.store,category) -end +--- Called when LuaGuiElement selection state is changed (related to drop-downs and listboxes). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_selection_changed = event_handler_factory(defines.events.on_gui_selection_state_changed) ---- Sets the value in this elements store, category needed if serializer function used --- @tparam string category[opt] the category to get such as player name or force name --- @tparam any value the value to set for this define, must be valid for its type ie for checkbox etc --- @treturn boolean true if the value was set -function Prototype:set_store(category,value) - if not self.store then return end - return Store.set(self.store,category,value) -end +--- Called when LuaGuiElement switch state is changed (related to switches). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_switch_changed = event_handler_factory(defines.events.on_gui_switch_state_changed) ---- Sets the value in this elements store to nil, category needed if serializer function used --- @tparam[opt] string category the category to get such as player name or force name --- @treturn boolean true if the value was set -function Prototype:clear_store(category) - if not self.store then return end - return Store.clear(self.store,category) -end +--- Called when LuaGuiElement text is changed by the player. +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_text_changed = event_handler_factory(defines.events.on_gui_text_changed) -return Constructor \ No newline at end of file +--- Called when LuaGuiElement slider value is changed (related to the slider element). +-- @tparam function handler the event handler which will be called +Gui._prototype_element.on_value_changed = event_handler_factory(defines.events.on_gui_value_changed) + +-- Module return +return Gui \ No newline at end of file diff --git a/expcore/gui/require.lua b/expcore/gui/require.lua new file mode 100644 index 00000000..26fcf0d6 --- /dev/null +++ b/expcore/gui/require.lua @@ -0,0 +1,8 @@ +local Gui = require 'expcore.gui.prototype' +require 'expcore.gui.core_defines' +require 'expcore.gui.top_flow' +require 'expcore.gui.left_flow' +require 'expcore.gui.helper_functions' +require 'expcore.gui.defines' + +return Gui \ No newline at end of file diff --git a/expcore/gui/test.lua b/expcore/gui/test.lua deleted file mode 100644 index 37cc54f8..00000000 --- a/expcore/gui/test.lua +++ /dev/null @@ -1,663 +0,0 @@ ---[[-- Core Module - Gui - @module Gui - @alias tests -]] - ---- Test. --- This file creates a test gui that is used to test every input method --- note that this does not cover every permutation only features in independence --- for example store in most cases is just by player name, but other store methods are tested with checkbox --- @section test - -local Gui = require 'expcore.gui' --- @dep expcore.gui -local format_chat_colour,table_keys = ext_require('expcore.common','format_chat_colour','table_keys') --- @dep expcore.common -local Colors = require 'resources.color_presets' --- @dep resources.color_presets -local Event = require 'utils.event' --- @dep utils.event -local Store = require 'expcore.store' --- @dep expcore.store - -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 -]] - -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) - ---[[ - Center Frame Tests - > Main test gui - Main test gui triggers all other tests -]] - -local test_gui = -Gui.new_center_frame('gui-test-open') -:set_caption('Open Test Gui') -:set_tooltip('Main test gui triggers all other tests') -:set_post_authenticator(function(player,button_name) - return global.show_test_gui -end) - -:on_creation(function(player,frame) - 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) - ---[[ - Left Frame Test - > Left frame which holds all online player names, updates when player leaves or joins -]] - -local left_frame = -Gui.new_left_frame('test-left-frame') -:set_caption('Test Left Gui') -:set_tooltip('Left frame which holds all online player names, updates when player leaves or joins') -:set_post_authenticator(function(player,button_name) - return global.show_test_gui -end) - -:set_open_by_default() -:on_creation(function(_player,frame) - for _,player in pairs(game.connected_players) do - frame.add{ - type='label', - caption=player.name - } - end -end) - -Event.add(defines.events.on_player_joined_game,left_frame 'update_all') -Event.add(defines.events.on_player_left_game,left_frame 'update_all') - ---[[ - Popup Test - > Allows opening a popup which contains the players name and tick it was opened -]] - -local test_popup = -Gui.new_popup('test-popup') -:on_creation(function(player,frame) - frame.add{ - type='label', - caption=player.name - } - frame.add{ - type='label', - caption=game.tick - } -end) - -Gui.new_toolbar_button('test-popup-open') -:set_caption('Test Popup') -:set_tooltip('Allows opening a popup which contains the players name and tick it was opened') -:set_post_authenticator(function(player,button_name) - return global.show_test_gui -end) -:on_click(function(player,element) - test_popup(player,300) -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('Checkbox store force') -:set_caption('Checkbox Store Force') -:add_store(Gui.categorize_by_force) -: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.categorize_by_player) -:on_element_update(function(player,element,state) - player.print('Checkbox store player: '..tostring(state)) -end) - -tests.Checkboxes = { - ['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.categorize_by_player) -:on_element_update(function(player,element,state) - player.print('Radiobutton store: '..tostring(state)) -end) - -local radiobutton_option_set = -Gui.new_radiobutton_option_set(function(value,category) - game.print('Radiobutton option set for: '..category..' is now: '..tostring(value)) -end,Gui.categorize_by_player) - -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.categorize_by_player) -: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.categorize_by_player) -: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.categorize_by_player) -: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.categorize_by_player) -:on_element_update(function(player,element,value) - player.print('Dropdown store: '..tostring(value)) -end) - -tests["List Boxes"] = { - ['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('Slider 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('Slider store default') -:add_store(Gui.categorize_by_player) -: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('Slider 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('Slider 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('Slider 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('Slider store label') -:enable_auto_draw_label() -:add_store(Gui.categorize_by_player) -: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.categorize_by_player) -: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.categorize_by_player) -: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 -} - ---[[ - Progress bar tests - > Simple -- Progress bar that fills every 2 seconds - > Store -- Progress bar that fills every 5 seconds with synced value - > Reverse -- Progress bar that decreases every 2 seconds -]] - -local progressbar_one = -Gui.new_progressbar('test-prog-one') -:set_default_maximum(120) -:on_complete(function(player,element,reset_element) - reset_element() -end) - -local progressbar_two = -Gui.new_progressbar('test-prog-one') -:set_default_maximum(300) -:add_store(Gui.categorize_by_force) -:on_complete(function(player,element,reset_element) - reset_element() -end) -:on_store_complete(function(category,reset_store) - reset_store() -end) - -local progressbar_three = -Gui.new_progressbar('test-prog-one') -:set_default_maximum(120) -:use_count_down() -:on_complete(function(player,element,reset_element) - reset_element() -end) - -Event.add(defines.events.on_tick,function() - progressbar_one:increment() - progressbar_three:decrement() - local categories = Store.get(progressbar_two.store) or {} - for category,_ in pairs(categories) do - progressbar_two:increment(1,category) - end -end) - -tests["Progress Bars"] = { - ['Simple']=progressbar_one, - ['Store']=progressbar_two, - ['Reverse']=progressbar_three -} \ No newline at end of file diff --git a/expcore/gui/top_flow.lua b/expcore/gui/top_flow.lua new file mode 100644 index 00000000..d9291d0f --- /dev/null +++ b/expcore/gui/top_flow.lua @@ -0,0 +1,104 @@ +--[[-- Core Module - Gui +- Controls the elements on the top flow +@module Gui +]] + +local Gui = require 'expcore.gui.prototype' +local mod_gui = require 'mod-gui' --- @dep mod-gui + +local hide_top_flow = Gui.core_defines.hide_top_flow.name +local show_top_flow = Gui.core_defines.show_top_flow.name + +--- Top Flow. +-- @section topFlow + +--- Contains the uids of the elements that will shown on the top flow and their auth functions +-- @table top_elements +Gui.top_elements = {} + +--- The style that should be used for buttons on the top flow +-- @field Gui.top_flow_button_style +Gui.top_flow_button_style = mod_gui.button_style + +--- The style that should be used for buttons on the top flow when their flow is visible +-- @field Gui.top_flow_button_visible_style +Gui.top_flow_button_visible_style = 'menu_button_continue' + +--[[-- Gets the flow refered to as the top flow, each player has one top flow +@function Gui.get_top_flow(player) +@tparam LuaPlayer player the player that you want to get the flow for +@treturn LuaGuiElement the top element flow + +@usage-- Geting your top flow +local top_flow = Gui.get_top_flow(game.player) + +]] +Gui.get_top_flow = mod_gui.get_button_flow + +--[[-- Sets an element define to be drawn to the top flow when a player joins, includes optional authenticator +@tparam[opt] function authenticator called during toggle or update to decide weather the element should be visible +@treturn table the new element define to allow event handlers to be registered + +@usage-- Adding an element to the top flow on join +example_button:add_to_top_flow(function(player) + -- example button will only be shown if the player is an admin + -- note button will not update its state when player.admin is changed Gui.update_top_flow must be called for this + return player.admin +end) + +]] +function Gui._prototype_element:add_to_top_flow(authenticator) + Gui.top_elements[self.name] = authenticator or true + return self +end + +--[[-- Updates the visible state of all the elements on the players top flow, uses authenticator +@tparam LuaPlayer player the player that you want to update the top flow for + +@usage-- Update your top flow +Gui.update_top_flow(game.player) + +]] +function Gui.update_top_flow(player) + local top_flow = Gui.get_top_flow(player) + local hide_button = top_flow[hide_top_flow] + local is_visible = hide_button.visible + + -- Set the visible state of all elements in the flow + for name, authenticator in pairs(Gui.top_elements) do + -- Ensure the element exists + local element = top_flow[name] + if not element then + element = Gui.defines[name](top_flow) + end + + -- Set the visible state + element.visible = is_visible and authenticator(player) or false + end +end + +--[[-- Toggles the visible state of all the elements on a players top flow, effects all elements +@tparam LuaPlayer player the player that you want to toggle the top flow for +@tparam[opt] boolean state if given then the state will be set to this +@treturn boolean the new visible state of the top flow + +@usage-- Toggle your flow +Gui.toggle_top_flow(game.player) + +@usage-- Open your top flow +Gui.toggle_top_flow(game.player,true) + +]] +function Gui.toggle_top_flow(player,state) + -- Get the top flow and hide button + local top_flow = Gui.get_top_flow(player) + if state == nil then state = not top_flow.visible end + + -- Change the visiblty of the flow + local left_flow = Gui.get_left_flow(player) + local show_button = left_flow.gui_core_buttons[show_top_flow] + show_button.visible = not state + top_flow.visible = state + + return state +end \ No newline at end of file diff --git a/expcore/store.lua b/expcore/store.lua index f58e41b9..735ccef4 100644 --- a/expcore/store.lua +++ b/expcore/store.lua @@ -27,7 +27,7 @@ local player_scores = Store.register(function(player) -- Use player name as the end) -- When any key in the store is changed this function will trigger -Store.watch(player_scores,function(value,key) +Store.watch(player_scores,function(value,key,old_value) game.print(key..' now has a score of '..value) end) @@ -175,7 +175,7 @@ local player_scores = Store.register(function(player) end) -- Register the watcher so that when we change the value the message is printed -Store.watch(player_scores,function(value,key) +Store.watch(player_scores,function(value,key,old_value) game.print(key..' now has a score of '..value) end) @@ -274,18 +274,21 @@ Store.clear(player_scores) ]] function Store.clear(store,key) key = Store.validate(store,key,2) + local old_value -- Check if there is a key being used if key then if type(data_store[store]) == 'table' then + old_value = data_store[store][key] data_store[store][key] = nil end else + old_value = data_store[store] data_store[store] = nil end -- Trigger any watch functions - Store.raw_trigger(store,key,nil) + Store.raw_trigger(store,key,nil,old_value) end --[[-- Used to set the data in a store, will trigger any watchers, key is optional depending on if you are using them @@ -325,19 +328,22 @@ function Store.set(store,key,value) -- Check the store is valid key = Store.validate(store,key,2) + local old_value -- If there is a key being used then the store must be a able if key then if type(data_store[store]) ~= 'table' then data_store[store] = {_value = data_store[store]} end + old_value = data_store[store][key] data_store[store][key] = value else + old_value = data_store[store] data_store[store] = value end -- Trigger any watchers - Store.raw_trigger(store,key,value) + Store.raw_trigger(store,key,value,old_value) end --[[-- Used to update the data in a store, use this with tables, will trigger any watchers, key is optional depending on if you are using them @@ -386,7 +392,7 @@ function Store.update(store,key,updater) -- Check the store is valid key = Store.validate(store,key,2) - local value + local value, old_value -- If a key is used then the store must be a table if key then @@ -397,6 +403,7 @@ function Store.update(store,key,updater) -- Call the updater and if it returns a value then set this value local rtn = updater(data_store[store][key]) if rtn then + old_value = data_store[store][key] data_store[store][key] = rtn end value = data_store[store][key] @@ -405,6 +412,7 @@ function Store.update(store,key,updater) -- Call the updater and if it returns a value then set this value local rtn = updater(data_store[store]) if rtn then + old_value = data_store[store][key] data_store[store] = rtn end value = data_store[store] @@ -412,7 +420,7 @@ function Store.update(store,key,updater) end -- Trigger any watchers - Store.raw_trigger(store,key,value) + Store.raw_trigger(store,key,value,old_value) end --[[-- Used to update all values that are in a store, similar to Store.update but acts on all keys at once, will trigger watchers for every key present @@ -455,7 +463,7 @@ function Store.map(store,updater) if rtn then data[key] = rtn end - Store.raw_trigger(store,key,data[key]) + Store.raw_trigger(store,key,data[key],value) end end @@ -476,9 +484,10 @@ function Store.trigger(store,key) -- Get the data from the data store local data = data_store[store] if key then - Store.raw_trigger(store,key,data[key]) + data = data[key] + Store.raw_trigger(store,key,data,data) else - Store.raw_trigger(store,key,data) + Store.raw_trigger(store,key,data,data) end end @@ -486,6 +495,7 @@ end @tparam number store the uid of the store that you want to trigger @tparam[opt] ?string|any key the key that you want to trigger, must be a string unless you have a serializer @tparam[opt] any value the new value that is at this key or store, passed directly to the watcher +@tparam[opt] any old_value the old value that was at this key or store often the same if value is a table, passed directly to the watcher @usage-- Triggering a manule call of the watchers -- The type of store we use does not really matter for this as long as you pass it what you watchers are expecting @@ -493,16 +503,16 @@ local scenario_diffculty = Store.register() -- Trigger the watchers with a fake change of diffculty -- This is mostly used internally but it can be useful in other cases -Store.raw_trigger(scenario_diffculty,nil,'normal') +Store.raw_trigger(scenario_diffculty,nil,'normal','normal') ]] -function Store.raw_trigger(store,key,value) +function Store.raw_trigger(store,key,value,old_value) key = Store.validate(store,key,2) -- Get the watchers and then loop over them local watchers = Store.watchers[store] or {} for _,watcher in pairs(watchers) do - local success, err = pcall(watcher,value,key) + local success, err = pcall(watcher,value,key,old_value) if not success then error('Store watcher casued an error:\n\t'..err) end diff --git a/locale/en/gui.cfg b/locale/en/gui.cfg index 91d1faf2..440f485d 100644 --- a/locale/en/gui.cfg +++ b/locale/en/gui.cfg @@ -46,6 +46,8 @@ data-caption-avg-launch-n=Average Time __1__ data-tooltip-avg-launch-n=The average amount of time taken to launch the last __1__ rockets data-caption-milestone-n=Milestone __1__ data-tooltip-milestone-n=Time taken to each __1__ rockets +data-caption-milestone-next=N/A +data-tooltip-milestone-next=Not yet achieved progress-x-pos=X __1__ progress-y-pos=Y __1__ progress-label-tooltip=View on map @@ -91,7 +93,7 @@ cancel-tooltip=Discard changes edit-tooltip=Currently being edited by: __1__ edit-tooltip-none=Currently being edited by: Nobody discard-tooltip=Remove warp -timer-tooltip=Warp charge, charge time __1__ seconds +timer-tooltip=Warp cooldown takes __1__ seconds goto-tooltip=Go to x __1__ y __2__ goto-disabled=You must be on a warp point and have a full charge to warp goto-edit=Edit warp icon diff --git a/modules/commands/debug.lua b/modules/commands/debug.lua index f0be73ba..e29786a6 100644 --- a/modules/commands/debug.lua +++ b/modules/commands/debug.lua @@ -9,6 +9,6 @@ local Commands = require 'expcore.commands' --- @dep expcore.commands --- Opens the debug pannel for viewing tables. -- @command debug Commands.new_command('debug','Opens the debug pannel for viewing tables.') -:register(function(player,raw) +:register(function(player) DebugView.open_dubug(player) end) \ No newline at end of file diff --git a/modules/control/tasks.lua b/modules/control/tasks.lua index 6b2d9630..0806efde 100644 --- a/modules/control/tasks.lua +++ b/modules/control/tasks.lua @@ -89,8 +89,8 @@ Tasks.remove_task(task_id) function Tasks.remove_task(task_id) local task = Store.get(task_store,task_id) local force_name = task.force_name - Store.clear(task_store,task_id) table.remove_element(force_tasks[force_name],task_id) + Store.clear(task_store,task_id) end --[[-- Update the message and last edited information for a task diff --git a/modules/control/warps.lua b/modules/control/warps.lua index ad503c3a..8958c833 100644 --- a/modules/control/warps.lua +++ b/modules/control/warps.lua @@ -150,7 +150,7 @@ function Warps.make_warp_area(warp_id) local position = warp.position local posx = position.x local posy = position.y - local radius = config.activation_range + local radius = config.standard_proximity_radius local radius2 = radius^2 -- Get the tile that is being replaced, store.update not needed as we dont want it to trigger @@ -203,7 +203,7 @@ function Warps.remove_warp_area(warp_id) local warp = Store.get(warp_store,warp_id) local position = warp.position local surface = warp.surface - local radius = config.activation_range + local radius = config.standard_proximity_radius local radius2 = radius^2 -- Check that a warp area was created previously diff --git a/modules/gui/debug/event_view.lua b/modules/gui/debug/event_view.lua index bc372007..cae93e60 100644 --- a/modules/gui/debug/event_view.lua +++ b/modules/gui/debug/event_view.lua @@ -1,7 +1,7 @@ -local Event = require 'utils.event' --- @dep utils.event -local table = require 'utils.table' --- @dep utils.table -local Gui = require 'utils.gui' --- @dep utils.gui -local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model +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 @@ -19,13 +19,16 @@ local name_lookup = {} -- GUI names local checkbox_name = Gui.uid_name() +local filter_name = Gui.uid_name() +local clear_filter_name = Gui.uid_name() -- global tables local enabled = {} local last_events = {} global.debug_event_view = { enabled = enabled, - last_events = last_events + last_events = last_events, + filter = '' } function Public.on_open_debug() @@ -90,24 +93,73 @@ 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}) - +local function redraw_event_table(gui_table, filter) 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 - } + if filter == '' or event_name:find(filter) then + 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 end +function Public.show(container) + local filter = global.debug_event_view.filter + + local main_frame_flow = container.add({type = 'flow', direction = 'vertical'}) + + local filter_flow = main_frame_flow.add({type = 'flow', direction = 'horizontal'}) + filter_flow.add({type = 'label', caption = 'filter'}) + local filter_textfield = filter_flow.add({type = 'textfield', name = filter_name, text = filter}) + local clear_button = filter_flow.add({type = 'button', name = clear_filter_name, caption = 'clear'}) + + 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}) + + Gui.set_data(filter_textfield, gui_table) + Gui.set_data(clear_button, {gui_table = gui_table, filter_textfield = filter_textfield}) + + redraw_event_table(gui_table, filter) +end + Gui.on_checked_state_changed(checkbox_name, on_gui_checked_state_changed) +Gui.on_text_changed( + filter_name, + function(event) + local element = event.element + local gui_table = Gui.get_data(element) + + local filter = element.text:gsub(' ', '_') + + global.debug_event_view.filter = filter + element.text = filter + + gui_table.clear() + redraw_event_table(gui_table, filter) + end +) + +Gui.on_click( + clear_filter_name, + function(event) + local element = event.element + local data = Gui.get_data(element) + local filter_textfield = data.filter_textfield + local gui_table = data.gui_table + + filter_textfield.text = '' + global.debug_event_view.filter = '' + + gui_table.clear() + redraw_event_table(gui_table, '') + end +) + -- Event registers (TODO: turn to removable hooks.. maybe) for name, id in pairs(events) do name_lookup[id] = name diff --git a/modules/gui/debug/expcore_gui_view.lua b/modules/gui/debug/expcore_gui_view.lua new file mode 100644 index 00000000..cf95e894 --- /dev/null +++ b/modules/gui/debug/expcore_gui_view.lua @@ -0,0 +1,128 @@ +local Gui = require 'utils.gui' --- @dep utils.gui +local ExpGui = require 'expcore.gui' --- @dep utils.global +local Color = require 'resources.color_presets' --- @dep resources.color_presets +local Model = require 'modules.gui.debug.model' --- @dep 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 = 'Elements' + +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 element_id, file_path in pairs(ExpGui.file_paths) do + local header = left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = element_id..' - '..file_path} + Gui.set_data(header, element_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 element_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 {'Gui.defines[', element_id, ']'} + input_text_box.style.font_color = Color.black + + local content = dump(ExpGui.debug_info[element_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 diff --git a/modules/gui/debug/expcore_store_view.lua b/modules/gui/debug/expcore_store_view.lua index 2d115992..300acc2d 100644 --- a/modules/gui/debug/expcore_store_view.lua +++ b/modules/gui/debug/expcore_store_view.lua @@ -24,8 +24,8 @@ function Public.show(container) local left_panel_style = left_panel.style left_panel_style.width = 300 - for store_id, token_name in pairs(Store.file_paths) do - local header = left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = store_id..' - '..token_name} + for store_id, file_path in pairs(Store.file_paths) do + local header = left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = store_id..' - '..file_path} Gui.set_data(header, store_id) end diff --git a/modules/gui/debug/main_view.lua b/modules/gui/debug/main_view.lua index 3c286a46..9807329c 100644 --- a/modules/gui/debug/main_view.lua +++ b/modules/gui/debug/main_view.lua @@ -6,6 +6,7 @@ local Public = {} local pages = { require 'modules.gui.debug.redmew_global_view', require 'modules.gui.debug.expcore_store_view', + require 'modules.gui.debug.expcore_gui_view', require 'modules.gui.debug.global_view', require 'modules.gui.debug.package_view', require 'modules.gui.debug._g_view', @@ -31,7 +32,7 @@ function Public.open_dubug(player) return end - frame = center.add {type = 'frame', name = main_frame_name, caption = 'Debuggertron 3001', direction = 'vertical'} + frame = center.add {type = 'frame', name = main_frame_name, caption = 'Debuggertron 3002', direction = 'vertical'} local frame_style = frame.style frame_style.height = 600 frame_style.width = 900 diff --git a/modules/gui/player-list.lua b/modules/gui/player-list.lua index 80e81c13..0c460eb7 100644 --- a/modules/gui/player-list.lua +++ b/modules/gui/player-list.lua @@ -1,5 +1,5 @@ --[[-- Gui Module - Player List - - Adds a player list to show names and play time; also includes action buttons which can apply to players + - Adds a player list to show names and play time; also includes action buttons which can preform actions to players @gui Player-List @alias player_list ]] @@ -26,42 +26,21 @@ end) -- Set the config to use these stores config.set_store_uids(selected_player_store,selected_action_store) ---- Used to open the map on a player or toggle the settings -local zoom_to_map_name = Gui.uid_name() -Gui.on_click(zoom_to_map_name,function(event) - local selected_player_name = event.element.caption - local selected_player = Game.get_player_from_any(selected_player_name) - if event.button == defines.mouse_button_type.left then - -- LMB will open the map to the selected player - local position = selected_player.position - event.player.zoom_to_world(position,1.75) - else - -- RMB will toggle the settings - local player = event.player - local old_selected_player_name = Store.get(selected_player_store,player) - if selected_player_name == old_selected_player_name then - Store.clear(selected_player_store,player) - else - Store.set(selected_player_store,player,selected_player_name) - end - end -end) - --- Button used to open the action bar -- @element open_action_bar local open_action_bar = -Gui.new_button() -:set_sprites('utility/expand_dots_white') -:set_tooltip{'player-list.open-action-bar'} -:set_embedded_flow(function(element,selected_player_name) - return selected_player_name -end) -:set_style('frame_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.width = 8 - style.height = 14 -end) -:on_click(function(player,element) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/expand_dots_white', + tooltip = {'player-list.open-action-bar'}, + style = 'frame_button' +} +:style{ + padding = -2, + width = 8, + height = 14 +} +:on_click(function(player,element,_) local selected_player_name = element.parent.name local old_selected_player_name = Store.get(selected_player_store,player) if selected_player_name == old_selected_player_name then @@ -74,15 +53,14 @@ end) --- Button used to close the action bar -- @element close_action_bar local close_action_bar = -Gui.new_button() -:set_sprites('utility/close_black','utility/close_white') -:set_tooltip{'player-list.close-action-bar'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-1,-1,-1,-1) - style.height = 28 - style.width = 28 -end) -:on_click(function(player,element) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/close_black', + tooltip = {'player-list.close-action-bar'}, + style = 'shortcut_bar_button_red' +} +:style(Gui.sprite_style(30,-1,{ top_margin = -1, right_margin = -1 })) +:on_click(function(player,_) Store.clear(selected_player_store,player) Store.clear(selected_action_store,player) end) @@ -90,14 +68,13 @@ end) --- Button used to confirm a reason -- @element reason_confirm local reason_confirm = -Gui.new_button() -:set_sprites('utility/confirm_slot') -:set_tooltip{'player-list.reason-confirm'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-1,-1,-1,-1) - style.height = 28 - style.width = 28 -end) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/confirm_slot', + tooltip = {'player-list.reason-confirm'}, + style = 'shortcut_bar_button_green' +} +:style(Gui.sprite_style(30,-1,{ left_margin = -2, right_margin = -1 })) :on_click(function(player,element) local reason = element.parent.entry.text or 'Non Given' local action_name = Store.get(selected_action_store,player) @@ -108,109 +85,97 @@ end) element.parent.entry.text = '' end) ---[[ Creates the main gui areas for the player list - element - > container - >> scroll - >>> table - >> action_bar -]] -local function generate_container(player,element) - Gui.set_padding(element,2,2,2,2) - element.style.minimal_width = 200 +--- Set of elements that are used to make up a row of the player table +-- @element add_player_base +local add_player_base = +Gui.element(function(event_trigger,parent,player_data) + -- Add the button to open the action bar + local toggle_action_bar_flow = parent.add{ type = 'flow', name = player_data.name } + open_action_bar(toggle_action_bar_flow) - -- main container which contains the other elements - local container = - element.add{ - name='container', - type='frame', - direction='vertical', - style='window_content_frame_packed' + -- Add the player name + local player_name_flow = parent.add{ type = 'flow', 'player-name-'..player_data.index } + local player_name = player_name_flow.add{ + type = 'label', + name = event_trigger, + caption = player_data.name, + tooltip = {'player-list.open-map',player_data.name,player_data.tag,player_data.role_name} } - Gui.set_padding(container) + player_name.style.padding = {0,2,0,0} + player_name.style.font_color = player_data.chat_color - -- 3 wide table to contain: action button, player name, and play time - local list_table = Gui.create_scroll_table(container,3,188) - - -- action bar which contains the different action buttons - local action_bar = - container.add{ - name='action_bar', - type='frame', - style='subfooter_frame' + -- Add the time played label + local alignment = Gui.alignment(parent,'player-time-'..player_data.index) + local time_label = alignment.add{ + name = 'label', + type = 'label', + caption = player_data.caption, + tooltip = player_data.tooltip } - Gui.set_padding(action_bar,1,1,3,3) - action_bar.style.horizontally_stretchable = true - action_bar.style.height = 35 + time_label.style.padding = 0 - -- reason bar which contains the reason text field and confirm button - local reason_bar = - container.add{ - name='reason_bar', - type='frame', - style='subfooter_frame' - } - Gui.set_padding(reason_bar,-1,-1,3,3) - reason_bar.style.horizontally_stretchable = true - reason_bar.style.height = 35 - local action_name = Store.get(selected_action_store,player) - reason_bar.visible = action_name ~= nil + return time_label +end) +:on_click(function(player,element,event) + local selected_player_name = element.caption + local selected_player = Game.get_player_from_any(selected_player_name) + if event.button == defines.mouse_button_type.left then + -- LMB will open the map to the selected player + local position = selected_player.position + event.player.zoom_to_world(position,1.75) + else + -- RMB will toggle the settings + local old_selected_player_name = Store.get(selected_player_store,player) + if selected_player_name == old_selected_player_name then + Store.clear(selected_player_store,player) + else + Store.set(selected_player_store,player,selected_player_name) + end + end +end) - -- text entry for the reason bar - local reason_field = - reason_bar.add{ - name='entry', - type='textfield', - style='stretchable_textfield', - tooltip={'player-list.reason-entry'} - } - Gui.set_padding(reason_field) - reason_field.style.height = 28 - reason_field.style.minimal_width = 160 - - reason_confirm(reason_bar) - - return list_table, action_bar +-- Removes the three elements that are added as part of the base +local function remove_player_base(parent,player) + Gui.destroy_if_valid(parent[player.name]) + Gui.destroy_if_valid(parent['player-name-'..player.index]) + Gui.destroy_if_valid(parent['player-time-'..player.index]) end ---- Adds buttons and permission flows to the action bar -local function generate_action_bar(player,element) - close_action_bar(element) - local selected_player_name = Store.get(selected_player_store,player) +-- Update the time label for a player using there player time data +local function update_player_base(parent,player_time) + local time_element = parent[player_time.element_name] + if time_element and time_element.valid then + time_element.label.caption = player_time.caption + time_element.label.tooltip = player_time.tooltip + end +end - for action_name,buttons in pairs(config.buttons) do - local permission_flow = - element.add{ - type='flow', - name=action_name - } - - for _,button in ipairs(buttons) do +--- Adds all the buttons and flows that make up the action bar +-- @element add_action_bar +local add_action_bar_buttons = +Gui.element(function(_,parent) + close_action_bar(parent) + -- Loop over all the buttons in the config + for action_name,button_data in pairs(config.buttons) do + -- Added the permission flow + local permission_flow = parent.add{ type = 'flow', name = action_name } + permission_flow.visible = false + -- Add the buttons under that permission + for _,button in ipairs(button_data) do button(permission_flow) end - - if not Roles.player_allowed(player,action_name) then - permission_flow.visible = false - end - - if buttons.auth and selected_player_name and not buttons.auth(player,selected_player_name) then - permission_flow.visible = false - end end - if not selected_player_name then - element.visible = false - end -end + return parent +end) ---- Updates the action bar -local player_list_name -local function update_action_bar(player) - local frame = Gui.classes.left_frames.get_frame(player_list_name,player) - local element = frame.container.action_bar +--- Updates the visible state of the action bar buttons +local function update_action_bar(element) + local player = Gui.get_player_from_element(element) local selected_player_name = Store.get(selected_player_store,player) if not selected_player_name then + -- Hide the action bar when no player is selected element.visible = false else @@ -236,132 +201,213 @@ local function update_action_bar(player) end end ---- Adds a player to the player list -local function add_player(list_table,player,role_name) - open_action_bar(list_table,player.name) +--- Main player list container for the left flow +-- @element player_list_container +local player_list_container = +Gui.element(function(event_trigger,parent) + -- Draw the internal container + local container = Gui.container(parent,event_trigger,200) - -- flow to contain player_name to allow all to have trigger for zoom to map - local player_name_flow = - list_table.add{ - type='flow' + -- Draw the scroll table for the players + local scroll_table = Gui.scroll_table(container,184,3) + + -- Change the style of the scroll table + local scroll_table_style = scroll_table.style + scroll_table_style.padding = {1,0,1,2} + + -- Add the action bar + local action_bar = Gui.footer(container,nil,nil,false,'action_bar') + + -- Change the style of the action bar + local action_bar_style = action_bar.style + action_bar_style.height = 35 + action_bar_style.padding = {1,3} + action_bar.visible = false + + -- Add the buttons to the action bar + add_action_bar_buttons(action_bar) + + -- Add the reason bar + local reason_bar = Gui.footer(container,nil,nil,false,'reason_bar') + + -- Change the style of the reason bar + local reason_bar_style = reason_bar.style + reason_bar_style.height = 35 + reason_bar_style.padding = {-1,3} + reason_bar.visible = false + + -- Add the text entry for the reason bar + local reason_field = + reason_bar.add{ + name = 'entry', + type = 'textfield', + style = 'stretchable_textfield', + tooltip = {'player-list.reason-entry'} } - Gui.set_padding(player_name_flow) - -- player name with the tooltip of their highest role and in they colour - local player_name = - player_name_flow.add{ - name=zoom_to_map_name, - type='label', - caption=player.name, - tooltip={'player-list.open-map',player.name,player.tag,role_name} - } - Gui.set_padding(player_name,0,0,0,2) - player_name.style.font_color = player.chat_color + -- Change the style of the text entry + local reason_entry_style = reason_field.style + reason_entry_style.padding = 0 + reason_entry_style.height = 28 + reason_entry_style.minimal_width = 160 - -- flow which allows right align for the play time - local time_flow = Gui.create_alignment(list_table,'player-time-'..player.index) + -- Add the confirm reason button + reason_confirm(reason_bar) - -- time given in Xh Ym and is right aligned + -- Return the exteral container + return container.parent +end) +:add_to_left_flow(true) + +--- Button on the top flow used to toggle the player list container +-- @element toggle_left_element +Gui.left_toolbar_button('entity/character', {'player-list.main-tooltip'}, player_list_container, function(player) + return Roles.player_allowed(player,'gui/player-list') +end) + +-- Get caption and tooltip format for a player +local function get_time_formats(online_time,afk_time) local tick = game.tick > 0 and game.tick or 1 - local percent = math.round(player.online_time/tick,3)*100 - local time = - time_flow.add{ - name='label', - type='label', - caption=format_time(player.online_time), - tooltip={'player-list.afk-time',percent,format_time(player.afk_time,{minutes=true,long=true})} - } - Gui.set_padding(time) + local percent = math.round(online_time/tick,3)*100 + local caption = format_time(online_time) + local tooltip = {'player-list.afk-time', percent, format_time(afk_time,{minutes=true,long=true})} + return caption, tooltip end ---- Adds fake players to the player list -local function add_fake_players(list_table,count) - local role_name = 'Fake Player' - for i = 1,count do - add_player(list_table,{ - name='Player '..i, - index=0-i, - tag='', - online_time=math.random(0,game.tick), - afk_time=math.random(0,game.tick), - chat_color=table.get_random_dictionary_entry(Colors) - },role_name) +-- Get the player time to be used to update time label +local function get_player_times() + local ctn = 0 + local player_times = {} + for _, player in pairs(game.connected_players) do + ctn = ctn + 1 + -- Add the player time details to the array + local caption, tooltip = get_time_formats(player.online_time, player.afk_time) + player_times[ctn] = { + element_name = 'player-time-'..player.index, + caption = caption, + tooltip = tooltip + } end + + return player_times end ---- Registers the player list --- @element player_list -local player_list = -Gui.new_left_frame('gui/player-list') -:set_sprites('entity/character') -:set_tooltip{'player-list.main-tooltip'} -:set_open_by_default() -:set_direction('vertical') -:on_creation(function(player,element) - local list_table,action_bar = generate_container(player,element) - generate_action_bar(player,action_bar) - +-- Get a sorted list of all online players +local function get_player_list_order() + -- Sort all the online players into roles local players = {} - for _,next_player in pairs(game.connected_players) do - local highest_role = Roles.get_player_highest_role(next_player) + for _,player in pairs(game.connected_players) do + local highest_role = Roles.get_player_highest_role(player) if not players[highest_role.name] then players[highest_role.name] = {} end - table.insert(players[highest_role.name],next_player) + table.insert(players[highest_role.name],player) end + -- Sort the players from roles into a set order + local ctn = 0 + local player_list_order = {} for _,role_name in pairs(Roles.config.order) do if players[role_name] then - for _,next_player in pairs(players[role_name]) do - add_player(list_table,next_player,role_name) + for _,player in pairs(players[role_name]) do + ctn = ctn + 1 + -- Add the player data to the array + local caption, tooltip = get_time_formats(player.online_time, player.afk_time) + player_list_order[ctn] = { + name = player.name, + index = player.index, + tag = player.tag, + role_name = role_name, + chat_color = player.chat_color, + caption = caption, + tooltip = tooltip + } end end end - --add_fake_players(list_table,6) - --add_fake_players(list_table,20) -end) -:on_update(function(player,element) - local list = element.container.scroll.table - for _,next_player in pairs(game.connected_players) do - local time_element_name = 'player-time-'..next_player.index - local time_element = list[time_element_name] - if time_element and time_element.valid then - time_element.label.caption = format_time(next_player.online_time) - local tick = game.tick > 0 and game.tick or 1 - local percent = math.round(next_player.online_time/tick,3)*100 - time_element.label.tooltip = {'player-list.afk-time',percent,format_time(next_player.afk_time,{minutes=true,long=true})} + --[[Adds fake players to the player list + for i = 1, 10 do + local online_time = math.random(1,tick) + local afk_time = math.random(online_time-(tick/10),tick) + local caption, tooltip = get_time_formats(online_time, afk_time) + player_list_order[ctn+i] = { + name='Player '..i, + index=0-i, + tag='', + role_name = 'Fake Player', + chat_color = table.get_random_dictionary_entry(Colors), + caption = caption, + tooltip = tooltip + } + end]] + + return player_list_order +end + +--- Update the play times every 30 sections +Event.on_nth_tick(1800,function() + local player_times = get_player_times() + for _,player in pairs(game.connected_players) do + local frame = Gui.get_left_element(player,player_list_container) + local scroll_table = frame.container.scroll.table + for _,player_time in pairs(player_times) do + update_player_base(scroll_table,player_time) end end end) -player_list_name = player_list:uid() +--- When a player leaves only remove they entry +Event.add(defines.events.on_player_left_game,function(event) + local remove_player = event.player + for _,player in pairs(game.connected_players) do + local frame = Gui.get_left_element(player,player_list_container) + local scroll_table = frame.container.scroll.table + remove_player_base(scroll_table,remove_player) + end +end) + +--- All other events require a full redraw of the table +local function redraw_player_list() + local player_list_order = get_player_list_order() + for _,player in pairs(game.connected_players) do + local frame = Gui.get_left_element(player,player_list_container) + local scroll_table = frame.container.scroll.table + scroll_table.clear() + for _,next_player_data in ipairs(player_list_order) do + add_player_base(scroll_table,next_player_data) + end + end +end + +Event.add(defines.events.on_player_joined_game,redraw_player_list) +Event.add(Roles.events.on_role_assigned,redraw_player_list) +Event.add(Roles.events.on_role_unassigned,redraw_player_list) --- When the action player is changed the action bar will update Store.watch(selected_player_store,function(value,player_name) local player = Game.get_player_from_any(player_name) - update_action_bar(player) - - -- Change the style of the option buttons - local frame = player_list:get_frame(player) - local data_table = frame.container.scroll.table + local frame = Gui.get_left_element(player,player_list_container) + local scroll_table = frame.container.scroll.table + update_action_bar(frame.container.action_bar) for _,next_player in pairs(game.connected_players) do - local element = data_table[next_player.name][open_action_bar.name] + local element = scroll_table[next_player.name][open_action_bar.name] local style = 'frame_button' if next_player.name == value then style = 'tool_button' end element.style = style - Gui.set_padding(element,-2,-2,-2,-2) - element.style.width = 8 - element.style.height = 14 + local element_style = element.style + element_style.padding = -2 + element_style.width = 8 + element_style.height = 14 end end) --- When the action name is changed the reason input will update Store.watch(selected_action_store,function(value,player_name) local player = Game.get_player_from_any(player_name) - local frame = Gui.classes.left_frames.get_frame(player_list_name,player) + local frame = Gui.get_left_element(player,player_list_container) local element = frame.container.reason_bar if value then -- if there is a new value then check the player is still online @@ -379,13 +425,4 @@ Store.watch(selected_action_store,function(value,player_name) element.visible = false end -end) - ---- Many events which trigger the gui to be re drawn, it will also update the times every 30 seconds -Event.on_nth_tick(1800,player_list 'update_all') -Event.add(defines.events.on_player_joined_game,player_list 'redraw_all') -Event.add(defines.events.on_player_left_game,player_list 'redraw_all') -Event.add(Roles.events.on_role_assigned,player_list 'redraw_all') -Event.add(Roles.events.on_role_unassigned,player_list 'redraw_all') - -return player_list \ No newline at end of file +end) \ No newline at end of file diff --git a/modules/gui/rocket-info.lua b/modules/gui/rocket-info.lua index fd384627..f2384a21 100644 --- a/modules/gui/rocket-info.lua +++ b/modules/gui/rocket-info.lua @@ -12,8 +12,15 @@ local format_time = ext_require('expcore.common','format_time') --- @dep expcore local Colors = require 'resources.color_presets' --- @dep resources.color_presets local Rockets = require 'modules.control.rockets' --- @dep modules.control.rockets ---- Gets if a player is allowed to use the action buttons -local function player_allowed(player,action) +local time_formats = { + caption = function(value) return format_time(value, {minutes=true, seconds=true}) end, + caption_hours = function(value) return format_time(value) end, + tooltip = function(value) return format_time(value, {minutes=true, seconds=true, long=true}) end, + tooltip_hours = function(value) return format_time(value, {hours=true, minutes=true, seconds=true, long=true}) end +} + +--- Check if a player is allowed to use certain interactions +local function check_player_permissions(player,action) if not config.progress['allow_'..action] then return false end @@ -22,38 +29,48 @@ local function player_allowed(player,action) return false end - if config.progress[action..'_role_permission'] and not Roles.player_allowed(player,config.progress[action..'_role_permission']) then + if config.progress[action..'_role_permission'] + and not Roles.player_allowed(player,config.progress[action..'_role_permission']) then return false end return true end ---- Used on the name label to allow zoom to map --- @element zoom_to_map -local zoom_to_map_name = Gui.uid_name() -Gui.on_click(zoom_to_map_name,function(event) - local rocket_silo_name = event.element.parent.caption - local rocket_silo = Rockets.get_silo_entity(rocket_silo_name) - event.player.zoom_to_world(rocket_silo.position,2) +--- Button to toggle the auto launch on a rocket silo +-- @elemeent toggle_launch +local toggle_launch = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/play', + tooltip = {'rocket-info.toggle-rocket-tooltip'} +} +:style(Gui.sprite_style(16)) +:on_click(function(_,element,_) + local rocket_silo_name = element.parent.name:sub(8) + local rocket_silo = Rockets.get_silo_entity(rocket_silo_name) + if rocket_silo.auto_launch then + element.sprite = 'utility/play' + element.tooltip = {'rocket-info.toggle-rocket-tooltip'} + rocket_silo.auto_launch = false + else + element.sprite = 'utility/stop' + element.tooltip = {'rocket-info.toggle-rocket-tooltip-disabled'} + rocket_silo.auto_launch = true + end end) ---- Used to launch the rocket, when it is ready +--- Button to remotely launch a rocket from a silo -- @element launch_rocket local launch_rocket = -Gui.new_button() -:set_sprites('utility/center') -:set_tooltip{'rocket-info.launch-tooltip'} -:set_embedded_flow(function(element,rocket_silo_name) - return 'launch-'..rocket_silo_name -end) -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.width = 16 - style.height = 16 -end) -:on_click(function(player,element) - local rocket_silo_name = element.parent.name:sub(8) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/center', + tooltip = {'rocket-info.launch-tooltip'} +} +:style(Gui.sprite_style(16,-1)) +:on_click(function(player,element,_) + local rocket_silo_name = element.parent.name:sub(8) local silo_data = Rockets.get_silo_data_by_name(rocket_silo_name) if silo_data.entity.launch_rocket() then silo_data.awaiting_reset = true @@ -66,457 +83,519 @@ end) end end) ---- Used to toggle the auto launch on a rocket --- @element toggle_rocket -local toggle_rocket = -Gui.new_button() -:set_sprites('utility/play') -:set_tooltip{'rocket-info.toggle-rocket-tooltip'} -:set_embedded_flow(function(element,rocket_silo_name) - return 'toggle-'..rocket_silo_name +--- XY cords that allow zoom to map when pressed +-- @element silo_cords +local silo_cords = +Gui.element(function(event_trigger,parent,silo_data) + local silo_name = silo_data.silo_name + local pos = silo_data.position + local name = config.progress.allow_zoom_to_map and event_trigger or nil + local tooltip = config.progress.allow_zoom_to_map and {'rocket-info.progress-label-tooltip'} or nil + + -- Add the x cord flow + local flow_x = parent.add{ + type ='flow', + name = 'label-x-'..silo_name, + caption = silo_name + } + flow_x.style.padding = {0,2,0,1} + + -- Add the x cord label + flow_x.add{ + type = 'label', + name = name, + caption = {'rocket-info.progress-x-pos',pos.x}, + tooltip = tooltip + } + + -- Add the y cord flow + local flow_y = parent.add{ + type ='flow', + name = 'label-y-'..silo_name, + caption = silo_name + } + flow_y.style.padding = {0,2,0,1} + + -- Add the y cord label + flow_y.add{ + type = 'label', + name = name, + caption = {'rocket-info.progress-y-pos',pos.y}, + tooltip = tooltip + } + end) -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.width = 16 - style.height = 16 -end) -:on_click(function(player,element) - local rocket_silo_name = element.parent.name:sub(8) +:on_click(function(player,element,_) + local rocket_silo_name = element.parent.caption local rocket_silo = Rockets.get_silo_entity(rocket_silo_name) - if rocket_silo.auto_launch then - element.sprite = 'utility/play' - element.tooltip = {'rocket-info.toggle-rocket-tooltip'} - rocket_silo.auto_launch = false - else - element.sprite = 'utility/stop' - element.tooltip = {'rocket-info.toggle-rocket-tooltip-disabled'} - rocket_silo.auto_launch = true - end + player.zoom_to_world(rocket_silo.position,2) end) ---- Used to toggle the visibility of the different sections --- @element toggle_section -local toggle_section = -Gui.new_button() -:set_sprites('utility/expand_dark','utility/expand') -:set_tooltip{'rocket-info.toggle-section-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) -:on_click(function(player,element) - local flow_name = element.parent.caption - local flow = element.parent.parent.parent[flow_name] - if Gui.toggle_visible(flow) then - element.sprite = 'utility/collapse_dark' - element.hovered_sprite = 'utility/collapse' - element.tooltip = {'rocket-info.toggle-section-collapse-tooltip'} - else - element.sprite = 'utility/expand_dark' - element.hovered_sprite = 'utility/expand' - element.tooltip = {'rocket-info.toggle-section-tooltip'} - end +--- Base element for each rocket in the progress list +-- @element rocket_entry +local rocket_entry = +Gui.element(function(_,parent,silo_data) + local silo_name = silo_data.silo_name + local player = Gui.get_player_from_element(parent) + + -- Add the toggle auto launch if the player is allowed it + if check_player_permissions(player,'toggle_active') then + local flow = parent.add{ type = 'flow', name = 'toggle-'..silo_name} + local button = toggle_launch(flow) + button.tooltip = silo_data.toggle_tooltip + button.sprite = silo_data.toggle_sprite + end + + -- Add the remote launch if the player is allowed it + if check_player_permissions(player,'remote_launch') then + local flow = parent.add{ type = 'flow', name = 'launch-'..silo_name} + local button = launch_rocket(flow) + button.enabled = silo_data.allow_launch + end + + -- Draw the silo cords element + silo_cords(parent,silo_data) + + -- Add a progress label + local alignment = Gui.alignment(parent,silo_name) + local element = + alignment.add{ + type = 'label', + name = 'label', + caption = silo_data.progress_caption, + tooltip = silo_data.progress_tooltip + } + + -- Return the progress label + return element end) ---- Used to create the three different sections -local function create_section(container,section_name,table_size) - -- Header for the section - local header_area = Gui.create_header( - container, - {'rocket-info.section-caption-'..section_name}, - {'rocket-info.section-tooltip-'..section_name}, - true, - section_name..'-header' - ) +--- Data label which contains a name and a value label pair +-- @element data_label +local data_label = +Gui.element(function(_,parent,label_data) + local data_name = label_data.name + local data_subname = label_data.subname + local data_fullname = data_subname and data_name..data_subname or data_name - -- Right aligned button to toggle the section - header_area.caption = section_name - toggle_section(header_area) + -- Add the name label + local name_label = parent.add{ + type = 'label', + name = data_fullname..'-label', + caption = {'rocket-info.data-caption-'..data_name,data_subname}, + tooltip = {'rocket-info.data-tooltip-'..data_name,data_subname} + } + name_label.style.padding = {0,2} - -- Table used to store the data - local flow_table = Gui.create_scroll_table(container,table_size,215,section_name) - flow_table.parent.visible = false + --- Right aligned label to store the data + local alignment = Gui.alignment(parent,data_fullname) + local element = + alignment.add{ + type = 'label', + name = 'label', + caption = label_data.value, + tooltip = label_data.tooltip + } + element.style.padding = {0,2} + return element +end) + +-- Used to update the captions and tooltips on the data labels +local function update_data_labels(parent,data_label_data) + for _, label_data in ipairs(data_label_data) do + local data_name = label_data.subname and label_data.name..label_data.subname or label_data.name + if not parent[data_name] then + data_label(parent,label_data) + else + local data_label_element = parent[data_name].label + data_label_element.tooltip = label_data.tooltip + data_label_element.caption = label_data.value + end + end end ---[[ Creates the main structure for the gui - element - > container +local function get_progress_data(force_name) + local force_silos = Rockets.get_silos(force_name) + local progress_data = {} - >> stats-header - >>> stats - >>>> toggle_section.name - >> stats - >>> table + for _, silo_data in pairs(force_silos) do + local rocket_silo = silo_data.entity + if not rocket_silo or not rocket_silo.valid then + -- Remove from list if not valid + force_silos[silo_data.name] = nil + table.insert(progress_data,{ + silo_name = silo_data.name, + remove = true + }) - >> milestones-header - >>> milestones - >>>> toggle_section.name - >> milestones - >>> table + else + -- Get the progress caption and tooltip + local progress_color = Colors.white + local progress_caption = {'rocket-info.progress-caption',rocket_silo.rocket_parts} + local progress_tooltip = {'rocket-info.progress-tooltip',silo_data.launched or 0} + local status = rocket_silo.status == defines.entity_status.waiting_to_launch_rocket + if status and silo_data.awaiting_reset then + progress_caption = {'rocket-info.progress-launched'} + progress_color = Colors.green + elseif status then + progress_caption = {'rocket-info.progress-caption',100} + progress_color = Colors.cyan + else + silo_data.awaiting_reset = false + end - >> progress-header - >>> progress - >>>> toggle_section.name - >> progress - >>> table -]] -local function generate_container(player,element) - Gui.set_padding(element,1,2,2,2) - element.style.minimal_width = 200 + -- Get the toggle button data + local toggle_tooltip = {'rocket-info.toggle-rocket-tooltip-disabled'} + local toggle_sprite = 'utility/play' + if rocket_silo.auto_launch then + toggle_tooltip = {'rocket-info.toggle-rocket-tooltip'} + toggle_sprite = 'utility/stop' + end - -- main container which contains the other elements - local container = - element.add{ - name='container', - type='frame', - direction='vertical', - style='window_content_frame_packed' - } - Gui.set_padding(container) - - if config.stats.show_stats then - create_section(container,'stats',2) - end - - if config.milestones.show_milestones then - create_section(container,'milestones',2) - end - - if config.progress.show_progress then - local col_count = 3 - if player_allowed(player,'remote_launch') then col_count = col_count+1 end - if player_allowed(player,'toggle_active') then col_count = col_count+1 end - create_section(container,'progress',col_count) - --- label used when no active silos - container.progress.add{ - type='label', - name='no_silos', - caption={'rocket-info.progress-no-silos'} - } - end + -- Insert the gui data + table.insert(progress_data,{ + silo_name = silo_data.name, + position = rocket_silo.position, + allow_launch = not silo_data.awaiting_reset and status or false, + progress_color = progress_color, + progress_caption = progress_caption, + progress_tooltip = progress_tooltip, + toggle_tooltip = toggle_tooltip, + toggle_sprite = toggle_sprite + }) + end + end + return progress_data end ---[[ Creates a text label followed by a data label, or updates them if already present - element - > "data_name_extra"-label - > "data_name_extra" - >> label -]] -local function create_label_value_pair(element,data_name,value,tooltip,extra) - local data_name_extra = extra and data_name..extra or data_name - if element[data_name_extra] then - element[data_name_extra].label.caption = value - element[data_name_extra].label.tooltip = tooltip - else - --- Label used with the data - element.add{ - type='label', - name=data_name_extra..'-label', - caption={'rocket-info.data-caption-'..data_name,extra}, - tooltip={'rocket-info.data-tooltip-'..data_name,extra} - } - --- Right aligned label to store the data - local right_flow = Gui.create_alignment(element,data_name_extra) - right_flow.add{ - type='label', - name='label', - caption=value, - tooltip=tooltip - } - end +--- Update the build progress section +local function update_build_progress(parent,progress_data) + local show_message = true + for _, silo_data in ipairs(progress_data) do + parent.no_silos.visible = false + local silo_name = silo_data.silo_name + local progress_label = parent[silo_name] + if silo_data.remove then + -- Remove the rocket from the list + Gui.destroy_if_valid(parent['toggle-'..silo_name]) + Gui.destroy_if_valid(parent['launch-'..silo_name]) + Gui.destroy_if_valid(parent['label-x-'..silo_name]) + Gui.destroy_if_valid(parent['label-y-'..silo_name]) + Gui.destroy_if_valid(parent[silo_name]) + + elseif not progress_label then + -- Add the rocket to the list + show_message = false + rocket_entry(parent,silo_data) + + else + show_message = false + -- Update the existing labels + progress_label = progress_label.label + progress_label.caption = silo_data.progress_caption + progress_label.tooltip = silo_data.progress_tooltip + progress_label.style.font_color = silo_data.progress_color + + -- Update the toggle button + local toggle_button = parent['toggle-'..silo_name] + if toggle_button then + toggle_button = toggle_button[toggle_launch.name] + toggle_button.tooltip = silo_data.toggle_tooltip + toggle_button.sprite = silo_data.toggle_sprite + end + + -- Update the launch button + local launch_button = parent['launch-'..silo_name] + if launch_button then + launch_button = launch_button[launch_rocket.name] + launch_button.enabled = silo_data.allow_launch + end + end + end + if show_message then parent.no_silos.visible = true end end ---- Creates a text and data label using times as the data -local function create_label_value_pair_time(element,data_name,raw_value,no_hours,extra) - local value = no_hours and format_time(raw_value,{minutes=true,seconds=true}) or format_time(raw_value) - local tooltip = format_time(raw_value,{hours=not no_hours,minutes=true,seconds=true,long=true}) - create_label_value_pair(element,data_name,value,tooltip,extra) -end - ---- Adds the different data values to the stats section -local function generate_stats(player,frame) - if not config.stats.show_stats then return end - local element = frame.container.stats.table - local force_name = player.force.name +--- Gets the label data for all the different stats +local function get_stats_data(force_name) local force_rockets = Rockets.get_rocket_count(force_name) - local stats = Rockets.get_stats(force_name) + local stats = Rockets.get_stats(force_name) + local stats_data = {} - if config.stats.show_first_rocket then - create_label_value_pair_time(element,'first-launch',stats.first_launch or 0) + -- Format the first launch data + if config.stats.show_first_rocket then + local value = stats.first_launch or 0 + table.insert(stats_data,{ + name = 'first-launch', + value = time_formats.caption_hours(value), + tooltip = time_formats.tooltip_hours(value) + }) + end + + -- Format the last launch data + if config.stats.show_last_rocket then + local value = stats.last_launch or 0 + table.insert(stats_data,{ + name = 'last-launch', + value = time_formats.caption_hours(value), + tooltip = time_formats.tooltip_hours(value) + }) end - if config.stats.show_last_rocket then - create_label_value_pair_time(element,'last-launch',stats.last_launch or 0) - end - - if config.stats.show_fastest_rocket then - create_label_value_pair_time(element,'fastest-launch',stats.fastest_launch or 0,true) + -- Format fastest launch data + if config.stats.show_fastest_rocket then + local value = stats.fastest_launch or 0 + table.insert(stats_data,{ + name = 'fastest-launch', + value = time_formats.caption_hours(value), + tooltip = time_formats.tooltip_hours(value) + }) end + -- Format total rocket data if config.stats.show_total_rockets then local total_rockets = Rockets.get_game_rocket_count() total_rockets = total_rockets == 0 and 1 or total_rockets - local percentage = math.round(force_rockets/total_rockets,3)*100 - create_label_value_pair(element,'total-rockets',force_rockets,{'rocket-info.value-tooltip-total-rockets',percentage}) + local percentage = math.round(force_rockets/total_rockets,3)*100 + table.insert(stats_data,{ + name = 'total-rockets', + value = force_rockets, + tooltip = {'rocket-info.value-tooltip-total-rockets',percentage} + }) end + -- Format game avg data if config.stats.show_game_avg then - local avg = force_rockets > 0 and math.floor(game.tick/force_rockets) or 0 - create_label_value_pair_time(element,'avg-launch',avg,true) + local avg = force_rockets > 0 and math.floor(game.tick/force_rockets) or 0 + table.insert(stats_data,{ + name = 'avg-launch', + value = time_formats.caption(avg), + tooltip = time_formats.tooltip(avg) + }) end + -- Format rolling avg data for _,avg_over in pairs(config.stats.rolling_avg) do - local avg = Rockets.get_rolling_average(force_name,avg_over) - create_label_value_pair_time(element,'avg-launch-n',avg,true,avg_over) - end + local avg = Rockets.get_rolling_average(force_name,avg_over) + table.insert(stats_data,{ + name = 'avg-launch-n', + subname = avg_over, + value = time_formats.caption(avg), + tooltip = time_formats.tooltip(avg) + }) + end + -- Return formated data + return stats_data end ---- Creates the list of milestones -local function generate_milestones(player,frame) - if not config.milestones.show_milestones then return end - local element = frame.container.milestones.table - local force_name = player.force.name - local force_rockets = Rockets.get_rocket_count(force_name) +--- Gets the label data for the milestones +local function get_milestone_data(force_name) + local force_rockets = Rockets.get_rocket_count(force_name) + local milestone_data = {} - for _,milestone in ipairs(config.milestones) do + for _,milestone in ipairs(config.milestones) do if milestone <= force_rockets then - local time = Rockets.get_rocket_time(force_name,milestone) - create_label_value_pair_time(element,'milestone-n',time,false,milestone) - else - create_label_value_pair_time(element,'milestone-n',0,false,milestone) + local time = Rockets.get_rocket_time(force_name,milestone) + table.insert(milestone_data,{ + name = 'milestone-n', + subname = milestone, + value = time_formats.caption_hours(time), + tooltip = time_formats.tooltip_hours(time) + }) + else + table.insert(milestone_data,{ + name = 'milestone-n', + subname = milestone, + value = {'rocket-info.data-caption-milestone-next'}, + tooltip = {'rocket-info.data-tooltip-milestone-next'} + }) break end - end + end + + return milestone_data end ---- Creats the different buttons used with the rocket silos -local function generate_progress_buttons(player,element,silo_data) - local silo_name = silo_data.name - local rocket_silo = silo_data.entity - local status = rocket_silo.status == defines.entity_status.waiting_to_launch_rocket - local active = rocket_silo.auto_launch +-- Button to toggle a section dropdown +-- @element toggle_section +local toggle_section = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/expand_dark', + hovered_sprite = 'utility/expand', + tooltip = {'rocket-info.toggle-section-tooltip'} +} +:style(Gui.sprite_style(20)) +:on_click(function(_,element,_) + local header_flow = element.parent + local flow_name = header_flow.caption + local flow = header_flow.parent.parent[flow_name] + if Gui.toggle_visible_state(flow) then + element.sprite = 'utility/collapse_dark' + element.hovered_sprite = 'utility/collapse' + element.tooltip = {'rocket-info.toggle-section-collapse-tooltip'} + else + element.sprite = 'utility/expand_dark' + element.hovered_sprite = 'utility/expand' + element.tooltip = {'rocket-info.toggle-section-tooltip'} + end +end) - if player_allowed(player,'toggle_active') then - local button_element = element['toggle-'..silo_name] +-- Draw a section header and main scroll +-- @element rocket_list_container +local section = +Gui.element(function(_,parent,section_name,table_size) + -- Draw the header for the section + local header = Gui.header( + parent, + {'rocket-info.section-caption-'..section_name}, + {'rocket-info.section-tooltip-'..section_name}, + true, + section_name..'-header' + ) - if button_element then - button_element = button_element[toggle_rocket.name] - else - button_element = toggle_rocket(element,silo_name) - end + -- Right aligned button to toggle the section + header.caption = section_name + toggle_section(header) - if active then - button_element.tooltip = {'rocket-info.toggle-rocket-tooltip'} - button_element.sprite = 'utility/stop' - else - button_element.tooltip = {'rocket-info.toggle-rocket-tooltip-disabled'} - button_element.sprite = 'utility/play' - end - end + -- Table used to store the data + local scroll_table = Gui.scroll_table(parent,215,table_size,section_name) + scroll_table.parent.visible = false - if player_allowed(player,'remote_launch') then - local button_element = element['launch-'..silo_name] + -- Return the flow table + return scroll_table +end) - if button_element then - button_element = button_element[launch_rocket.name] - else - button_element = launch_rocket(element,silo_name) - end +--- Main gui container for the left flow +-- @element rocket_list_container +local rocket_list_container = +Gui.element(function(event_trigger,parent) + -- Draw the internal container + local container = Gui.container(parent,event_trigger,200) - if silo_data.awaiting_reset then - button_element.enabled = false - else - button_element.enabled = status - end - end + -- Set the container style + local style = container.style + style.padding = 0 + local player = Gui.get_player_from_element(parent) + local force_name = player.force.name + -- Draw stats section + if config.stats.show_stats then + update_data_labels(section(container,'stats',2),get_stats_data(force_name)) + end + + -- Draw milestones section + if config.milestones.show_milestones then + update_data_labels(section(container,'milestones',2),get_milestone_data(force_name)) + end + + -- Draw build progress list + if config.progress.show_progress then + local col_count = 3 + if check_player_permissions(player,'remote_launch') then col_count = col_count+1 end + if check_player_permissions(player,'toggle_active') then col_count = col_count+1 end + local progress = section(container,'progress',col_count) + -- Label used when there are no active silos + local no_silos = progress.add{ + type = 'label', + name = 'no_silos', + caption = {'rocket-info.progress-no-silos'} + } + no_silos.style.padding = {1,2} + update_build_progress(progress,get_progress_data(force_name)) + end + + -- Return the exteral container + return container.parent +end) +:add_to_left_flow(function(player) + return player.force.rockets_launched > 0 and Roles.player_allowed(player,'gui/rocket-info') +end) + +--- Button on the top flow used to toggle the container +-- @element toggle_left_element +Gui.left_toolbar_button('entity/rocket-silo', {'rocket-info.main-tooltip'}, rocket_list_container, function(player) + return Roles.player_allowed(player,'gui/rocket-info') +end) + +--- Update the gui for all players on a force +local function update_rocket_gui_all(force_name) + local stats = get_stats_data(force_name) + local milestones = get_milestone_data(force_name) + local progress = get_progress_data(force_name) + for _,player in pairs(game.forces[force_name].players) do + local frame = Gui.get_left_element(player,rocket_list_container) + local container = frame.container + update_data_labels(container.stats.table,stats) + update_data_labels(container.milestones.table,milestones) + update_build_progress(container.progress.table,progress) + end end ---[[ Creates build progress section - element - > toggle-"silo_name" (generate_progress_buttons) - > launch-"silo_name" (generate_progress_buttons) - > label-x-"silo_name" - >> "silo_name" - > label-y-"silo_name" - >> "silo_name" - > "silo_name" - >> label -]] -local function generate_progress(player,frame) - if not config.progress.show_progress then return end - local element = frame.container.progress.table - local force = player.force - local force_name = force.name - local force_silos = Rockets.get_silos(force_name) - - if not force_silos or table.size(force_silos) == 0 then - element.parent.no_silos.visible = true - - else - element.parent.no_silos.visible = false - - for _,silo_data in pairs(force_silos) do - local silo_name = silo_data.name - if not silo_data.entity or not silo_data.entity.valid then - force_silos[silo_name] = nil - Gui.destroy_if_valid(element['toggle-'..silo_name]) - Gui.destroy_if_valid(element['launch-'..silo_name]) - Gui.destroy_if_valid(element['label-x-'..silo_name]) - Gui.destroy_if_valid(element['label-y-'..silo_name]) - Gui.destroy_if_valid(element[silo_name]) - - elseif not element[silo_name] then - local entity = silo_data.entity - local progress = entity.rocket_parts - local pos = { - x=entity.position.x, - y=entity.position.y - } - - generate_progress_buttons(player,element,silo_data) - - --- Creates two flows and two labels for the X and Y position - local name = config.progress.allow_zoom_to_map and zoom_to_map_name or nil - local tooltip = config.progress.allow_zoom_to_map and {'rocket-info.progress-label-tooltip'} or nil - local flow_x = element.add{ - type='flow', - name='label-x-'..silo_name, - caption=silo_name - } - Gui.set_padding(flow_x,0,0,1,2) - flow_x.add{ - type='label', - name=name, - caption={'rocket-info.progress-x-pos',pos.x}, - tooltip=tooltip - } - - local flow_y = element.add{ - type='flow', - name='label-y-'..silo_name, - caption=silo_name - } - Gui.set_padding(flow_y,0,0,1,2) - flow_y.add{ - type='label', - name=name, - caption={'rocket-info.progress-y-pos',pos.y}, - tooltip=tooltip - } - - --- Creates the progress value which is right aligned - local right_flow = Gui.create_alignment(element,silo_name) - right_flow.add{ - type='label', - name='label', - caption={'rocket-info.progress-caption',progress}, - tooltip={'rocket-info.progress-tooltip',silo_data.launched or 0} - } - - else - local entity = silo_data.entity - local progress = entity.rocket_parts - local status = entity.status == 21 - - local label = element[silo_name].label - label.caption = {'rocket-info.progress-caption',progress} - label.tooltip = {'rocket-info.progress-tooltip',silo_data.launched or 0} - - if status and silo_data.awaiting_reset then - label.caption = {'rocket-info.progress-launched'} - label.style.font_color = Colors.green - elseif status then - label.caption = {'rocket-info.progress-caption',100} - label.style.font_color = Colors.cyan - else - silo_data.awaiting_reset = false - label.style.font_color = Colors.white - end - - generate_progress_buttons(player,element,silo_data) - - end - end - - end -end - ---- Registers the rocket info --- @element rocket_info -local rocket_info = -Gui.new_left_frame('gui/rocket-info') -:set_sprites('entity/rocket-silo') -:set_post_authenticator(function(player,define_name) - return player.force.rockets_launched > 0 and Gui.classes.toolbar.allowed(player,define_name) -end) -:set_open_by_default(function(player,define_name) - return player.force.rockets_launched > 0 -end) -:set_direction('vertical') -:on_creation(function(player,element) - generate_container(player,element) - generate_stats(player,element) - generate_milestones(player,element) - generate_progress(player,element) -end) -:on_update(function(player,element) - generate_stats(player,element) - generate_milestones(player,element) - generate_progress(player,element) -end) - ---- Event used to update the stats and the hui when a rocket is launched +--- Event used to update the stats when a rocket is launched Event.add(defines.events.on_rocket_launched,function(event) local force = event.rocket_silo.force - local rockets_launched = force.rockets_launched - local first_rocket = rockets_launched == 1 + update_rocket_gui_all(force.name) + if force.rockets_launched == 1 then + for _,player in pairs(force.players) do + Gui.update_top_flow(player) + end + end +end) - --- Updates all the guis (and toolbar since the button may now be visible) - for _,player in pairs(force.players) do - rocket_info:update(player) - if first_rocket then - Gui.update_toolbar(player) - rocket_info:toggle(player) - end - end +--- Update only the progress gui for a force +local function update_rocket_gui_progress(force_name) + local progress = get_progress_data(force_name) + for _,player in pairs(game.forces[force_name].players) do + local frame = Gui.get_left_element(player,rocket_list_container) + local container = frame.container + update_build_progress(container.progress.table,progress) + end +end + +Event.on_nth_tick(150,function() + for _,force in pairs(game.forces) do + if #Rockets.get_silos(force.name) > 0 then + update_rocket_gui_progress(force.name) + end + end end) --- Adds a silo to the list when it is built local function on_built(event) local entity = event.created_entity if entity.valid and entity.name == 'rocket-silo' then - local force = entity.force - - for _,player in pairs(force.players) do - local frame = rocket_info:get_frame(player) - generate_progress(player,frame) - end + update_rocket_gui_progress(entity.force.name) end end Event.add(defines.events.on_built_entity,on_built) Event.add(defines.events.on_robot_built_entity,on_built) ---- Optimised update for only the build progress -Event.on_nth_tick(150,function() - for _,force in pairs(game.forces) do - local silos = Rockets.get_silos(force.name) - if #silos > 0 then - for _,player in pairs(force.connected_players) do - local frame = rocket_info:get_frame(player) - generate_progress(player,frame) - end - end - end -end) +--- Redraw the progress section on role change +local function role_update_event(event) + local player = game.players[event.player_index] + local container = Gui.get_left_element(player,rocket_list_container).container + local progress = container.progress + if config.progress.show_progress then + progress.destroy() + local col_count = 3 + if check_player_permissions(player,'remote_launch') then col_count = col_count+1 end + if check_player_permissions(player,'toggle_active') then col_count = col_count+1 end + progress = section(container,'progress',col_count) + -- Label used when there are no active silos + progress.add{ + type = 'label', + name = 'no_silos', + caption = {'rocket-info.progress-no-silos'} + } + update_build_progress(progress,get_progress_data(player.force.name)) + end +end ---- Makes sure the right buttons are present when role changes -Event.add(Roles.events.on_role_assigned,rocket_info 'redraw') -Event.add(Roles.events.on_role_unassigned,rocket_info 'redraw') +Event.add(Roles.events.on_role_assigned,role_update_event) +Event.add(Roles.events.on_role_unassigned,role_update_event) -return rocket_info \ No newline at end of file +return rocket_list_container \ No newline at end of file diff --git a/modules/gui/science-info.lua b/modules/gui/science-info.lua index 9ecce6e2..36d4d947 100644 --- a/modules/gui/science-info.lua +++ b/modules/gui/science-info.lua @@ -5,6 +5,7 @@ ]] local Gui = require 'expcore.gui' --- @dep expcore.gui +local Roles = require 'expcore.roles' --- @dep expcore.gui local Event = require 'utils.event' --- @dep utils.event local format_time = ext_require('expcore.common','format_time') --- @dep expcore.common local config = require 'config.science' --- @dep config.science @@ -13,275 +14,360 @@ local Production = require 'modules.control.production' --- @dep modules.control local null_time_short = {'science-info.eta-time',format_time(0,{hours=true,minutes=true,seconds=true,time=true,null=true})} local null_time_long = format_time(0,{hours=true,minutes=true,seconds=true,long=true,null=true}) ---[[ Generates the main structure for the gui - element - > container - >> header - >> scroll - >>> non_made - >>> table - >> footer (when eta is enabled) - >>> eta-label - >>> eta - >>>> label -]] -local function generate_container(element) - Gui.set_padding(element,1,2,2,2) - element.style.minimal_width = 200 +--- Data label that contains the value and the surfix +-- @element production_label +local production_label = +Gui.element(function(_,parent,production_label_data) + local name = production_label_data.name + local tooltip = production_label_data.tooltip + local color = production_label_data.color - -- main container which contains the other elements - local container = - element.add{ - name='container', - type='frame', - direction='vertical', - style='window_content_frame_packed' + -- Add an alignment for the number + local alignment = Gui.alignment(parent,name) + + -- Add the main value label + local element = + alignment.add{ + name = 'label', + type = 'label', + caption = production_label_data.caption, + tooltip = tooltip } - Gui.set_padding(container) - -- main header for the gui - Gui.create_header( - container, - {'science-info.main-caption'}, - {'science-info.main-tooltip'} - ) + -- Change the style + element.style.font_color = color - -- table that stores all the data - local flow_table = Gui.create_scroll_table(container,4,185) - - -- message to say that you have not made any packs yet - local non_made = - flow_table.parent.add{ - name='non_made', - type='label', - caption={'science-info.no-packs'} + -- Add the surfix label + local surfix_element = + parent.add{ + name = 'surfix-'..name, + type = 'label', + caption = {'science-info.unit',production_label_data.surfix}, + tooltip = tooltip } - non_made.style.width = 200 - non_made.style.single_line = false - local eta - if config.show_eta then - -- footer used to store the eta - local footer = - container.add{ - name='footer', - type='frame', - style='subheader_frame' - } - Gui.set_padding(footer,2,2,4,4) - footer.style.horizontally_stretchable = true + -- Change the style + local surfix_element_style = surfix_element.style + surfix_element_style.font_color = color + surfix_element_style.right_margin = 1 - -- label for the footer - footer.add{ - name='eta-label', - type='label', - caption={'science-info.eta-caption'}, - tooltip={'science-info.eta-tooltip'}, - style='heading_1_label' - } + -- Return the value label + return element +end) - -- data for the footer - local right_align = Gui.create_alignment(footer,'eta') - eta = - right_align.add{ - name='label', - type='label', - caption=null_time_short, - tooltip=null_time_long, - style='heading_1_label' - } - end - - return flow_table, eta -end - ---[[ Adds two labels where one is right aligned and the other is a unit - element - > "name" - >> label - > spm-"name" -]] -local function add_data_label(element,name,value,secondary,tooltip) +-- Get the data that is used with the production label +local function get_production_label_data(name,tooltip,value,secondary) local data_colour = Production.get_color(config.color_clamp, value, secondary) local surfix,caption = Production.format_number(value) - if element[name] then - local data = element[name].label - data.caption = caption - data.tooltip = tooltip - data.style.font_color = data_colour - local label = element['spm-'..name] - label.caption = {'science-info.unit',surfix} - label.tooltip = tooltip - label.style.font_color = data_colour - - else - -- right aligned number - local right_align = Gui.create_alignment(element,name) - local data = - right_align.add{ - name='label', - type='label', - caption=caption, - tooltip=tooltip - } - data.style.font_color = data_colour - - -- adds the unit onto the end - local label = - element.add{ - name='spm-'..name, - type='label', - caption={'science-info.unit',surfix}, - tooltip=tooltip - } - label.style.font_color = data_colour - end + return { + name = name, + caption = caption, + surfix = surfix, + tooltip = tooltip, + color = data_colour + } end ---[[ Adds a science pack to the list - element - > icon-"science_pack" - > delta-"science_pack" - >> table - >>> pos-"science_pack" (add_data_label) - >>> neg-"science_pack" (add_data_label) - > net-"science_pack" (add_data_label) -]] -local function generate_science_pack(player,element,science_pack) - local total = Production.get_production_total(player.force, science_pack) - local minute = Production.get_production(player.force, science_pack, defines.flow_precision_index.one_minute) - if total.made > 0 then - element.parent.non_made.visible = false +-- Updates a prodution label to match the current data +local function update_production_label(parent,production_label_data) + local name = production_label_data.name + local tooltip = production_label_data.tooltip + local color = production_label_data.color - local icon_style = 'quick_bar_slot_button' - local flux = Production.get_fluctuations(player.force, science_pack, defines.flow_precision_index.one_minute) - if flux.net > -config.color_flux/2 then - icon_style = 'green_slot_button' - elseif flux.net < -config.color_flux then - icon_style = 'red_slot_button' - elseif minute.made > 0 then - icon_style = 'selected_slot_button' - end + -- Update the production label + local production_label_element = parent[name] and parent[name].label or production_label(parent,production_label_data) + production_label_element.caption = production_label_data.caption + production_label_element.tooltip = production_label_data.tooltip + production_label_element.style.font_color = color - local icon = element['icon-'..science_pack] + -- Update the surfix label + local surfix_element = parent['surfix-'..name] + surfix_element.caption = {'science-info.unit',production_label_data.surfix} + surfix_element.tooltip = tooltip + surfix_element.style.font_color = color - if icon then - icon.style = icon_style - icon.style.height = 55 - if icon_style == 'quick_bar_slot_button' then - icon.style.width = 36 - Gui.set_padding(icon,0,0,-2,-2) - end - - else - icon = - element.add{ - name='icon-'..science_pack, - type='sprite-button', - sprite='item/'..science_pack, - tooltip={'item-name.'..science_pack}, - style=icon_style - } - icon.style.height = 55 - if icon_style == 'quick_bar_slot_button' then - icon.style.width = 36 - Gui.set_padding(icon,0,0,-2,-2) - end - - end - - local delta = element['delta-'..science_pack] - - if not delta then - delta = - element.add{ - name='delta-'..science_pack, - type='frame', - style='bordered_frame' - } - Gui.set_padding(delta,0,0,3,3) - - local delta_table = - delta.add{ - name='table', - type='table', - column_count=2 - } - Gui.set_padding(delta_table) - end - - add_data_label(delta.table,'pos-'..science_pack,minute.made,nil,{'science-info.pos-tooltip',total.made}) - add_data_label(delta.table,'neg-'..science_pack,-minute.used,nil,{'science-info.neg-tooltip',total.used}) - add_data_label(element,'net-'..science_pack,minute.net,minute.made+minute.used,{'science-info.net-tooltip',total.net}) - end end ---- Updates the eta label that was created with generate_container -local function update_eta(player,element) - if not config.show_eta then return end +--- Adds 4 elements that show the data for a science pack +-- @element science_pack_base +local science_pack_base = +Gui.element(function(_,parent,science_pack_data) + local science_pack = science_pack_data.science_pack + + -- Draw the icon for the science pack + local icon_style = science_pack_data.icon_style + local pack_icon = + parent.add{ + name = 'icon-'..science_pack, + type = 'sprite-button', + sprite = 'item/'..science_pack, + tooltip = {'item-name.'..science_pack}, + style = icon_style + } + + -- Change the style of the icon + local pack_icon_style = pack_icon.style + pack_icon_style.height = 55 + if icon_style == 'quick_bar_slot_button' then + pack_icon_style.padding = {0,-2} + pack_icon_style.width = 36 + end + + -- Draw the delta flow + local delta_flow = + parent.add{ + name = 'delta-'..science_pack, + type = 'frame', + style = 'bordered_frame' + } + delta_flow.style.padding = {0,3} + + -- Draw the delta flow table + local delta_table = + delta_flow.add{ + name = 'table', + type = 'table', + column_count = 2 + } + delta_table.style.padding = 0 + + -- Draw the production labels + update_production_label(delta_table,science_pack_data.positive) + update_production_label(delta_table,science_pack_data.negative) + update_production_label(parent,science_pack_data.net) + + -- Return the pack icon + return pack_icon +end) + +local function get_science_pack_data(player,science_pack) local force = player.force + + -- Check that some packs have been made + local total = Production.get_production_total(force, science_pack) + local minute = Production.get_production(force, science_pack, defines.flow_precision_index.one_minute) + if total.made == 0 then + return + end + + -- Get the icon style + local icon_style = 'quick_bar_slot_button' + local flux = Production.get_fluctuations(force, science_pack, defines.flow_precision_index.one_minute) + if minute.net > 0 and flux.net > -config.color_flux/2 then + icon_style = 'green_slot_button' + elseif flux.net < -config.color_flux then + icon_style = 'red_slot_button' + elseif minute.made > 0 then + icon_style = 'selected_slot_button' + end + + -- Return the pack data + return { + science_pack = science_pack, + icon_style = icon_style, + positive = get_production_label_data( + 'pos-'..science_pack, + {'science-info.pos-tooltip', total.made}, + minute.made + ), + negative = get_production_label_data( + 'neg-'..science_pack, + {'science-info.neg-tooltip', total.used}, + -minute.used + ), + net = get_production_label_data( + 'net-'..science_pack, + {'science-info.net-tooltip', total.net}, + minute.net, + minute.made+minute.used + ) + } + +end + +local function update_science_pack(pack_table,science_pack_data) + if not science_pack_data then return end + local science_pack = science_pack_data.science_pack + pack_table.parent.non_made.visible = false + + -- Update the icon + local pack_icon = pack_table['icon-'..science_pack] or science_pack_base(pack_table,science_pack_data) + local icon_style = science_pack_data.icon_style + pack_icon.style = icon_style + + local pack_icon_style = pack_icon.style + pack_icon_style.height = 55 + if icon_style == 'quick_bar_slot_button' then + pack_icon_style.padding = {0,-2} + pack_icon_style.width = 36 + end + + -- Update the production labels + local delta_table = pack_table['delta-'..science_pack].table + update_production_label(delta_table,science_pack_data.positive) + update_production_label(delta_table,science_pack_data.negative) + update_production_label(pack_table,science_pack_data.net) + +end + +--- Gets the data that is used with the eta label +local function get_eta_label_data(player) + local force = player.force + + -- If there is no current research then return no research local research = force.current_research if not research then - element.caption = null_time_short - element.tooltip = null_time_long + return { research = false } + end - else - local progress = force.research_progress - local remaining = research.research_unit_count*(1-progress) - local limit - - local stats = player.force.item_production_statistics - for _,ingredient in pairs(research.research_unit_ingredients) do - local pack_name = ingredient.name - local required = ingredient.amount * remaining - local time = Production.get_consumsion_eta(force, pack_name, defines.flow_precision_index.one_minute, required) - if not limit or limit < time then - limit = time - end - end - - if not limit or limit == -1 then - element.caption = null_time_short - element.tooltip = null_time_long - - else - element.caption = {'science-info.eta-time',format_time(limit,{hours=true,minutes=true,seconds=true,time=true})} - element.tooltip = format_time(limit,{hours=true,minutes=true,seconds=true,long=true}) + local limit + local progress = force.research_progress + local remaining = research.research_unit_count*(1-progress) + -- Check for the limiting science pack + for _,ingredient in pairs(research.research_unit_ingredients) do + local pack_name = ingredient.name + local required = ingredient.amount * remaining + local time = Production.get_consumsion_eta(force, pack_name, defines.flow_precision_index.one_minute, required) + if not limit or limit < time then + limit = time end end + + -- Return the caption and tooltip + return limit and limit > 0 and { + research = true, + caption = format_time(limit,{hours=true,minutes=true,seconds=true,time=true}), + tooltip = format_time(limit,{hours=true,minutes=true,seconds=true,long=true}) + } or { research = false } + end ---- Registers the science info --- @element science_info -local science_info = -Gui.new_left_frame('gui/science-info') -:set_sprites('entity/lab') -:set_direction('vertical') -:set_tooltip{'science-info.main-tooltip'} -:on_creation(function(player,element) - local table, eta = generate_container(element) - - for _,science_pack in ipairs(config) do - generate_science_pack(player,table,science_pack) +-- Updates the eta label +local function update_eta_label(element,eta_label_data) + -- If no research selected show null + if not eta_label_data.research then + element.caption = null_time_short + element.tooltip = null_time_long + return end - update_eta(player,eta) + -- Update the element + element.caption = {'science-info.eta-time',eta_label_data.caption} + element.tooltip = eta_label_data.tooltip +end + +--- Main task list container for the left flow +-- @element task_list_container +local science_info_container = +Gui.element(function(event_trigger,parent) + local player = Gui.get_player_from_element(parent) + + -- Draw the internal container + local container = Gui.container(parent,event_trigger,200) + + -- Draw the header + Gui.header(container, {'science-info.main-caption'}, {'science-info.main-tooltip'}) + + -- Draw the scroll table for the tasks + local scroll_table = Gui.scroll_table(container,178,4) + + -- Draw the no packs label + local no_packs_label = + scroll_table.parent.add{ + name = 'non_made', + type = 'label', + caption = {'science-info.no-packs'} + } + + -- Change the style of the no packs label + local no_packs_style = no_packs_label.style + no_packs_style.padding = {2,4} + no_packs_style.single_line = false + no_packs_style.width = 200 + + -- Add the footer and eta + if config.show_eta then + -- Draw the footer + local footer = Gui.footer(container, {'science-info.eta-caption'}, {'science-info.eta-tooltip'}, true) + + -- Draw the eta label + local eta_label = + footer.add{ + name = 'label', + type = 'label', + caption = null_time_short, + tooltip = null_time_long, + style = 'heading_1_label' + } + + -- Update the eta + update_eta_label(eta_label,get_eta_label_data(player)) + + end + + -- Add packs which have been made + for _,science_pack in ipairs(config) do + update_science_pack(scroll_table,get_science_pack_data(player,science_pack)) + end + + -- Return the exteral container + return container.parent end) -:on_update(function(player,element) - local container = element.container - local table = container.scroll.table - local eta = container.footer.eta.label +:add_to_left_flow() - for _,science_pack in ipairs(config) do - generate_science_pack(player,table,science_pack) - end - - update_eta(player,eta) +--- Button on the top flow used to toggle the task list container +-- @element toggle_left_element +Gui.left_toolbar_button('entity/lab', {'science-info.main-tooltip'}, science_info_container, function(player) + return Roles.player_allowed(player,'gui/science-info') end) --- Updates the gui every 1 second -Event.on_nth_tick(60,science_info 'update_all') +Event.on_nth_tick(60,function() + local force_pack_data = {} + local force_eta_data = {} + for _,player in pairs(game.connected_players) do + local force_name = player.force.name + local frame = Gui.get_left_element(player,science_info_container) + local container = frame.container -return science_info \ No newline at end of file + -- Update the science packs + local scroll_table = container.scroll.table + local pack_data = force_pack_data[force_name] + if not pack_data then + -- No data in chache so it needs to be generated + pack_data = {} + force_pack_data[force_name] = pack_data + for _,science_pack in ipairs(config) do + local next_data = get_science_pack_data(player,science_pack) + pack_data[science_pack] = next_data + update_science_pack(scroll_table,next_data) + end + + else + -- Data found in chache is no need to generate it + for _,next_data in ipairs(pack_data) do + update_science_pack(scroll_table,next_data) + end + + end + + -- Update the eta times + if not config.show_eta then return end + local eta_label = container.footer.alignment.label + local eta_data = force_eta_data[force_name] + if not eta_data then + -- No data in chache so it needs to be generated + eta_data = get_eta_label_data(player) + force_eta_data[force_name] = eta_data + update_eta_label(eta_label,eta_data) + + else + -- Data found in chache is no need to generate it + update_eta_label(eta_label,eta_data) + + end + + end +end) \ No newline at end of file diff --git a/modules/gui/task-list.lua b/modules/gui/task-list.lua index d82a3a77..b8b260b0 100644 --- a/modules/gui/task-list.lua +++ b/modules/gui/task-list.lua @@ -1,5 +1,5 @@ --[[-- Gui Module - Task List - - Adds a task list to the game which players can add remove and edit items on + - Adds a task list to the game which players can add, remove and edit items on @gui Task-List @alias task_list ]] @@ -11,338 +11,406 @@ local config = require 'config.tasks' --- @dep config.tasks local format_time,table_keys = ext_require('expcore.common','format_time','table_keys') --- @dep expcore.common local Tasks = require 'modules.control.tasks' --- @dep modules.control.tasks +-- Styles used for sprite buttons +local Styles = { + sprite20 = Gui.sprite_style(20), + sprite22 = Gui.sprite_style(20, nil, { right_margin = -3 }) +} + --- If a player is allowed to use the edit buttons -local function player_allowed_edit(player,task) +local function check_player_permissions(player,task) if task then + -- When a task is given check if the player can edit it + local allow_edit_task = config.allow_edit_task + + -- Check if the player being the last to edit will override existing permisisons if config.user_can_edit_own_tasks and task.last_edit_name == player.name then return true end - else - if config.any_user_can_add_new_task then + + -- Check player has permisison based on value in the config + if allow_edit_task == 'all' then return true + elseif allow_edit_task == 'admin' then + return player.admin + elseif allow_edit_task == 'expcore.roles' then + return Roles.player_allowed(player,config.edit_tasks_role_permission) end - end - if config.only_admins_can_edit and not player.admin then + -- Return false as all other condidtions have not been met + return false + else + -- When a task is not given check if the player can add a new task + local allow_add_task = config.allow_add_task + + -- Check player has permisison based on value in the config + if allow_add_task == 'all' then + return true + elseif allow_add_task == 'admin' then + return player.admin + elseif allow_add_task == 'expcore.roles' then + return Roles.player_allowed(player,config.expcore_roles_add_permission) + end + + -- Return false as all other condidtions have not been met return false end - - if config.edit_tasks_role_permission and not Roles.player_allowed(player,config.edit_tasks_role_permission) then - return false - end - - return true end ---- Button in the header to add a new task +--- Button displayed in the ehader bar, used to add a new task -- @element add_new_task local add_new_task = -Gui.new_button() -:set_sprites('utility/add') -:set_tooltip{'task-list.add-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) -:on_click(function(player,element) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/add', + tooltip = {'task-list.add-tooltip'}, + style = 'tool_button' +} +:style(Styles.sprite20) +:on_click(function(player,_,_) Tasks.add_task(player.force.name,nil,player.name) end) ---- Used to save changes to a task --- @element confirm_edit -local confirm_edit = -Gui.new_button() -:set_sprites('utility/downloaded') -:set_tooltip{'task-list.confirm-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 +--- Button displayed next to tasks which the user is can edit, used to start editing a task +-- @element edit_task +local edit_task = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/rename_icon_normal', + tooltip = {'task-list.edit-tooltip-none'}, + style = 'tool_button' +} +:style(Styles.sprite20) +:on_click(function(player,element,_) + local task_id = element.parent.name:sub(6) + Tasks.set_editing(task_id,player.name,true) end) -:on_click(function(player,element) + +--- Button displayed next to tasks which the user is can edit, used to delete a task from the list +-- @element discard_task +local discard_task = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/trash', + tooltip = {'task-list.discard-tooltip'}, + style = 'tool_button' +} +:style(Styles.sprite20) +:on_click(function(_,element,_) + local task_id = element.parent.name:sub(6) + Tasks.remove_task(task_id) +end) + +--- Set of three elements which make up each row of the task table +-- @element add_task_base +local add_task_base = +Gui.element(function(_,parent,task_id) + -- Add the task number label + local task_number = parent.add{ + name = 'count-'..task_id, + type = 'label', + caption = '0)' + } + task_number.style.left_margin = 1 + + -- Add a flow which will contain the task message and edit buttons + local task_flow = parent.add{ name = task_id, type = 'flow', } + task_flow.style.padding = 0 + + -- Add the two edit buttons outside the task flow + local edit_flow = Gui.alignment(parent,'edit-'..task_id) + edit_task(edit_flow) + discard_task(edit_flow) + + -- Return the task flow as the main element + return task_flow +end) + +-- Removes the three elements that are added as part of the task base +local function remove_task_base(parent,task_id) + Gui.destroy_if_valid(parent['count-'..task_id]) + Gui.destroy_if_valid(parent['edit-'..task_id]) + Gui.destroy_if_valid(parent[task_id]) +end + +--- Button displayed next to tasks which the user is currently editing, used to save changes +-- @element confirm_edit +local task_editing +local confirm_edit = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/downloaded', + tooltip = {'task-list.confirm-tooltip'}, + style = 'shortcut_bar_button_green' +} +:style(Styles.sprite22) +:on_click(function(player,element,_) local task_id = element.parent.name - local new_message = element.parent.task.text + local new_message = element.parent[task_editing.name].text Tasks.set_editing(task_id,player.name) Tasks.update_task(task_id,new_message,player.name) end) ---- Used to cancel any changes you made to a task +--- Button displayed next to tasks which the user is currently editing, used to discard changes -- @element cancel_edit local cancel_edit = -Gui.new_button() -:set_sprites('utility/close_black') -:set_tooltip{'task-list.cancel-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) -:on_click(function(player,element) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/close_black', + tooltip = {'task-list.cancel-tooltip'}, + style = 'shortcut_bar_button_red' +} +:style(Styles.sprite22) +:on_click(function(player,element,_) local task_id = element.parent.name Tasks.set_editing(task_id,player.name) end) ---- Removes the task from the list --- @element discard_task -local discard_task = -Gui.new_button() -:set_sprites('utility/trash') -:set_tooltip{'task-list.discard-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 +--- Editing state for a task, contrins a text field and the two edit buttons +-- @element task_editing +task_editing = +Gui.element(function(event_trigger,parent,task) + local message = task.message + + -- Draw the element + local element = + parent.add{ + name = event_trigger, + type = 'textfield', + text = message, + clear_and_focus_on_right_click = true + } + + -- Add the edit buttons + cancel_edit(parent) + confirm_edit(parent) + + -- Return the element + return element end) -:on_click(function(player,element) +:style{ + maximal_width = 110, + height = 20 +} +:on_confirmed(function(player,element,_) local task_id = element.parent.name - Tasks.remove_task(task_id) + local new_message = element.text + Tasks.set_editing(task_id,player.name) + Tasks.update_task(task_id,new_message,player.name) end) ---- Opens edit mode for the task --- @element edit_task -local edit_task = -Gui.new_button() -:set_sprites('utility/rename_icon_normal') -:set_tooltip{'task-list.edit-tooltip-none'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) -:on_click(function(player,element) - local task_id = element.parent.name - Tasks.set_editing(task_id,player.name,true) +--- Default state for a task, contains only a label with the task message +-- @element task_label +local task_label = +Gui.element(function(_,parent,task) + local message = task.message + local last_edit_name = task.last_edit_name + local last_edit_time = task.last_edit_time + -- Draw the element + return parent.add{ + name = task_editing.name, + type = 'label', + caption = message, + tooltip = {'task-list.last-edit', last_edit_name, format_time(last_edit_time)} + } end) +:style{ + single_line = false, + maximal_width = 150 +} ---[[ Generates each task, handles both view and edit mode - element - > count-"task_id" - >> label - > "task_id" - >> task - >> cancel_edit (edit mode) - >> confirm_edit (edit mode) - > edit-"task_id" - >> edit_task - >> discard_task -]] -local function generate_task(player,element,task_id) +--- Updates a task for a player +local function update_task(player,task_table,task_id) local task = Tasks.get_task(task_id) local task_ids = Tasks.get_force_task_ids(player.force.name) local task_number = table.index_of(task_ids, task_id) + -- Task no longer exists so should be removed from the list if not task then - -- task is nil so remove it from the list - element.parent.no_tasks.visible = #task_ids == 1 - Gui.destroy_if_valid(element['count-'..task_id]) - Gui.destroy_if_valid(element['edit-'..task_id]) - Gui.destroy_if_valid(element[task_id]) - - else - local message = task.message - local editing = task.curently_editing[player.name] - local last_edit_name = task.last_edit_name - local last_edit_time = task.last_edit_time - - element.parent.no_tasks.visible = false - -- if it is not already present then add it now - local task_area = element[task_id] - if not task_area then - -- label to show the task number - element.add{ - name='count-'..task_id, - type='label', - caption=task_number..')' - } - - -- area which stores the task and buttons - task_area = - element.add{ - name=task_id, - type='flow', - } - Gui.set_padding(task_area) - - -- if the player can edit then it adds the edit and delete button - local flow = Gui.create_alignment(element,'edit-'..task_id) - local sub_flow = flow.add{type='flow',name=task_id} - - edit_task(sub_flow) - discard_task(sub_flow) - - end - - -- update the number indexes and the current editing players - element['count-'..task_id].caption = task_number..')' - - local edit_area = element['edit-'..task_id][task_id] - local players = table_keys(task.editing) - local allowed = player_allowed_edit(player,task) - - edit_area.visible = allowed - - if #players > 0 then - edit_area[edit_task.name].tooltip = {'task-list.edit-tooltip',table.concat(players,', ')} - else - edit_area[edit_task.name].tooltip = {'task-list.edit-tooltip-none'} - end - - -- draws/updates the task area - local element_type = task_area.task and task_area.task.type or nil - if not editing and element_type == 'label' then - -- update the label already present - task_area.task.caption = message - task_area.task.tooltip = {'task-list.last-edit',last_edit_name,format_time(last_edit_time)} - - elseif not editing then - -- create the label, view mode - if edit_area then - edit_area[edit_task.name].enabled = true - end - - task_area.clear() - - local label = - task_area.add{ - name='task', - type='label', - caption=message, - tooltip={'task-list.last-edit',last_edit_name,format_time(last_edit_time)} - } - label.style.single_line = false - label.style.maximal_width = 150 - - elseif editing and element_type ~= 'textfield' then - -- create the text field, edit mode, update it omitted as value is being edited - if edit_area then - edit_area[edit_task.name].enabled = false - end - - task_area.clear() - - local entry = - task_area.add{ - name='task', - type='textfield', - text=message - } - entry.style.maximal_width = 150 - entry.style.height = 20 - - cancel_edit(task_area) - confirm_edit(task_area) - - end - + task_table.parent.no_tasks.visible = #task_ids == 0 + remove_task_base(task_table,task_id) + return end + -- Get the task flow for this task + local task_flow = task_table[task_id] or add_task_base(task_table,task_id) + task_table.parent.no_tasks.visible = false + task_table['count-'..task_id].caption = task_number..')' + + -- Update the edit flow + local edit_flow = task_table['edit-'..task_id] + local player_allowed_edit = check_player_permissions(player,task) + local players_editing = table_keys(task.curently_editing) + local edit_task_element = edit_flow[edit_task.name] + local discard_task_element = edit_flow[discard_task.name] + + edit_task_element.visible = player_allowed_edit + discard_task_element.visible = player_allowed_edit + if #players_editing > 0 then + edit_task_element.hovered_sprite = 'utility/warning_icon' + edit_task_element.tooltip = {'task-list.edit-tooltip',table.concat(players_editing,', ')} + else + edit_task_element.hovered_sprite = edit_task_element.sprite + edit_task_element.tooltip = {'task-list.edit-tooltip-none'} + end + + -- Check if the player is was editing and/or currently editing + local task_entry = task_flow[task_editing.name] or task_label(task_flow,task) + local player_was_editing = task_entry.type == 'textfield' + local player_is_editing = task.curently_editing[player.name] + + -- Update the task flow + if not player_was_editing and not player_is_editing then + -- Update the task message label + local message = task.message + local last_edit_name = task.last_edit_name + local last_edit_time = task.last_edit_time + task_entry.caption = message + task_entry.tooltip = {'task-list.last-edit', last_edit_name, format_time(last_edit_time)} + + elseif player_was_editing and not player_is_editing then + -- Player was editing but is no longer, remove text field and add label + edit_task_element.enabled = true + task_flow.clear() + task_label(task_flow,task) + + elseif not player_was_editing and player_is_editing then + -- Player was not editing but now is, remove label and add text field + edit_task_element.enabled = false + task_flow.clear() + task_editing(task_flow,task).focus() + task_table.parent.scroll_to_element(task_flow,'top-third') + + end end ---[[ generates the main gui structure - element - > container - >> header - >>> right aligned add_new_task - >> scroll - >>> no_tasks - >>> table -]] -local function generate_container(player,element) - Gui.set_padding(element,2,2,2,2) - element.style.minimal_width = 200 +-- Update all the tasks for a player +local function update_all_tasks(player,scroll_table) + local task_ids = Tasks.get_force_task_ids(player.force.name) + if #task_ids > 0 then + for _,task_id in ipairs(task_ids) do + update_task(player,scroll_table,task_id) + end + end +end - -- main container which contains the other elements - local container = - element.add{ - name='container', - type='frame', - direction='vertical', - style='window_content_frame_packed' - } - Gui.set_padding(container) - container.style.vertically_stretchable = false +--- Main task list container for the left flow +-- @element task_list_container +local task_list_container = +Gui.element(function(event_trigger,parent) + -- Draw the internal container + local container = Gui.container(parent,event_trigger,200) - -- main header for the gui - local header_area = Gui.create_header( + -- Draw the header + local header = Gui.header( container, {'task-list.main-caption'}, {'task-list.sub-tooltip'}, true ) - --- Right aligned button to toggle the section - if player_allowed_edit(player) then - add_new_task(header_area) - end + -- Draw the new task button + local player = Gui.get_player_from_element(parent) + local add_new_task_element = add_new_task(header) + add_new_task_element.visible = check_player_permissions(player) - -- table that stores all the data - local flow_table = Gui.create_scroll_table(container,3,185) - flow_table.draw_horizontal_lines = true - flow_table.vertical_centering = false - flow_table.style.top_cell_padding = 3 - flow_table.style.bottom_cell_padding = 3 + -- Draw the scroll table for the tasks + local scroll_table = Gui.scroll_table(container,190,3) + scroll_table.draw_horizontal_lines = true + scroll_table.vertical_centering = false - -- message to say that you have no tasks - local non_made = - flow_table.parent.add{ - name='no_tasks', - type='label', - caption={'task-list.no-tasks'} + -- Change the style of the scroll table + local scroll_table_style = scroll_table.style + scroll_table_style.top_cell_padding = 3 + scroll_table_style.bottom_cell_padding = 3 + + -- Draw the no tasks label + local no_tasks_label = + scroll_table.parent.add{ + name = 'no_tasks', + type = 'label', + caption = {'task-list.no-tasks'} } - non_made.style.width = 200 - non_made.style.single_line = false - return flow_table -end + -- Change the style of the no tasks label + local no_tasks_style = no_tasks_label.style + no_tasks_style.padding = {2,4} + no_tasks_style.single_line = false + no_tasks_style.width = 200 ---- Registers the task list --- @element task_list -local task_list = -Gui.new_left_frame('gui/task-list') -:set_sprites('utility/not_enough_repair_packs_icon') -:set_direction('vertical') -:set_tooltip{'task-list.main-tooltip'} -:set_open_by_default() -:on_creation(function(player,element) - local data_table = generate_container(player,element) + -- Add any existing tasks local task_ids = Tasks.get_force_task_ids(player.force.name) - - for _,task_id in pairs(task_ids) do - generate_task(player,data_table,task_id) + if #task_ids > 0 then + no_tasks_style.visible = false + for _,task_id in ipairs(task_ids) do + update_task(player,scroll_table,task_id) + end end + + -- Return the exteral container + return container.parent end) -:on_update(function(player,element) - local data_table = element.container.scroll.table +:add_to_left_flow(function(player) local task_ids = Tasks.get_force_task_ids(player.force.name) + return #task_ids > 0 +end) - for _,task_id in pairs(task_ids) do - generate_task(player,data_table,task_id) - end +--- Button on the top flow used to toggle the task list container +-- @element toggle_left_element +Gui.left_toolbar_button('utility/not_enough_repair_packs_icon', {'task-list.main-tooltip'}, task_list_container, function(player) + return Roles.player_allowed(player,'gui/task-list') end) --- When a new task is added it will udpate the task list for everyone on that force -Tasks.on_update(function(task,task_id) - local players +Tasks.on_update(function(task,task_id,removed_task) + -- Get the force to update, task is nil when removed + local force if task then - local force = game.forces[task.force_name] - players = force.connected_players + force = game.forces[task.force_name] else - players = game.connected_players + force = game.forces[removed_task.force_name] end - for _,player in pairs(players) do - local frame = task_list:get_frame(player) - local element = frame.container.scroll.table - generate_task(player,element,task_id) + -- Update the task for all the players on the force + local task_ids = Tasks.get_force_task_ids(force.name) + for _,player in pairs(force.connected_players) do + local frame = Gui.get_left_element(player,task_list_container) + local scroll_table = frame.container.scroll.table + + -- Update the task that was changed + update_task(player,scroll_table,task_id) + + -- Update the numbering of the other tasks if the task was removed + if not task then + for task_number, next_task_id in pairs(task_ids) do + scroll_table['count-'..next_task_id].caption = task_number..')' + end + end end + end) --- Update the tasks when the player joins -Event.add(defines.events.on_player_joined_game,task_list 'redraw') +Event.add(defines.events.on_player_joined_game,function(event) + local player = game.players[event.player_index] + local frame = Gui.get_left_element(player,task_list_container) + local scroll_table = frame.container.scroll.table + update_all_tasks(player,scroll_table) +end) --- Makes sure the right buttons are present when roles change -Event.add(Roles.events.on_role_assigned,task_list 'redraw') -Event.add(Roles.events.on_role_unassigned,task_list 'redraw') +local function role_update_event(event) + local player = game.players[event.player_index] + local container = Gui.get_left_element(player,task_list_container).container -return task_list \ No newline at end of file + -- Update the tasks, incase the user can now edit them + local scroll_table = container.scroll.table + update_all_tasks(player,scroll_table) + + -- Update the new task button incase the user can now add them + local add_new_task_element = container.header.alignment[add_new_task.name] + add_new_task_element.visible = check_player_permissions(player) +end + +Event.add(Roles.events.on_role_assigned,role_update_event) +Event.add(Roles.events.on_role_unassigned,role_update_event) \ No newline at end of file diff --git a/modules/gui/warp-list.lua b/modules/gui/warp-list.lua index d5d12a4f..de92d42e 100644 --- a/modules/gui/warp-list.lua +++ b/modules/gui/warp-list.lua @@ -20,137 +20,154 @@ local player_in_range_store = Store.register(function(player) return player.name end) +-- Stores the time remaing for a players warp cooldown +local player_warp_cooldown_store = Store.register(function(player) + return player.name +end) + -- Table that stores a boolean value of weather to keep the warp gui open local keep_gui_open = {} Global.register(keep_gui_open,function(tbl) keep_gui_open = tbl end) +-- Styles used for sprite buttons +local Styles = { + sprite20 = Gui.sprite_style(20), + sprite22 = Gui.sprite_style(20, nil, { right_margin = -3 }), + sprite32 = { height = 32, width = 32, left_margin = 1 } +} + --- Returns if a player is allowed to edit the given warp -local function player_allowed_edit(player,warp) - if warp then +--- If a player is allowed to use the edit buttons +local function check_player_permissions(player,action,warp) + -- Check if the action is allow edit and then check bypass settings + if action == 'allow_edit_warp' then + -- Check if the warp is the spawn then it cant be edited local spawn_id = Warps.get_spawn_warp_id(player.force.name) if spawn_id == warp.warp_id then return false end + + -- Check if the player being the last to edit will override existing permisisons if config.user_can_edit_own_warps and warp.last_edit_name == player.name then return true end - else - if config.any_user_can_add_new_warp then - return true - end end - if config.only_admins_can_edit and not player.admin then - return false + -- Check player has permisison based on value in the config + local action_config = config[action] + if action_config == 'all' then + return true + elseif action_config == 'admin' then + return player.admin + elseif action_config == 'expcore.roles' then + return Roles.player_allowed(player,config['expcore_roles_'..action]) end - if config.edit_warps_role_permission and not Roles.player_allowed(player,config.edit_warps_role_permission) then - return false - end - - return true + -- Return false as all other condidtions have not been met + return false end ---- Used on the name label to allow zoom to map --- @element zoom_to_map -local zoom_to_map_name = Gui.uid_name() -Gui.on_click(zoom_to_map_name,function(event) - local warp_id = event.element.parent.name - local warp = Warps.get_warp(warp_id) - local position = warp.position - event.player.zoom_to_world(position,1.5) -end) - - ---- This timer controls when a player is able to warp, eg every 60 seconds --- @element warp_timer -local warp_timer = -Gui.new_progressbar() -:set_tooltip{'warp-list.timer-tooltip',config.recharge_time} -:set_default_maximum(math.floor(config.recharge_time*config.update_smoothing)) -:add_store(Gui.categorize_by_player) -:set_style(nil,function(style) - style.horizontally_stretchable = true - style.color = Colors.light_blue -end) -:on_store_complete(function(player_name,reset) - Store.trigger(player_in_range_store,player_name) -end) - ---- When the button is clicked it will teleport the player --- @element goto_warp -local goto_warp = -Gui.new_button() -:set_sprites('item/'..config.default_icon) -:set_tooltip{'warp-list.goto-tooltip',0,0} -:set_style('quick_bar_slot_button',function(style) - style.height = 32 - style.width = 32 -end) -:on_click(function(player,element) - local warp_id = element.parent.caption - Warps.teleport_player(warp_id,player) - - -- Reset the warp cooldown if the player does not have unlimited warps - if config.bypass_warp_limits_permission and not Roles.player_allowed(player,config.bypass_warp_limits_permission) then - warp_timer:set_store(player.name,0) - Store.trigger(player_in_range_store,player) - end -end) - --- Will add a new warp to the list, checks if the player is too close to an existing one -- @element add_new_warp local add_new_warp = -Gui.new_button() -:set_sprites('utility/add') -:set_tooltip{'warp-list.add-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) -:on_click(function(player,element) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/add', + tooltip = {'warp-list.add-tooltip'}, + style = 'tool_button' +} +:style(Styles.sprite20) +:on_click(function(player,_) + -- Add the new warp local force_name = player.force.name local surface = player.surface local position = player.position - local px = position.x - local py = position.y - local dist2 = config.minimum_distance^2 - - -- Check the distance to all existing warps - local warp_ids = Warps.get_force_warp_ids(force_name) - for _,warp_id in pairs(warp_ids) do - local warp = Warps.get_warp(warp_id) - local pos = warp.position - if surface == warp.surface and (px-pos.x)^2+(py-pos.y)^2 < dist2 then - player.print{'warp-list.too-close',warp.name} - return - end - end - - -- Add the new warp local warp_id = Warps.add_warp(force_name,surface,position,player.name) Warps.make_warp_tag(warp_id) Warps.make_warp_area(warp_id) end) +--- Removes a warp from the list, including the physical area and map tag +-- @element discard_warp +local discard_warp = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/trash', + tooltip = {'warp-list.discard-tooltip'}, + style = 'tool_button' +} +:style(Styles.sprite20) +:on_click(function(_,element) + local warp_id = element.parent.name:sub(6) + Warps.remove_warp(warp_id) +end) + +--- Opens edit mode for the warp +-- @element edit_warp +local edit_warp = +Gui.element{ + type = 'sprite-button', + sprite = 'utility/rename_icon_normal', + tooltip = {'warp-list.edit-tooltip-none'}, + style = 'tool_button' +} +:style(Styles.sprite20) +:on_click(function(player,element) + local warp_id = element.parent.name:sub(6) + Warps.set_editing(warp_id,player.name,true) +end) + +--- Set of three elements which make up each row of the warp table +-- @element add_warp_base +local add_warp_base = +Gui.element(function(_,parent,warp_id) + -- Add the icon flow + local icon_flow = + parent.add{ + name = 'icon-'..warp_id, + type = 'flow', + caption = warp_id + } + icon_flow.style.padding = 0 + + -- Add a flow which will contain the warp name and edit buttons + local warp_flow = parent.add{ type = 'flow', name = warp_id } + warp_flow.style.padding = 0 + + -- Add the two edit buttons outside the warp flow + local edit_flow = Gui.alignment(parent,'edit-'..warp_id) + edit_warp(edit_flow) + discard_warp(edit_flow) + + -- Return the warp flow as the main element + return warp_flow +end) + +-- Removes the three elements that are added as part of the warp base +local function remove_warp_base(parent,warp_id) + Gui.destroy_if_valid(parent['icon-'..warp_id]) + Gui.destroy_if_valid(parent['edit-'..warp_id]) + Gui.destroy_if_valid(parent[warp_id]) +end + --- Confirms the edit to name or icon of the warp -- @element confirm_edit +local warp_editing +local warp_icon_button local confirm_edit = -Gui.new_button() -:set_sprites('utility/downloaded') -:set_tooltip{'warp-list.confirm-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/downloaded', + tooltip = {'warp-list.confirm-tooltip'}, + style = 'shortcut_bar_button_green' +} +:style(Styles.sprite22) :on_click(function(player,element) local warp_id = element.parent.name - local warp_name = element.parent.warp.text - local warp_icon = element.parent.parent['icon-'..warp_id].icon.elem_value + local warp_name = element.parent[warp_editing.name].text + local warp_icon = element.parent.parent['icon-'..warp_id][warp_icon_button.name].elem_value Warps.set_editing(warp_id,player.name) Warps.update_warp(warp_id,warp_name,warp_icon,player.name) end) @@ -158,360 +175,396 @@ end) --- Cancels the editing changes of the selected warp name or icon -- @element cancel_edit local cancel_edit = -Gui.new_button() -:set_sprites('utility/close_black') -:set_tooltip{'warp-list.cancel-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 -end) +Gui.element{ + type = 'sprite-button', + sprite = 'utility/close_black', + tooltip = {'warp-list.cancel-tooltip'}, + style = 'shortcut_bar_button_red' +} +:style(Styles.sprite22) :on_click(function(player,element) local warp_id = element.parent.name Warps.set_editing(warp_id,player.name) end) ---- Removes a warp from the list, including the physical area and map tag --- @element discard_warp -local discard_warp = -Gui.new_button() -:set_sprites('utility/trash') -:set_tooltip{'warp-list.discard-tooltip'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 +--- Editing state for a warp, contrins a text field and the two edit buttons +-- @element warp_editing +warp_editing = +Gui.element(function(event_trigger,parent,warp) + local name = warp.name + + -- Draw the element + local element = + parent.add{ + name = event_trigger, + type = 'textfield', + text = name, + clear_and_focus_on_right_click = true + } + + -- Add the edit buttons + cancel_edit(parent) + confirm_edit(parent) + + -- Return the element + return element end) -:on_click(function(player,element) +:style{ + maximal_width = 110, + height = 20 +} +:on_confirmed(function(player,element,_) local warp_id = element.parent.name - Warps.remove_warp(warp_id) + local warp_name = element.text + local warp_icon = element.parent.parent['icon-'..warp_id][warp_icon_button.name].elem_value + Warps.set_editing(warp_id,player.name) + Warps.update_warp(warp_id,warp_name,warp_icon,player.name) end) ---- Opens edit mode for the warp --- @element edit_warp -local edit_warp = -Gui.new_button() -:set_sprites('utility/rename_icon_normal') -:set_tooltip{'warp-list.edit-tooltip-none'} -:set_style('tool_button',function(style) - Gui.set_padding_style(style,-2,-2,-2,-2) - style.height = 20 - style.width = 20 +--- Default state for a warp, contains only a label with the warp name +-- @element warp_label +local warp_label = +Gui.element(function(event_trigger,parent,warp) + local last_edit_name = warp.last_edit_name + local last_edit_time = warp.last_edit_time + -- Draw the element + return parent.add{ + name = event_trigger, + type = 'label', + caption = warp.name, + tooltip = {'warp-list.last-edit',last_edit_name,format_time(last_edit_time)} + } end) -:on_click(function(player,element) +:style{ + single_line = false, + maximal_width = 150 +} +:on_click(function(player,element,_) local warp_id = element.parent.name - Warps.set_editing(warp_id,player.name,true) -end) - ---[[ Generates each warp, handles both view and edit mode - element - > icon-"warp_id" - >> goto_warp or icon - > "warp_id" - >> warp - >> cancel_edit (edit mode) - >> confirm_edit (edit mode) - > edit-"warp_id" - >> "warp_id" - >>> edit_warp - >>> discard_warp -]] -local function generate_warp(player,element,warp_id) local warp = Warps.get_warp(warp_id) + local position = warp.position + player.zoom_to_world(position,1.5) +end) + + +--- Default state for the warp icon, when pressed teleports the player +-- @element warp_icon_button +warp_icon_button = +Gui.element(function(event_trigger,parent,warp) + local warp_position = warp.position + -- Draw the element + return parent.add{ + name = event_trigger, + type = 'sprite-button', + sprite = 'item/'..warp.icon, + tooltip = {'warp-list.goto-tooltip',warp_position.x,warp_position.y}, + style = 'quick_bar_slot_button' + } +end) +:style(Styles.sprite32) +:on_click(function(player,element,_) + if element.type == 'choose-elem-button' then return end + local warp_id = element.parent.caption + Warps.teleport_player(warp_id,player) + + -- Reset the warp cooldown if the player does not have unlimited warps + if not check_player_permissions(player,'bypass_warp_cooldown') then + Store.set(player_warp_cooldown_store,player,config.cooldown_duraction) + Store.trigger(player_in_range_store,player) + end +end) + +--- Editing state for the warp icon, chose elem used to chosse icon +-- @element warp_icon_editing +local warp_icon_editing = +Gui.element(function(_,parent,warp) + return parent.add{ + name = warp_icon_button.name, + type = 'choose-elem-button', + elem_type = 'item', + item = warp.icon, + tooltip = {'warp-list.goto-edit'}, + } +end) +:style(Styles.sprite32) + +--- This timer controls when a player is able to warp, eg every 60 seconds +-- @element warp_timer +local warp_timer = +Gui.element{ + type = 'progressbar', + tooltip = {'warp-list.timer-tooltip',config.cooldown_duraction}, + minimum_value = 0, + maximum_value = config.cooldown_duraction*config.update_smoothing +} +:style{ + horizontally_stretchable = true, + color = Colors.light_blue +} + +--- Updates a warp for a player +local function update_warp(player,warp_table,warp_id) + local warp = Warps.get_warp(warp_id) + + -- Warp no longer exists so should be removed from the list if not warp then - -- warp is nil so remove it from the list - Gui.destroy_if_valid(element['icon-'..warp_id]) - Gui.destroy_if_valid(element['edit-'..warp_id]) - Gui.destroy_if_valid(element[warp_id]) - - else - local warp_name = warp.name - local warp_icon = warp.icon - local editing = warp.currently_editing[player.name] - local last_edit_name = warp.last_edit_name - local last_edit_time = warp.last_edit_time - local position = warp.position - - -- if it is not already present then add it now - local warp_area = element[warp_id] - local icon_area = element['icon-'..warp_id] - if not warp_area then - -- area to store the warp icon - icon_area = - element.add{ - name='icon-'..warp_id, - type='flow', - caption=warp_id - } - Gui.set_padding(icon_area) - - -- area which stores the warp and buttons - warp_area = - element.add{ - name=warp_id, - type='flow', - } - Gui.set_padding(warp_area) - - -- if the player can edit then it adds the edit and delete button - local flow = Gui.create_alignment(element,'edit-'..warp_id) - local sub_flow = flow.add{type='flow',name=warp_id} - - edit_warp(sub_flow) - discard_warp(sub_flow) - - end - - local edit_area = element['edit-'..warp_id][warp_id] - local players = warp.currently_editing and table_keys(warp.currently_editing) or {} - local allowed = player_allowed_edit(player,warp) - - edit_area.visible = allowed - - if #players > 0 then - edit_area[edit_warp.name].tooltip = {'warp-list.edit-tooltip',table.concat(players,', ')} - else - edit_area[edit_warp.name].tooltip = {'warp-list.edit-tooltip-none'} - end - - -- draws/updates the warp area - local label_element = warp_area.warp or warp_area[zoom_to_map_name] or nil - local element_type = label_element and label_element.type or nil - if not editing and element_type == 'label' then - -- update the label already present - label_element.caption = warp_name - label_element.tooltip = {'warp-list.last-edit',last_edit_name,format_time(last_edit_time)} - icon_area[goto_warp.name].sprite = 'item/'..warp_icon - - elseif not editing then - -- create the label, view mode - if edit_area then - edit_area[edit_warp.name].enabled = true - end - - -- redraws the icon for the warp - icon_area.clear() - - local btn = goto_warp(icon_area) - btn.sprite = 'item/'..warp_icon - btn.tooltip = {'warp-list.goto-tooltip',position.x,position.y} - - local timer = warp_timer:get_store(player.name) - local enabled = not timer and Store.get(player_in_range_store,player) - or Roles.player_allowed(player,config.bypass_warp_limits_permission) - if not enabled then - btn.enabled = false - btn.tooltip = {'warp-list.goto-disabled'} - end - - -- redraws the label for the warp name - warp_area.clear() - - local label = - warp_area.add{ - name=zoom_to_map_name, - type='label', - caption=warp_name, - tooltip={'warp-list.last-edit',last_edit_name,format_time(last_edit_time)} - } - label.style.single_line = false - label.style.maximal_width = 150 - - elseif editing and element_type ~= 'textfield' then - -- create the text field, edit mode, update it omitted as value is being edited - if edit_area then - edit_area[edit_warp.name].enabled = false - end - - -- redraws the icon for the warp and allows selection - icon_area.clear() - - local btn = - icon_area.add{ - name='icon', - type='choose-elem-button', - elem_type='item', - item=warp_icon, - tooltip={'warp-list.goto-edit'}, - } - btn.style.height = 32 - btn.style.width = 32 - - -- redraws the label for the warp name and allows editing - warp_area.clear() - - local entry = - warp_area.add{ - name='warp', - type='textfield', - text=warp_name - } - entry.style.maximal_width = 150 - entry.style.height = 20 - - cancel_edit(warp_area) - confirm_edit(warp_area) - - end - + remove_warp_base(warp_table,warp_id) + return end + -- Get the warp flow for this warp + local warp_flow = warp_table[warp_id] or add_warp_base(warp_table,warp_id) + local icon_flow = warp_table['icon-'..warp_id] + + -- Update the edit flow + local edit_flow = warp_table['edit-'..warp_id] + local player_allowed_edit = check_player_permissions(player,'allow_edit_warp',warp) + local players_editing = table_keys(warp.currently_editing) + local edit_warp_element = edit_flow[edit_warp.name] + local discard_warp_element = edit_flow[discard_warp.name] + + edit_warp_element.visible = player_allowed_edit + discard_warp_element.visible = player_allowed_edit + if #players_editing > 0 then + edit_warp_element.hovered_sprite = 'utility/warning_icon' + edit_warp_element.tooltip = {'warp-list.edit-tooltip',table.concat(players_editing,', ')} + else + edit_warp_element.hovered_sprite = edit_warp_element.sprite + edit_warp_element.tooltip = {'warp-list.edit-tooltip-none'} + end + + -- Check if the player is was editing and/or currently editing + local warp_label_element = warp_flow[warp_label.name] or warp_label(warp_flow,warp) + local icon_entry = icon_flow[warp_icon_button.name] or warp_icon_button(icon_flow,warp) + local player_was_editing = icon_entry.type == 'choose-elem-button' + local player_is_editing = warp.currently_editing[player.name] + + -- Update the warp and icon flow + if not player_was_editing and not player_is_editing then + -- Update the warp name label and icon + local warp_name = warp.name + local warp_icon = warp.icon + local last_edit_name = warp.last_edit_name + local last_edit_time = warp.last_edit_time + warp_label_element.caption = warp_name + warp_label_element.tooltip = {'warp-list.last-edit',last_edit_name,format_time(last_edit_time)} + icon_entry.sprite = 'item/'..warp_icon + + elseif player_was_editing and not player_is_editing then + -- Player was editing but is no longer, remove text field and add label + edit_warp_element.enabled = true + warp_flow.clear() + warp_label(warp_flow,warp) + + icon_flow.clear() + local warp_icon_element = warp_icon_button(icon_flow,warp) + local timer = Store.get(player_warp_cooldown_store,player) + local in_range = Store.get(player_in_range_store,player) + local apply_proximity = not check_player_permissions(player,'bypass_warp_proximity') + if (timer and timer > 0) or (apply_proximity and not in_range) then + warp_icon_element.enabled = false + warp_icon_element.tooltip = {'warp-list.goto-disabled'} + end + + elseif not player_was_editing and player_is_editing then + -- Player was not editing but now is, remove label and add text field + edit_warp_element.enabled = false + warp_flow.clear() + warp_editing(warp_flow,warp).focus() + warp_table.parent.scroll_to_element(warp_flow,'top-third') + icon_flow.clear() + warp_icon_editing(icon_flow,warp) + + end end ---[[ generates the main gui structure - element - > container - >> header - >>> right aligned add_new_warp - >> scroll - >>> table - >> warp_timer -]] -local function generate_container(player,element) - Gui.set_padding(element,2,2,2,2) - element.style.minimal_width = 200 +-- Update all the warps for a player +local function update_all_warps(player,warp_table) + local warp_ids = Warps.get_force_warp_ids(player.force.name) + if #warp_ids > 0 then + for _,warp_id in ipairs(warp_ids) do + update_warp(player,warp_table,warp_id) + end + end +end - -- main container which contains the other elements - local container = - element.add{ - name='container', - type='frame', - direction='vertical', - style='window_content_frame_packed' - } - Gui.set_padding(container) - container.style.vertically_stretchable = false +--- Main warp list container for the left flow +-- @element warp_list_container +local warp_list_container = +Gui.element(function(event_trigger,parent) + -- Draw the internal container + local container = Gui.container(parent,event_trigger,200) - -- main header for the gui - local header_area = Gui.create_header( + -- Draw the header + local header = Gui.header( container, {'warp-list.main-caption'}, - {'warp-list.sub-tooltip',config.recharge_time,config.activation_range}, + {'warp-list.sub-tooltip', config.cooldown_duraction, config.standard_proximity_radius}, true ) - --- Right aligned button to toggle the section - if player_allowed_edit(player) then - add_new_warp(header_area) + -- Draw the new warp button + local player = Gui.get_player_from_element(parent) + local add_new_warp_element = add_new_warp(header) + add_new_warp_element.visible = check_player_permissions(player,'allow_add_warp') + + -- Draw the scroll table for the warps + local scroll_table = Gui.scroll_table(container,250,3) + + -- Change the style of the scroll table + local scroll_table_style = scroll_table.style + scroll_table_style.top_cell_padding = 3 + scroll_table_style.bottom_cell_padding = 3 + + -- Draw the warp cooldown progress bar + local warp_timer_element = warp_timer(container) + + -- Change the progress of the warp timer + local progress = 1 + local timer = Store.get(player_warp_cooldown_store,player) + if timer and timer > 0 then + progress = 1 - (timer/config.cooldown_duraction) end + warp_timer_element.value = progress - -- table that stores all the data - local flow_table = Gui.create_scroll_table(container,3,258) - flow_table.style.top_cell_padding = 3 - flow_table.style.bottom_cell_padding = 3 + -- Add any existing warps + update_all_warps(player,scroll_table) - warp_timer(container) - - return flow_table -end - ---- Registers the warp list --- @element warp_list -local warp_list = -Gui.new_left_frame('gui/warp-list') -:set_sprites('item/'..config.default_icon) -:set_tooltip{'warp-list.main-tooltip',config.activation_range} -:set_direction('vertical') -:on_creation(function(player,element) - local data_table = generate_container(player,element) - local warp_ids = Warps.get_force_warp_ids(player.force.name) - - for _,warp_id in ipairs(warp_ids) do - generate_warp(player,data_table,warp_id) - end + -- Return the exteral container + return container.parent end) -:on_update(function(player,element) - local data_table = element.container.scroll.table - local warp_ids = Warps.get_force_warp_ids(player.force.name) +:add_to_left_flow() - data_table.clear() - for _,warp_id in ipairs(warp_ids) do - generate_warp(player,data_table,warp_id) - end +--- Button on the top flow used to toggle the warp list container +-- @element warp_list_toggle +Gui.left_toolbar_button('item/'..config.default_icon,{'warp-list.main-tooltip',config.standard_proximity_radius},warp_list_container, function(player) + return Roles.player_allowed(player,'gui/warp-list') end) -:on_player_toggle(function(player,element,visible) - keep_gui_open[player.name] = visible +:on_custom_event(Gui.events.on_visibility_changed_by_click, function(player,_,event) + -- Set gui keep open state for player that clicked the button: true if visible, false if invisible + keep_gui_open[player.name] = event.state end) --- When the name of a warp is updated this is triggered -Warps.on_update(function(warp) - local players - local force_name +Warps.on_update(function(warp,_,removed_warp) + -- Get the force to update, warp is nil when removed + local force if warp then - local force = game.forces[warp.force_name] - players = force.connected_players - force_name = warp.force_name + force = game.forces[warp.force_name] else - players = game.connected_players + force = game.forces[removed_warp.force_name] end -- Update the gui for selected players - local force_warps = {} - for _,player in pairs(players) do - local frame = warp_list:get_frame(player) - local element = frame.container.scroll.table - - -- Get the warp ids for the players force - force_name = force_name or player.force.name - local warp_ids = force_warps[force_name] - if not warp_ids then - warp_ids = Warps.get_force_warp_ids(force_name) - force_warps[force_name] = warp_ids - end + local warp_ids = Warps.get_force_warp_ids(force.name) + for _,player in pairs(force.connected_players) do + local frame = Gui.get_left_element(player,warp_list_container) + local scroll_table = frame.container.scroll.table -- Update the gui - element.clear() - for _,warp_id in ipairs(warp_ids) do - generate_warp(player,element,warp_id) + scroll_table.clear() + for _,next_warp_id in ipairs(warp_ids) do + update_warp(player,scroll_table,next_warp_id) end end end) --- Update the warps when the player joins -Event.add(defines.events.on_player_joined_game,warp_list 'redraw') -Event.add(Roles.events.on_role_assigned,warp_list 'redraw') -Event.add(Roles.events.on_role_unassigned,warp_list 'redraw') +Event.add(defines.events.on_player_joined_game,function(event) + local player = game.players[event.player_index] + local frame = Gui.get_left_element(player,warp_list_container) + local scroll_table = frame.container.scroll.table + update_all_warps(player,scroll_table) +end) + +--- Makes sure the right buttons are present when roles change +local function role_update_event(event) + local player = game.players[event.player_index] + local container = Gui.get_left_element(player,warp_list_container).container + + -- Update the warps, incase the user can now edit them + local scroll_table = container.scroll.table + update_all_warps(player,scroll_table) + + -- Update the new warp button incase the user can now add them + local add_new_warp_element = container.header.alignment[add_new_warp.name] + add_new_warp_element.visible = check_player_permissions(player,'allow_add_warp') +end + +Event.add(Roles.events.on_role_assigned,role_update_event) +Event.add(Roles.events.on_role_unassigned,role_update_event) --- When the player leaves or enters range of a warp this is triggered Store.watch(player_in_range_store,function(value,player_name) local player = game.players[player_name] local force = player.force - local frame = warp_list:get_frame(player_name) - local table_area = frame.container.scroll.table - local timer = warp_timer:get_store(player_name) - local state = not timer and value + -- Change if the frame is visible based on if the player is in range if not keep_gui_open[player.name] then - Gui.toggle_left_frame(warp_list.name,player,value) + Gui.toggle_left_element(player,warp_list_container,value) end - if Roles.player_allowed(player,config.bypass_warp_limits_permission) then + -- Check if the player requires proximity + if check_player_permissions(player,'bypass_warp_proximity') then return end + -- Get the warp table + local frame = Gui.get_left_element(player,warp_list_container) + local scroll_table = frame.container.scroll.table + + -- Check if the buttons should be active + local timer = Store.get(player_warp_cooldown_store,player) + local button_disabled = timer and timer > 0 or not value + + -- Change the enabled state of the warp buttons local warp_ids = Warps.get_force_warp_ids(force.name) for _,warp_id in pairs(warp_ids) do - local element = table_area['icon-'..warp_id][goto_warp.name] + local element = scroll_table['icon-'..warp_id][warp_icon_button.name] if element and element.valid then - element.enabled = state - if state then + element.enabled = not button_disabled + if button_disabled then + element.tooltip = {'warp-list.goto-disabled'} + else local position = Warps.get_warp(warp_id).position element.tooltip = {'warp-list.goto-tooltip',position.x,position.y} - else - element.tooltip = {'warp-list.goto-disabled'} end end end end) ---- Handles updating the timer and checking distance from a warp -local r2 = config.activation_range^2 -local rs2 = config.spawn_activation_range^2 -Event.on_nth_tick(math.floor(60/config.update_smoothing),function() - local categories = Store.get(warp_timer.store) or {} - for category,_ in pairs(categories) do - warp_timer:increment(1,category) +--- Update the warp cooldown progress bars to match the store +Store.watch(player_warp_cooldown_store,function(value,player_name,old_value) + if value == old_value then return end + -- Get the progress bar element + local player = game.players[player_name] + local frame = Gui.get_left_element(player,warp_list_container) + local warp_timer_element = frame.container[warp_timer.name] + + -- Set the progress + local progress = 1 + local timer = Store.get(player_warp_cooldown_store,player) + if timer and timer > 0 then + progress = 1 - (timer/config.cooldown_duraction) end + warp_timer_element.value = progress + + -- Trigger update of buttons if cooldown is now 0 + if value == 0 then + Store.trigger(player_in_range_store,player_name) + end +end) + +--- Handles updating the timer and checking distance from a warp +local r2 = config.standard_proximity_radius^2 +local rs2 = config.spawn_proximity_radius^2 +local mr2 = config.minimum_distance^2 +Event.on_nth_tick(math.floor(60/config.update_smoothing),function() + Store.map(player_warp_cooldown_store,function(value) + if value > 0 then + return value - 1 + end + end) local force_warps = {} local warps = {} @@ -527,6 +580,8 @@ Event.on_nth_tick(math.floor(60/config.update_smoothing),function() end -- Check if the force has any warps + local closest_warp + local closest_distance if #warp_ids > 0 then local surface = player.surface local pos = player.position @@ -545,20 +600,34 @@ Event.on_nth_tick(math.floor(60/config.update_smoothing),function() local warp_pos = warp.position if warp.surface == surface then local dx, dy = px-warp_pos.x, py-warp_pos.y - if (warp_id == warp_ids.spawn and (dx*dx)+(dy*dy) < rs2) or (dx*dx)+(dy*dy) < r2 then - -- Set in range to true if the player was preiovusly out of range - if not was_in_range then - Store.set(player_in_range_store,player,true) - end - was_in_range = false -- stops setting back to false below - break + local dist = (dx*dx)+(dy*dy) + if closest_distance == nil or dist < closest_distance then + closest_warp = warp + closest_distance = dist + if dist < r2 then break end end end end - -- Set in range to false if the player was preiovusly in range - if was_in_range then + -- Check the dist to the closest warp + local in_range = closest_warp.warp_id == warp_ids.spawn and closest_distance < rs2 or closest_distance < r2 + if was_in_range and not in_range then Store.set(player_in_range_store,player,false) + elseif not was_in_range and in_range then + Store.set(player_in_range_store,player,true) + end + + -- Change the enabled state of the add warp button + local frame = Gui.get_left_element(player,warp_list_container) + local add_warp_element = frame.container.header.alignment[add_new_warp.name] + local was_able_to_make_warp = add_warp_element.enabled + local can_make_warp = closest_distance > mr2 + if can_make_warp and not was_able_to_make_warp then + add_warp_element.enabled = true + add_warp_element.tooltip = {'warp-list.add-tooltip'} + elseif not can_make_warp and was_able_to_make_warp then + add_warp_element.enabled = false + add_warp_element.tooltip = {'warp-list.too-close',closest_warp.name} end end @@ -567,18 +636,10 @@ Event.on_nth_tick(math.floor(60/config.update_smoothing),function() end) ---- When a player is created it will set them being in range to false to stop warping on join +--- When a player is created make sure that there is a spawn warp created Event.add(defines.events.on_player_created,function(event) - local player = Game.get_player_by_index(event.player_index) - - -- Check if a player is allowed unlimited warps - local allowed = config.bypass_warp_limits_permission and Roles.player_allowed(player,config.bypass_warp_limits_permission) or false - Store.set(player_in_range_store,player,allowed) - if allowed then - warp_timer:set_store(player.name,1) - end - -- If the force has no spawn then make a spawn warp + local player = Game.get_player_by_index(event.player_index) local force = player.force local spawn_id = Warps.get_spawn_warp_id(force.name) if not spawn_id then @@ -590,6 +651,7 @@ Event.add(defines.events.on_player_created,function(event) end end) +--- When a chart tag is removed or edited make sure it is not one that belongs to a warp local function maintain_tag(event) if not event.player_index then return end local tag = event.tag @@ -608,6 +670,4 @@ local function maintain_tag(event) end Event.add(defines.events.on_chart_tag_modified,maintain_tag) -Event.add(defines.events.on_chart_tag_removed,maintain_tag) - -return warp_list \ No newline at end of file +Event.add(defines.events.on_chart_tag_removed,maintain_tag) \ No newline at end of file diff --git a/utils/gui.lua b/utils/gui.lua index 764037e0..36fc1d61 100644 --- a/utils/gui.lua +++ b/utils/gui.lua @@ -1,11 +1,7 @@ -local Token = require 'utils.token' --- @dep utils.token -local Event = require 'utils.event' --- @dep utils.event -local Game = require 'utils.game' --- @dep utils.game local Global = require 'utils.global' --- @dep utils.global -local mod_gui = require 'mod-gui' --- @dep mod-gui +local ExpGui = require 'expcore.gui' --- @dep expcore.gui local Gui = {} - local data = {} Global.register( @@ -15,12 +11,9 @@ Global.register( end ) -local top_elements = {} -local on_visible_handlers = {} -local on_pre_hidden_handlers = {} - function Gui.uid_name() - return tostring(Token.uid()) + local new_element = ExpGui.element() + return new_element.name end -- Associates data with the LuaGuiElement. If data is nil then removes the data @@ -75,219 +68,62 @@ function Gui.clear(element) element.clear() end -local function handler_factory(event_id) - local handlers - - local function on_event(event) - local element = event.element - if not element or not element.valid then - return - end - - local handler = handlers[element.name] - if not handler then - return - end - - local player = Game.get_player_by_index(event.player_index) - if not player or not player.valid then - return - end - event.player = player - - handler(event) - end - +local function handler_factory(event_name) return function(element_name, handler) - if not handlers then - handlers = {} - Event.add(event_id, on_event) - end - - handlers[element_name] = handler + local element = ExpGui.defines[element_name] + if not element then return end + element[event_name](element,function(_,_,event) + handler(event) + end) end end -local function custom_handler_factory(handlers) - return function(element_name, handler) - handlers[element_name] = handler - end -end - -local function custom_raise(handlers, element, player) - local handler = handlers[element.name] - if not handler then - return - end - - handler({element = element, player = player}) -end - -- Register a handler for the on_gui_checked_state_changed event for LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_checked_state_changed = handler_factory(defines.events.on_gui_checked_state_changed) +Gui.on_checked_state_changed = handler_factory('on_checked_changed') -- Register a handler for the on_gui_click event for LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_click = handler_factory(defines.events.on_gui_click) +Gui.on_click = handler_factory('on_click') -- Register a handler for the on_gui_closed event for a custom LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_custom_close = handler_factory(defines.events.on_gui_closed) +Gui.on_custom_close = handler_factory('on_closed') -- Register a handler for the on_gui_elem_changed event for LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_elem_changed = handler_factory(defines.events.on_gui_elem_changed) +Gui.on_elem_changed = handler_factory('on_elem_changed') -- Register a handler for the on_gui_selection_state_changed event for LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_selection_state_changed = handler_factory(defines.events.on_gui_selection_state_changed) +Gui.on_selection_state_changed = handler_factory('on_selection_changed') -- Register a handler for the on_gui_text_changed event for LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_text_changed = handler_factory(defines.events.on_gui_text_changed) +Gui.on_text_changed = handler_factory('on_text_changed') -- Register a handler for the on_gui_value_changed event for LuaGuiElements with element_name. -- Can only have one handler per element name. -- Guarantees that the element and the player are valid when calling the handler. -- Adds a player field to the event table. -Gui.on_value_changed = handler_factory(defines.events.on_gui_value_changed) - --- Register a handler for when the player shows the top LuaGuiElements with element_name. --- Assuming the element_name has been added with Gui.allow_player_to_toggle_top_element_visibility. --- Can only have one handler per element name. --- Guarantees that the element and the player are valid when calling the handler. --- Adds a player field to the event table. -Gui.on_player_show_top = custom_handler_factory(on_visible_handlers) - --- Register a handler for when the player hides the top LuaGuiElements with element_name. --- Assuming the element_name has been added with Gui.allow_player_to_toggle_top_element_visibility. --- Can only have one handler per element name. --- Guarantees that the element and the player are valid when calling the handler. --- Adds a player field to the event table. -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 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 This name must be globally unique. -function Gui.allow_player_to_toggle_top_element_visibility(element_name) - if _LIFECYCLE ~= _STAGE.control then - error('can only be called during the control stage', 2) - end - top_elements[#top_elements + 1] = element_name -end +Gui.on_value_changed = handler_factory('on_value_changed') --- 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 LuaPlayer player pointer to the player who has the gui -- @treturn LuaGuiElement 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, - function(event) - local player = Game.get_player_by_index(event.player_index) - - if not player or not player.valid then - return - end - - 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 = {'gui_util.button_tooltip'} - } - local style = b.style - style.width = 18 - style.height = 36 - style.left_padding = 0 - style.top_padding = 0 - style.right_padding = 0 - style.bottom_padding = 0 - style.font = 'default-small-bold' - end -) - -Gui.on_click( - toggle_button_name, - function(event) - local button = event.element - local player = event.player - 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 - if ele.visible then - custom_raise(on_pre_hidden_handlers, ele, player) - ele.visible = false - end - end - end - - button.caption = '>' - button.style.height = 24 - else - for i = 1, #top_elements do - local name = top_elements[i] - local ele = top[name] - if ele and ele.valid then - if not ele.visible then - ele.visible = true - custom_raise(on_visible_handlers, ele, player) - end - end - end - - button.caption = '<' - button.style.height = 36 - end - end -) - -if _DEBUG then - local concat = table.concat - - local names = {} - Gui.names = names - - function Gui.uid_name() - local info = debug.getinfo(2, 'Sl') - local filepath = info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) - local line = info.currentline - - local token = tostring(Token.uid()) - - local name = concat {token, ' - ', filepath, ':line:', line} - names[token] = name - - return token - end -end +Gui.get_top_element_flow = ExpGui.get_top_flow return Gui \ No newline at end of file