diff --git a/README.md b/README.md index 2c9d02e7..8ff71f05 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Explosive Gaming (often ExpGaming) is a server hosting community with a strong f ## 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]. 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. @@ -111,6 +111,7 @@ All are welcome to make pull requests and issues for this scenario, if you are i The Explosive Gaming codebase is licensed under the [GNU General Public License v3.0](LICENSE) +[docs]: https://explosivegaming.github.io/scenario/ [issues]: https://github.com/explosivegaming/scenario/issues/new/choose [website]: https://explosivegaming.nl [discord]: https://discord.explosivegaming.nl diff --git a/config/_file_loader.lua b/config/_file_loader.lua index c4a5bba6..e9be5b99 100644 --- a/config/_file_loader.lua +++ b/config/_file_loader.lua @@ -39,12 +39,12 @@ return { 'modules.addons.discord-alerts', 'modules.addons.chat-reply', -- GUI - 'modules.gui.rocket-info', - 'modules.gui.science-info', - 'modules.gui.warp-list', - 'modules.gui.task-list', - 'modules.gui.player-list', - 'modules.commands.debug', + --'modules.gui.rocket-info', + --'modules.gui.science-info', + --'modules.gui.warp-list', + --'modules.gui.task-list', + --'modules.gui.player-list', + --'modules.commands.debug', -- Config Files 'config.expcore-commands.auth_admin', -- commands tagged with admin_only are blocked for non admins 'config.expcore-commands.auth_roles', -- commands must be allowed via the role config diff --git a/docs/addons/Advanced-Start.html b/docs/addons/Advanced-Start.html index 0b56fc11..99ffc5b4 100644 --- a/docs/addons/Advanced-Start.html +++ b/docs/addons/Advanced-Start.html @@ -74,6 +74,7 @@ + @@ -348,7 +349,7 @@ generated by LDoc diff --git a/docs/addons/Chat-Popups.html b/docs/addons/Chat-Popups.html index 75114dcc..b06d2672 100644 --- a/docs/addons/Chat-Popups.html +++ b/docs/addons/Chat-Popups.html @@ -74,6 +74,7 @@ + @@ -349,7 +350,7 @@ generated by LDoc diff --git a/docs/addons/Chat-Reply.html b/docs/addons/Chat-Reply.html index be18394a..d45ea3c6 100644 --- a/docs/addons/Chat-Reply.html +++ b/docs/addons/Chat-Reply.html @@ -74,6 +74,7 @@ + @@ -376,7 +377,7 @@ generated by LDoc diff --git a/docs/addons/Compilatron.html b/docs/addons/Compilatron.html index 3ad91922..6eb7d3fe 100644 --- a/docs/addons/Compilatron.html +++ b/docs/addons/Compilatron.html @@ -75,6 +75,7 @@ + @@ -585,7 +586,7 @@ generated by LDoc diff --git a/docs/addons/Damage-Popups.html b/docs/addons/Damage-Popups.html index 42cd4094..95607966 100644 --- a/docs/addons/Damage-Popups.html +++ b/docs/addons/Damage-Popups.html @@ -74,6 +74,7 @@ + @@ -349,7 +350,7 @@ generated by LDoc diff --git a/docs/addons/Death-Logger.html b/docs/addons/Death-Logger.html index 01b1f797..3ab0419f 100644 --- a/docs/addons/Death-Logger.html +++ b/docs/addons/Death-Logger.html @@ -74,6 +74,7 @@ + @@ -404,7 +405,7 @@ generated by LDoc diff --git a/docs/addons/Discord-Alerts.html b/docs/addons/Discord-Alerts.html index cce518e8..7e7065bc 100644 --- a/docs/addons/Discord-Alerts.html +++ b/docs/addons/Discord-Alerts.html @@ -74,6 +74,7 @@ + @@ -460,7 +461,7 @@ generated by LDoc diff --git a/docs/addons/Player-Colours.html b/docs/addons/Player-Colours.html index d17bb676..e2995d38 100644 --- a/docs/addons/Player-Colours.html +++ b/docs/addons/Player-Colours.html @@ -74,6 +74,7 @@ + @@ -404,7 +405,7 @@ generated by LDoc diff --git a/docs/addons/Pollution-Grading.html b/docs/addons/Pollution-Grading.html index bfc08f0d..f257ab61 100644 --- a/docs/addons/Pollution-Grading.html +++ b/docs/addons/Pollution-Grading.html @@ -74,6 +74,7 @@ + @@ -320,7 +321,7 @@ generated by LDoc diff --git a/docs/addons/Scorched-Earth.html b/docs/addons/Scorched-Earth.html index 09d37fe9..6f6fc337 100644 --- a/docs/addons/Scorched-Earth.html +++ b/docs/addons/Scorched-Earth.html @@ -74,6 +74,7 @@ + @@ -404,7 +405,7 @@ generated by LDoc diff --git a/docs/addons/Spawn-Area.html b/docs/addons/Spawn-Area.html index 3ba5ee0d..b2b11a94 100644 --- a/docs/addons/Spawn-Area.html +++ b/docs/addons/Spawn-Area.html @@ -74,6 +74,7 @@ + @@ -376,7 +377,7 @@ generated by LDoc diff --git a/docs/commands/Admin-Chat.html b/docs/commands/Admin-Chat.html index e8b3303d..aafc0e4e 100644 --- a/docs/commands/Admin-Chat.html +++ b/docs/commands/Admin-Chat.html @@ -84,6 +84,7 @@ + @@ -388,7 +389,7 @@ generated by LDoc diff --git a/docs/commands/Bonus.html b/docs/commands/Bonus.html index 4b41076e..9db97cf7 100644 --- a/docs/commands/Bonus.html +++ b/docs/commands/Bonus.html @@ -84,6 +84,7 @@ + @@ -500,7 +501,7 @@ generated by LDoc diff --git a/docs/commands/Cheat-Mode.html b/docs/commands/Cheat-Mode.html index cb0d0a09..1e4cc198 100644 --- a/docs/commands/Cheat-Mode.html +++ b/docs/commands/Cheat-Mode.html @@ -84,6 +84,7 @@ + @@ -361,7 +362,7 @@ generated by LDoc diff --git a/docs/commands/Clear-Inventory.html b/docs/commands/Clear-Inventory.html index 27f45940..03e6c886 100644 --- a/docs/commands/Clear-Inventory.html +++ b/docs/commands/Clear-Inventory.html @@ -84,6 +84,7 @@ + @@ -388,7 +389,7 @@ generated by LDoc diff --git a/docs/commands/Debug.html b/docs/commands/Debug.html index e2f78d24..edfcdbb1 100644 --- a/docs/commands/Debug.html +++ b/docs/commands/Debug.html @@ -84,6 +84,7 @@ + @@ -365,7 +366,7 @@ generated by LDoc diff --git a/docs/commands/Find.html b/docs/commands/Find.html index c727cd0e..586d8d34 100644 --- a/docs/commands/Find.html +++ b/docs/commands/Find.html @@ -84,6 +84,7 @@ + @@ -360,7 +361,7 @@ generated by LDoc diff --git a/docs/commands/Help.html b/docs/commands/Help.html index d5178346..25a8f115 100644 --- a/docs/commands/Help.html +++ b/docs/commands/Help.html @@ -84,6 +84,7 @@ + @@ -404,7 +405,7 @@ generated by LDoc diff --git a/docs/commands/Home.html b/docs/commands/Home.html index a1ba8bce..e88d2da7 100644 --- a/docs/commands/Home.html +++ b/docs/commands/Home.html @@ -84,6 +84,7 @@ + @@ -458,7 +459,7 @@ generated by LDoc diff --git a/docs/commands/Interface.html b/docs/commands/Interface.html index c38850c0..2cf6091a 100644 --- a/docs/commands/Interface.html +++ b/docs/commands/Interface.html @@ -84,6 +84,7 @@ + @@ -416,7 +417,7 @@ generated by LDoc diff --git a/docs/commands/Jail.html b/docs/commands/Jail.html index 2f087f4c..1d41e418 100644 --- a/docs/commands/Jail.html +++ b/docs/commands/Jail.html @@ -84,6 +84,7 @@ + @@ -611,7 +612,7 @@ generated by LDoc diff --git a/docs/commands/Kill.html b/docs/commands/Kill.html index 33cd787e..6b7e21d8 100644 --- a/docs/commands/Kill.html +++ b/docs/commands/Kill.html @@ -84,6 +84,7 @@ + @@ -389,7 +390,7 @@ generated by LDoc diff --git a/docs/commands/Me.html b/docs/commands/Me.html index ee42acca..a071c0c1 100644 --- a/docs/commands/Me.html +++ b/docs/commands/Me.html @@ -84,6 +84,7 @@ + @@ -360,7 +361,7 @@ generated by LDoc diff --git a/docs/commands/Rainbow.html b/docs/commands/Rainbow.html index b7f2a851..dc82cc79 100644 --- a/docs/commands/Rainbow.html +++ b/docs/commands/Rainbow.html @@ -84,6 +84,7 @@ + @@ -388,7 +389,7 @@ generated by LDoc diff --git a/docs/commands/Repair.html b/docs/commands/Repair.html index 19e506ca..29437a17 100644 --- a/docs/commands/Repair.html +++ b/docs/commands/Repair.html @@ -83,6 +83,7 @@ + @@ -321,7 +322,7 @@ generated by LDoc diff --git a/docs/commands/Reports.html b/docs/commands/Reports.html index c0f17772..65f2d825 100644 --- a/docs/commands/Reports.html +++ b/docs/commands/Reports.html @@ -84,6 +84,7 @@ + @@ -585,7 +586,7 @@ generated by LDoc diff --git a/docs/commands/Roles.html b/docs/commands/Roles.html index d9a1f285..e0d338c1 100644 --- a/docs/commands/Roles.html +++ b/docs/commands/Roles.html @@ -84,6 +84,7 @@ + @@ -557,7 +558,7 @@ generated by LDoc diff --git a/docs/commands/Spawn.html b/docs/commands/Spawn.html index bb58d8a9..f8ef4787 100644 --- a/docs/commands/Spawn.html +++ b/docs/commands/Spawn.html @@ -84,6 +84,7 @@ + @@ -389,7 +390,7 @@ generated by LDoc diff --git a/docs/commands/Tag.html b/docs/commands/Tag.html index 43fab495..ac1dd9e2 100644 --- a/docs/commands/Tag.html +++ b/docs/commands/Tag.html @@ -84,6 +84,7 @@ + @@ -443,7 +444,7 @@ generated by LDoc diff --git a/docs/commands/Teleport.html b/docs/commands/Teleport.html index 42089cc1..efe6fe04 100644 --- a/docs/commands/Teleport.html +++ b/docs/commands/Teleport.html @@ -84,6 +84,7 @@ + @@ -484,7 +485,7 @@ generated by LDoc diff --git a/docs/commands/Warnings.html b/docs/commands/Warnings.html index 0bb7d855..4d8a95a6 100644 --- a/docs/commands/Warnings.html +++ b/docs/commands/Warnings.html @@ -84,6 +84,7 @@ + @@ -569,7 +570,7 @@ generated by LDoc diff --git a/docs/config.ld b/docs/config.ld index f5a7a308..d3b5fe24 100644 --- a/docs/config.ld +++ b/docs/config.ld @@ -1,5 +1,5 @@ file = '../' -dir = '../doc' +dir = '../docs' project = 'ExpGaming Scenario' title = 'ExpGaming Scenario' description = 'Explosive Gaming\'s server scenario for 0.17' @@ -10,8 +10,8 @@ not_luadoc = true no_lua_ref = true template_escape = ">" topics = {"../README.md", "../LICENSE"} -style = '../doc' -template = '../doc' +style = '../docs' +template = '../docs' no_space_before_args = true merge=true @@ -23,8 +23,8 @@ new_type("gui", "Guis", true) new_type("config", "Configs", true, "Settings") new_type("dep", "Dependencies", false) -new_type("element", "Elements", false) new_type("setting", "Settings", false) +new_type("element", "Elements", false, "Properties / Events") new_type("event", "Events", false, "Event Parameters") new_type("command", "Commands", false, "Command Parameters") diff --git a/docs/configs/Advanced-Start.html b/docs/configs/Advanced-Start.html index 46ef69a1..981debc7 100644 --- a/docs/configs/Advanced-Start.html +++ b/docs/configs/Advanced-Start.html @@ -89,6 +89,7 @@ + @@ -506,7 +507,7 @@ generated by LDoc diff --git a/docs/configs/Bonuses.html b/docs/configs/Bonuses.html index e1806bce..f42ddc42 100644 --- a/docs/configs/Bonuses.html +++ b/docs/configs/Bonuses.html @@ -81,6 +81,7 @@ + @@ -237,7 +238,7 @@ generated by LDoc diff --git a/docs/configs/Chat-Reply.html b/docs/configs/Chat-Reply.html index c8ef6dfa..37c2a42d 100644 --- a/docs/configs/Chat-Reply.html +++ b/docs/configs/Chat-Reply.html @@ -90,6 +90,7 @@ + @@ -485,7 +486,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Auth-Admin.html b/docs/configs/Commands-Auth-Admin.html index ffc290aa..48724dfc 100644 --- a/docs/configs/Commands-Auth-Admin.html +++ b/docs/configs/Commands-Auth-Admin.html @@ -89,6 +89,7 @@ + @@ -294,7 +295,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Auth-Roles.html b/docs/configs/Commands-Auth-Roles.html index 1f3c18d9..dc9614f2 100644 --- a/docs/configs/Commands-Auth-Roles.html +++ b/docs/configs/Commands-Auth-Roles.html @@ -89,6 +89,7 @@ + @@ -320,7 +321,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Auth-Runtime-Disable.html b/docs/configs/Commands-Auth-Runtime-Disable.html index f68dc361..c68b216a 100644 --- a/docs/configs/Commands-Auth-Runtime-Disable.html +++ b/docs/configs/Commands-Auth-Runtime-Disable.html @@ -90,6 +90,7 @@ + @@ -442,7 +443,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Parse-Roles.html b/docs/configs/Commands-Parse-Roles.html index d18424fa..f432ec70 100644 --- a/docs/configs/Commands-Parse-Roles.html +++ b/docs/configs/Commands-Parse-Roles.html @@ -89,6 +89,7 @@ + @@ -354,7 +355,7 @@ generated by LDoc diff --git a/docs/configs/Commands-Parse.html b/docs/configs/Commands-Parse.html index 2f413722..d3c7c295 100644 --- a/docs/configs/Commands-Parse.html +++ b/docs/configs/Commands-Parse.html @@ -89,6 +89,7 @@ + @@ -338,7 +339,7 @@ see ./expcore/commands.lua for more details

generated by LDoc diff --git a/docs/configs/Compilatron.html b/docs/configs/Compilatron.html index 5bf4b1ba..daeb3b5e 100644 --- a/docs/configs/Compilatron.html +++ b/docs/configs/Compilatron.html @@ -89,6 +89,7 @@ + @@ -354,7 +355,7 @@ generated by LDoc diff --git a/docs/configs/Death-Logger.html b/docs/configs/Death-Logger.html index 76aec8f5..60c66414 100644 --- a/docs/configs/Death-Logger.html +++ b/docs/configs/Death-Logger.html @@ -89,6 +89,7 @@ + @@ -416,7 +417,7 @@ generated by LDoc diff --git a/docs/configs/Discord-Alerts.html b/docs/configs/Discord-Alerts.html index 03ca2c6d..6cbff49c 100644 --- a/docs/configs/Discord-Alerts.html +++ b/docs/configs/Discord-Alerts.html @@ -81,6 +81,7 @@ + @@ -237,7 +238,7 @@ generated by LDoc diff --git a/docs/configs/File-Loader.html b/docs/configs/File-Loader.html index 58c755b1..f83ad879 100644 --- a/docs/configs/File-Loader.html +++ b/docs/configs/File-Loader.html @@ -81,6 +81,7 @@ + @@ -240,7 +241,7 @@ generated by LDoc diff --git a/docs/configs/Permission-Groups.html b/docs/configs/Permission-Groups.html index 7043ae72..8a41a0bb 100644 --- a/docs/configs/Permission-Groups.html +++ b/docs/configs/Permission-Groups.html @@ -89,6 +89,7 @@ + @@ -295,7 +296,7 @@ generated by LDoc diff --git a/docs/configs/Player-List.html b/docs/configs/Player-List.html index c6e1c748..abbd67bc 100644 --- a/docs/configs/Player-List.html +++ b/docs/configs/Player-List.html @@ -90,6 +90,7 @@ + @@ -812,7 +813,7 @@ generated by LDoc diff --git a/docs/configs/Pollution-Grading.html b/docs/configs/Pollution-Grading.html index 9eb9892f..55ce2814 100644 --- a/docs/configs/Pollution-Grading.html +++ b/docs/configs/Pollution-Grading.html @@ -89,6 +89,7 @@ + @@ -384,7 +385,7 @@ generated by LDoc diff --git a/docs/configs/Popup-Messages.html b/docs/configs/Popup-Messages.html index 39690dd2..2a98b0b2 100644 --- a/docs/configs/Popup-Messages.html +++ b/docs/configs/Popup-Messages.html @@ -89,6 +89,7 @@ + @@ -414,7 +415,7 @@ generated by LDoc diff --git a/docs/configs/Preset-Player-Colours.html b/docs/configs/Preset-Player-Colours.html index 9d37a9a8..5933597f 100644 --- a/docs/configs/Preset-Player-Colours.html +++ b/docs/configs/Preset-Player-Colours.html @@ -89,6 +89,7 @@ + @@ -324,7 +325,7 @@ generated by LDoc diff --git a/docs/configs/Repair.html b/docs/configs/Repair.html index 8625da88..1c90a44e 100644 --- a/docs/configs/Repair.html +++ b/docs/configs/Repair.html @@ -89,6 +89,7 @@ + @@ -414,7 +415,7 @@ generated by LDoc diff --git a/docs/configs/Rockets.html b/docs/configs/Rockets.html index 9be2580d..4478572f 100644 --- a/docs/configs/Rockets.html +++ b/docs/configs/Rockets.html @@ -89,6 +89,7 @@ + @@ -834,7 +835,7 @@ generated by LDoc diff --git a/docs/configs/Roles.html b/docs/configs/Roles.html index c1aebec6..f503d293 100644 --- a/docs/configs/Roles.html +++ b/docs/configs/Roles.html @@ -89,6 +89,7 @@ + @@ -292,7 +293,7 @@ generated by LDoc diff --git a/docs/configs/Science.html b/docs/configs/Science.html index d279267e..fc973191 100644 --- a/docs/configs/Science.html +++ b/docs/configs/Science.html @@ -89,6 +89,7 @@ + @@ -354,7 +355,7 @@ generated by LDoc diff --git a/docs/configs/Scorched-Earth.html b/docs/configs/Scorched-Earth.html index 508bde53..b8e6ad74 100644 --- a/docs/configs/Scorched-Earth.html +++ b/docs/configs/Scorched-Earth.html @@ -89,6 +89,7 @@ + @@ -388,7 +389,7 @@ generated by LDoc diff --git a/docs/configs/Spawn-Area.html b/docs/configs/Spawn-Area.html index 9b9a9a5a..8ac57876 100644 --- a/docs/configs/Spawn-Area.html +++ b/docs/configs/Spawn-Area.html @@ -89,6 +89,7 @@ + @@ -744,7 +745,7 @@ generated by LDoc diff --git a/docs/configs/Tasks.html b/docs/configs/Tasks.html index 6072ae03..44ef1e74 100644 --- a/docs/configs/Tasks.html +++ b/docs/configs/Tasks.html @@ -89,6 +89,7 @@ + @@ -384,7 +385,7 @@ generated by LDoc diff --git a/docs/configs/Warnings.html b/docs/configs/Warnings.html index f3edf5aa..1a874b76 100644 --- a/docs/configs/Warnings.html +++ b/docs/configs/Warnings.html @@ -89,6 +89,7 @@ + @@ -355,7 +356,7 @@ generated by LDoc diff --git a/docs/configs/Warps.html b/docs/configs/Warps.html index 8800c822..a8b05959 100644 --- a/docs/configs/Warps.html +++ b/docs/configs/Warps.html @@ -89,6 +89,7 @@ + @@ -684,7 +685,7 @@ generated by LDoc diff --git a/docs/control/Jail.html b/docs/control/Jail.html index 5f68c34b..4e10b7c8 100644 --- a/docs/control/Jail.html +++ b/docs/control/Jail.html @@ -73,6 +73,7 @@ + @@ -1208,7 +1209,7 @@ generated by LDoc diff --git a/docs/control/Production.html b/docs/control/Production.html index ccfd8f5f..115f41c1 100644 --- a/docs/control/Production.html +++ b/docs/control/Production.html @@ -73,6 +73,7 @@ + @@ -1329,7 +1330,7 @@ generated by LDoc diff --git a/docs/control/Reports.html b/docs/control/Reports.html index ddcdfb3e..f8c8e04b 100644 --- a/docs/control/Reports.html +++ b/docs/control/Reports.html @@ -73,6 +73,7 @@ + @@ -1110,7 +1111,7 @@ generated by LDoc diff --git a/docs/control/Rockets.html b/docs/control/Rockets.html index 431f9815..9c23440e 100644 --- a/docs/control/Rockets.html +++ b/docs/control/Rockets.html @@ -72,6 +72,7 @@ + @@ -984,7 +985,7 @@ generated by LDoc diff --git a/docs/control/Tasks.html b/docs/control/Tasks.html index 7fa706cc..b09d725e 100644 --- a/docs/control/Tasks.html +++ b/docs/control/Tasks.html @@ -72,6 +72,7 @@ + @@ -1039,7 +1040,7 @@ generated by LDoc diff --git a/docs/control/Warnings.html b/docs/control/Warnings.html index c1ac81e7..e2f72325 100644 --- a/docs/control/Warnings.html +++ b/docs/control/Warnings.html @@ -72,6 +72,7 @@ + @@ -1465,7 +1466,7 @@ generated by LDoc diff --git a/docs/control/Warps.html b/docs/control/Warps.html index 5fa18a14..1a650f00 100644 --- a/docs/control/Warps.html +++ b/docs/control/Warps.html @@ -73,6 +73,7 @@ + @@ -1413,7 +1414,7 @@ generated by LDoc diff --git a/docs/core/Commands.html b/docs/core/Commands.html index 683bf908..37d28eb4 100644 --- a/docs/core/Commands.html +++ b/docs/core/Commands.html @@ -61,6 +61,7 @@ + @@ -1972,7 +1973,7 @@ generated by LDoc diff --git a/docs/core/Common-Library.html b/docs/core/Common-Library.html index 44c6136e..e4c5c30d 100644 --- a/docs/core/Common-Library.html +++ b/docs/core/Common-Library.html @@ -57,6 +57,7 @@ + @@ -357,6 +358,22 @@ format_chat_player_name(player[, raw_string=false]) Returns the players name in the players color + + get_file_path([offset=0]) + Returns a desync safe file path for the current file + + + array_insert(tbl[, start_index], values) + Much faster method for inserting items into an array + + + table_insert(tbl[, start_index], tbl2) + Much faster method for inserting keys into a table + + + resolve_value(value) + Used to resolve a value that could also be a function returning that value + @@ -2402,6 +2419,318 @@ + +
+
+
+ # + get_file_path([offset=0]) +
+
+
+
+ +

Returns a desync safe file path for the current file

+

+ + + Parameters: + + + + + + + Returns: + + + + + + + + + + +
+
+
+
+ # + array_insert(tbl[, start_index], values) +
+
+
+
+ +

Much faster method for inserting items into an array

+

+ + + Parameters: + + + + + + + Returns: + + + + + + + + + Usage: +
-- Adding 1000 values into the middle of the array
+local tbl = {}
+local values = {}
+for i = 1,1000 do tbl[i] = i values[i] = i end
+Common.array_insert(tbl,500,values) -- around 0.4ms
+ + +
+
+
+
+ # + table_insert(tbl[, start_index], tbl2) +
+
+
+
+ +

Much faster method for inserting keys into a table

+

+ + + Parameters: + + + + + + + Returns: + + + + + + + + + Usage: +
-- Merging two tables
+local tbl = {}
+local tbl2 = {}
+for i = 1,100 do tbl[i] = i tbl['_'..i] = i tbl2[i] = i tbl2['__'..i] = i end
+Common.table_insert(tbl,50,tbl2)
+ + +
+
+
+
+ # + resolve_value(value) +
+
+
+
+ +

Used to resolve a value that could also be a function returning that value

+

+ + + Parameters: + + + + + + + Returns: + + + + + + + + + Usage: +
-- Default value handling
+-- if default value is not a function then it is returned
+-- if it is a function then it is called with the first argument being self
+local value = Common.resolve_value(self.defaut_value,self)
+ +
@@ -2418,7 +2747,7 @@ generated by LDoc diff --git a/docs/core/Gui.html b/docs/core/Gui.html index cc61f4e7..67827252 100644 --- a/docs/core/Gui.html +++ b/docs/core/Gui.html @@ -41,22 +41,17 @@ @@ -71,6 +66,7 @@ + @@ -216,22 +212,17 @@ @@ -251,11 +242,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

+

Core Module - Gui

@@ -263,6 +250,69 @@ +

Usage

+
-- Making the base button concept
+local button =
+Gui.new_concept() -- Make a new empty concept
+:save_as('button') -- Save it as Gui.concepts.button so it can be used in other files
+:new_event('on_click',defines.events.on_gui_click) -- Add an on click event for this concept
+:new_property('tooltip') -- Add a property with the default setter method called tooltip
+:new_property('caption',function(properties,value) -- Add a property with a custom setter method called caption
+    properties.caption = value
+    properties.sprite = nil
+    properties.type = 'button'
+end)
+:new_property('sprite',function(properties,value) -- Add a property with a custom setter method called sprite
+    properties.image = value
+    properties.caption = nil
+    properties.type = 'sprite-button'
+end)
+:define_draw(function(properties,parent,element) -- Add the draw function to create the element from the concept
+    -- Properties will include all the information that you need to draw the element
+    -- Parent is the parent element for the element, this may have been altered by previous draw functions
+    -- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function
+    if properties.type == 'button' then
+        element = parent.add{
+            type = properties.type,
+            name = properties.name,
+            caption = properties.caption,
+            tooltip = properties.tooltip
+        }
+
+    else
+        element = parent.add{
+            type = properties.type,
+            name = properties.name,
+            sprite = properties.sprite,
+            tooltip = properties.tooltip
+        }
+
+    end
+
+    -- If you return element or parent then their values will be updated for the next draw function in the chain
+    -- It is best practice to always return the values if you have made any changes to them
+    return element, parent
+end)
+
-- Making a new button which has a custom style
+local custom_button =
+Gui.new_concept('button') -- We can use button here since we used save as on the concept
+-- button:clone() -- If we had not used save as then this is how we would use it as a base
+:set_caption('Custom Button') -- Set the caption of the concept, this is possible as we added caption as a property
+:set_tooltip('Only admins can press this button') -- Set the tooltip of the concept, this is possible as we added tooltip as a property
+:on_click(function(event) -- Register a handler to the click event we added with new event
+    if not event.player.admin then
+        event.player.print('You must be admin to use this button')
+    end
+end)
+:new_event('on_admin_clicked',defines.events.on_gui_click,function(event) -- Add a click event which has a filter function
+    return event.player.admin -- Check if the player is admin
+end)
+:on_admin_clicked(function(event) -- Register a handler to the admin click event we have just created
+    -- The admin click event is only an example, because of how sinmple the filter is we could have just used an if else statement
+    game.print(event.player.name..' pressed my admin button')
+end)
+
-- Drawing a concept
+custom_button:draw(game.player.gui.left)
@@ -270,461 +320,69 @@ -

Dependencies

+

Elements

- + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - -
expcore.gui.corebuttonClickable elements that fire on_gui_click when clicked.
expcore.gui.instancescheckboxClickable elements with a cross in the middle that can be turned off or on.
expcore.gui.elements.buttonsdropdownA drop down list of other elements.
expcore.gui.elements.checkboxelem_buttonA button that lets the player pick one of an: item, entity, tile, or signal similar to the filter-select window.
expcore.gui.elements.dropdownemptyA empty widget that just exists.
expcore.gui.elements.sliderflowInvisible containers that lay out children either horizontally or vertically.
expcore.gui.elements.textframeGrey semi-transparent boxes that contain other elements.
expcore.gui.elements.elem-buttonframeA piece of text.
expcore.gui.elements.progress-barlineA vertical or horizontal line.
expcore.gui.concepts.toolbarprogress_barIndicate progress by displaying a partially filled bar.
expcore.gui.concepts.leftscrollSimilar to a flow but includes the ability to show and use scroll bars.
expcore.gui.concepts.centersliderA number picker.
expcore.gui.concepts.popupstableAn invisible container that lays out children in a specific number of columns.
- - -

Center Guis

- - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.coretext_boxA multi-line text box that supports selection and copy-paste.
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.buttons
mod-gui
utils.game
utils.event
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=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
- - -

Popups

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 function
- - -

Toolbar

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
expcore.gui.core
expcore.gui.elements.buttons
expcore.roles
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 return
- - -

Core

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
utils.gui
utils.game
new_define(prototype[, debug_name])Used to create new element defines from a class prototype, please use the own given by the class
get_define(name[, internal])Gets an element define give the uid, debug name or a copy of the element define
categorize_by_player(element)A categorize function to be used with add_store, each player has their own value
categorize_by_force(element)A categorize function to be used with add_store, each force has its own value
categorize_by_surface(element)A categorize function to be used with add_store, each surface has its own value
draw(name, element)Draws a copy of the element define to the parent element, see draw_to
toggle_enabled(element)Will toggle the enabled state of an element
toggle_visible(element)Will toggle the visiblity of an element
set_padding(element[, up=0][, down=0][, left=0][, right=0])Sets the padding for a gui element
set_padding_style(style[, up=0][, down=0][, left=0][, right=0])Sets the padding for a gui style
create_alignment(element[, name][, horizontal_align='right'][, vertical_align='center'])Allows the creation of an alignment flow to place elements into
destroy_if_valid(element)Destroies an element but tests for it being present and valid first
create_scroll_table(element, table_size, maximal_height[, name='scroll'])Creates a scroll area with a table inside, table can be any size
create_header(element, caption[, tooltip][, right_align][, name='header'])Creates a header section with a label and button area
- - -

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(name, callback, categorize)Registers a new option set that can be linked to radiobuttons (only one can be true at a time)
Checkbox.draw_option_set(name, element)Draws all radiobuttons that are part of an option set at once (Gui.draw will not work)
Checkbox.reset_radiobuttons(element[, exclude][, recursive=false])Sets all radiobutton in a element to false (unless excluded) and can act recursivelytext_fieldBoxes of text the user can type in.
@@ -735,70 +393,16 @@ - expcore.gui.core + set_dropdown_value(element, value) + Selects the index of a dropdown with this value - expcore.gui.prototype + get_dropdown_value(element) + Gets the selected item value of a dropdown - 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 stringadd_dropdown_items(element[, start_index], new_items)Adds the given items into the list of items for this dropdown
@@ -809,306 +413,240 @@ - expcore.gui.core + progress_bar:increment(element[, amount=1]) + Will increase the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances - expcore.gui.prototype + progress_bar:decrement(element[, amount=1]) + Will decrease the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances - utils.global + progress_bar:reset(element) + Resets the progress back to 0% for this element, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances - utils.game + increment_progress_bar(element[, amount=0.01]) + Increment any progress bar by the given percentage - 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 + decrement_progress_bar(element[, amount=0.01]) + Decrement any progress bar by the given percentage -

Sliders

+

Concept Control

- + + - + + - + + - + + - - + + - - - - - - - - - - + +
expcore.gui.corerequire_concept(concept_name)Loads a concept from the concepts file
expcore.gui.prototyperequire_style(style_name)Loads a set of concepts from the styles file
expcore.gui.instancesget_concept(name)Gets a gui concept from name, id, or its self
utils.gamePrototype:save_as(save_name)Used to save the concept to the main gui module to allow access from other files
Slider.new_slider([name])Creates a new slider element definenew_concept([base_concept])Returns a new gui concept, option to provide a base concept to copy properties and draw functions from
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 sliderdraw_concept(concept, parent)Used to draw a concept to a parent element
-

Text

+

Element Control

- + + - + + - + + - - + + - - + + - - - - - - - - - - + +
expcore.gui.coreget_player_from_element(element)Gets the player who owns this element
expcore.gui.prototypevalid(element)Simple check for if an element is valid
utils.gamedestroy(element)Destroies and element if it is valid
Text.new_text_field([name])Creates a new text field element definetoggle_enabled(element)Toggles the enabled state of an element
Text.new_text_box([name])Creates a new text box element definetoggle_visible(element)Toggles the visible state of an element
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 onlyset_padding(element[, up=0][, down=0][, left=0][, right=0])Sets the padding for a gui element
-

Instances

+

Store Categories

- + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + +
utils.globalcategorize_by_player(element)A categorize function to be used with add_store, each player has their own category
Instances.has_categories(name)Returns if a instance group has a categorise function; must be registeredcategorize_by_force(element)A categorize function to be used with add_store, each force has its own category
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 registeredcategorize_by_surface(element)A categorize function to be used with add_store, each surface has its own category
-

Prototype

+

Concept Base

- + + - + + - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +
utils.gamePrototype:clone(concept_name)Used to copy all the settings from one concept to another and removing links to the orginal
expcore.storePrototype:define_clone(clone_callback)Use to add your own callbacks to the clone function, for example adding to a local table
expcore.gui.instancesPrototype:save_as(save_name)Used to save the concept to the main gui module to allow access from other files
Constructor.event(event_name)Creates a new function to add functions to an event handlerPrototype:debug(name)Sets a debug name that can be used with error handlers
Constructor.extend(new_prototype)Extents a prototype with the base functions of all gui prototypes, no metatablesPrototype:new_event(event_name[, factorio_event][, event_condition])Adds a new event trigger to the concept which can be linked to a factorio event
Constructor.store(sync, callback)Creates a new function which adds a store to a gui definePrototype:on_custom_event(handler)Adds a custom event handler, replace with the name of the event
Constructor.setter(value_type, key[, second_key])Creates a setter function that checks the type when a value is setPrototype:raise_event(event_name[, event={}][, from_factorio=false])Raises a custom event, folowing keys included automaticlly: concept, event name, game tick, player from player_index, element if valid
Prototype:uid()Gets the uid for the element definePrototype:new_property(property_name[, setter_callback][, default])Adds a new property to the concept, such as caption, tooltip, or some custom property you want to control
Prototype.debug_nameSets a debug alias for the definePrototype:set_custom_property(value)Sets a new value for a property, triggers setter method if provided, replace with property name
Prototype.set_captionSets the caption for the element definePrototype:define_draw(draw_callback)Used to define how the concept is turned into an ingame element or "instance" as we may refer to them
Prototype.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 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 usedPrototype:draw(parent_element)Calls all the draw functions in order to create this concept in game; will also store and sync the instance if stores are used
-

Test

+

Concept Instances

- + + - + + - + + - + + + + +
expcore.guiPrototype:define_instance_store([category_callback])Adds an instance store to the concept; when a new instance is made it is stored so you can access it later
expcore.commonPrototype.get_instances([category])Gets all insatnces in a category, category may be nil to return all
resources.color_presetsPrototype.add_instance(element[, category])Adds an instance to this concept, used automatically during concept:draw
utils.eventPrototype.update_instances([category], update_callback)Applies an update function to all instances, simialr use to what table.forEach would be
+ + +

Concept Data

+ + + + + + - + + + + + + + + + + + + + + + + +
Prototype:define_data_store([category_callback])Adds a data store to this concept which allows you to store synced/percistent data between instances
expcore.storePrototype.get_data([category])Gets the data that is stored for this category
Prototype.set_data([category], value)Sets the data that is stored for this category
Prototype.clear_data([category])Clears the data that is stored for this category
Prototype.update_data([category], update_callback)Updates the data that is stored for this category
+ + +

Concept Combined Instances

+ + + + + + + + + + + + +
Prototype:define_combined_store([category_callback], sync_callback)Used to add a both instance and data store which are linked together, new instances are synced to the current value, changing the stored value will change all instances
Prototype.sync_instance(element)Will sync an instance to match the stored value based on the given sync callback
+ + +

Tests

+ + + + + +
run_tests(player[, category])Runs a set of gui tests to ensure that the system is working
@@ -1117,451 +655,23 @@
-

Dependencies

+

Elements

- # - expcore.gui.core + # + button
- - - - - - - - - - - - - - -
-
-
-
- # - 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

+

Clickable elements that fire on_gui_click when clicked.

- Parameters: + Properties / Events:
    @@ -1571,13 +681,90 @@
  • - player + on_click : - (LuaPlayer) - the player to get the flow for + fired when the player clicks the button + +
  • + + + + + +
  • + + on_left_click + + : + + + fired when the player clicks with the right mouse button + +
  • + + + + + +
  • + + on_left_click + + : + + + fired when the player clicks with the right mouse button + +
  • + + + + + +
  • + + caption + + : + + (string or LocalisedString) + + the message that is shown on the button + +
  • + + + + + +
  • + + tooltip + + : + + (string or LocalisedString) + + the tooltip that shows when a player hovers over the button + +
  • + + + + + +
  • + + sprite + + : + + (SpritePath) + + upto three sprites in the order: default, hovered, clicked
  • @@ -1587,13 +774,6 @@ - Returns: - @@ -1601,24 +781,41 @@ + Usage: +
    -- Making a basic button
    +local basic_button =
    +Gui.new_concept('button')
    +:set_caption('Basic Button')
    +:set_tooltip('Basic button')
    +:on_click(function(event)
    +    event.player.print('You pressed basic button!')
    +end)
    +
    -- Making a sprite button
    +local sprite_button =
    +Gui.new_concept('button')
    +:set_sprite('utility/warning_icon')
    +:set_tooltip('Sprite button')
    +:on_click(function(event)
    +    event.player.print('You pressed sprite button!')
    +end)
- # - CenterFrames.clear_flow(player) + # + checkbox
-

Clears the center flow for a player

+

Clickable elements with a cross in the middle that can be turned off or on.

- Parameters: + Properties / Events:
    @@ -1628,63 +825,28 @@
  • - player + on_state_changed : - (LuaPlayer) - the player to clear the flow for + fired when the state of the element is changed
  • -
- - - - - - - - - - - - - -
-
-
-
- # - CenterFrames.draw_frame(player, name) -
-
-
-
- -

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

-

- - - Parameters: - -
    - -
  • - player + caption : - (LuaPlayer) + (string or LocalisedString) - the player that will have the frame drawn + the message that is shown next to the checkbox
  • @@ -1694,70 +856,13 @@
  • - name + tooltip : - (string) + (string or LocalisedString) - 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 + the tooltip that shows when a player hovers over the checkbox
  • @@ -1767,1007 +872,30 @@
  • - 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 -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - mod-gui -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - utils.game -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - utils.event -
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
- # - LeftFrames.get_flow(player) -
-
-
-
- -

Gets the left frame flow for a player

-

- - - Parameters: - -
    - - - - - -
  • - - player - - : - - (LuaPlayer) - - 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 - -
  • - - -
- - - - - Returns: -
    -
  • - (table) - contains all the open (and registered) frames for the player -
  • -
- - - - - - - - - -
-
-
-
- # - LeftFrames.toggle_frame(name, player[, state]) -
-
-
-
- -

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

-

- - - Parameters: - -
    - - - - - -
  • - - name - - : - - (string) - - the name of the gui frame to toggle - -
  • - - - - - -
  • - - player - - : - - (LuaPlayer) - - the player to get the frame of - -
  • - - - - - -
  • - - state - - : - - (boolean) - - when given will be the state that the visibility is set to - - (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 - -
  • - - -
- - - - - Returns: -
    -
  • - (table) - the 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

-

- - - Parameters: - -
    - - - - - -
  • - - state + default : (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 + the default state of this checkbox, or a function which returns the default state + +
  • + + + + + +
  • + + use_radio + + : + + (boolean) + + setting to true will use radio buttons rather than checkboxs - (default: true)
  • @@ -2783,24 +911,312 @@ + Usage: +
    -- Making a basic checkbox
    +local basic_checkbox =
    +Gui.new_concept('checkbox')
    +:set_caption('Basic Checkbox')
    +:set_tooltip('Basic checkbox')
    +:on_state_changed(function(event)
    +    event.player.print('Basic checkbox is now: '..tostring(event.element.state))
    +end)
- # - LeftFrames._prototype:set_direction(direction) + # + dropdown
-

Sets the direction of the frame, either vertical or horizontal

+

A drop down list of other elements.

- Parameters: + Properties / Events: + +
    + + + + + +
  • + + on_selection_changed + + : + + + fired when the selected value is changed + +
  • + + + + + +
  • + + default + + : + + (string, LocalisedString or function) + + the option which is selected by default, or a function which returns the default + +
  • + + + + + +
  • + + use_list_box + + : + + (boolean) + + when true a list box will be used rather than a dropdown menu + +
  • + + + + + +
  • + + static_items + + : + + (nil or table) + + when called with a table the values will be added as items for the dropdown, if called with nil then all items are cleared + +
  • + + + + + +
  • + + dynamic_items + + : + + (function) + + the given function will be called to return a list of items and optional start index to add items to the dropdown when it is first drawn + +
  • + + +
+ + + + + + + + + + + + Usage: +
-- Making a basic dropdown
+local static_dropdown =
+Gui.new_concept('dropdown')
+:set_static_items{'Option 1','Option 2','Option 3'}
+:on_selection_changed(function(event)
+    local value = Gui.get_dropdown_value(event.element)
+    event.player.print('Static dropdown is now: '..value)
+end)
+
-- Making a dropdown with dynamic items, example is name of online players
+local dynamic_dropdown =
+Gui.new_concept('dropdown')
+:set_dynamic_items(function(element)
+    local items = {}
+    for _,player in pairs(game.connected_players) do
+        items[#items+1] = player.name
+    end
+    return items
+end)
+:on_selection_changed(function(event)
+    local value = Gui.get_dropdown_value(event.element)
+    event.player.print('Dynamic dropdown is now: '..value)
+end)
+ + +
+
+
+
+ # + elem_button +
+
+
+
+ +

A button that lets the player pick one of an: item, entity, tile, or signal similar to the filter-select window.

+

+ + + Properties / Events: + +
    + + + + + +
  • + + on_selection_changed + + : + + + fired when the selected value is changed + +
  • + + + + + +
  • + + default + + : + + (string, SignalID or function) + + the option which is selected by default, or a function which returns the default + +
  • + + + + + +
  • + + elem_type + + : + + (string) + + the type of elem selection that this is, default is item selection + +
  • + + +
+ + + + + + + + + + + + Usage: +
-- Making a basic elem button
+local basic_elem_button =
+Gui.new_concept('elem_button')
+:on_selection_changed(function(event)
+    event.player.print('Basic elem button is now: '..event.element.elem_value)
+end)
+ + +
+
+
+
+ # + empty +
+
+
+
+ +

A empty widget that just exists.

+

The root GUI element screen is an empty-widget.

+ + + Properties / Events: + +
    + + + + + +
  • + + style + + : + + (string) + + the style that the element will have + +
  • + + +
+ + + + + + + + + + + + Usage: +
-- Making a draggable space styled widget
+local draggable_space =
+Gui.new_concept('empty')
+:set_style('draggable_space')
+ + +
+
+
+
+ # + flow +
+
+
+
+ +

Invisible containers that lay out children either horizontally or vertically.

+

The root GUI elements (top, left and center; see LuaGui) are flows.

+ + + Properties / Events:
    @@ -2816,7 +1232,7 @@ (string) - the direction to have the elements be added to the frame + the direction that children will be added @@ -2833,24 +1249,34 @@ + Usage: +
    -- Making a basic flow, contains a label with hello world
    +local basic_flow =
    +Gui.new_concept('flow')
    +:define_draw(function(properties,parent,element)
    +    element.add{
    +        type = 'label',
    +        caption = 'Hello, World!'
    +    }
    +end)
- # - LeftFrames._prototype:_internal_draw(player) + # + frame
-

Creates the gui for the first time, used internally

-

+

Grey semi-transparent boxes that contain other elements.

+

They have a caption, and, just like flows, they lay out children either horizontally or vertically.

- Parameters: + Properties / Events:
    @@ -2860,445 +1286,30 @@
  • - player + title : - (LuaPlayer) + (string or LocalisedString) - the player to draw the frame to + the title that will show in the frame
  • -
- - - - - Returns: - - - - - - - - - - -
-
-
-
- # - 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 + direction : (string) - the action to take on this event + the direction that children will be added - (default: update)
  • @@ -3314,252 +1325,35 @@ - - -
-
-

Popups

-
-
-
-
- # - expcore.gui.core -
-
-
-
- - - - - - - - - - - - - + Usage: +
-- Making a basic frame, contains a label with hello world
+local basic_frame =
+Gui.new_concept('frame')
+:set_title('Basic Frame')
+:define_draw(function(properties,parent,element)
+    element.add{
+        type = 'label',
+        caption = 'Hello, World!'
+    }
+end)
- # - expcore.gui.prototype + # + frame
- - - - - - - - - - - - - - -
-
-
-
- # - 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

+

A piece of text.

- Parameters: + Properties / Events:
    @@ -3569,13 +1363,45 @@
  • - player + caption : - (LuaPlayer) + (string or LocalisedString) - the player to get the flow for + the caption that will show in the label + +
  • + + + + + +
  • + + description + + : + + (string or LocalisedString) + + the description that will show on the label + +
  • + + + + + +
  • + + rich_text + + : + + (defines.rich_text_setting) + + how this element handles rich text
  • @@ -3585,13 +1411,6 @@ - Returns: -
      -
    • - (LuaGuiElement) - the left flow that contains the popup frames -
    • -
    @@ -3599,24 +1418,29 @@ + Usage: +
    -- Making a basic label
    +local basic_label =
    +Gui.new_concept('label')
    +:set_caption('Hello, World!')
- # - PopupFrames.open(define_name, player[, open_time], ...) + # + line
-

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

+

A vertical or horizontal line.

- Parameters: + Properties / Events:
    @@ -3626,29 +1450,66 @@
  • - define_name + direction : (string) - the name of the define that you want to open for the player + the direction that children will be added
  • +
+ + + + + + + + + + + + Usage: +
-- Making a basic frame, contains a label with hello world
+local basic_line =
+Gui.new_concept('line')
+ + +
+
+
+
+ # + progress_bar +
+
+
+
+ +

Indicate progress by displaying a partially filled bar.

+

+ + + Properties / Events: + +
    + +
  • - player + on_completion : - (LuaPlayer) - the player to open the popup for + fired when increment reaches the maxium value set by set_maximum
  • @@ -3658,15 +1519,30 @@
  • - open_time + tooltip + + : + + (string or LocalisedString) + + the tooltip that will show for this element + +
  • + + + + + +
  • + + maximum : (number) - the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default + the maxium amount an instance can be increased, default 100 - (optional)
  • @@ -3675,13 +1551,29 @@
  • - ... + delay_completion : - (any) + (boolean) - the other params that you want to pass to your on_draw event + when true the progress will be completed untill after the maximum rather than at the maximum + +
  • + + + + + +
  • + + inverted + + : + + (boolean) + + although this will NOT effect how you use the functions it will make the element start full and reduce as you call increase, note issues with 0 detections
  • @@ -3691,37 +1583,83 @@ - Returns: + + + + + + + + Usage: +
    -- Making a basic progress bar, will increase when pressed then will reset when full
    +local basic_progress_bar =
    +Gui.new_concept('progress_bar')
    +:set_tooltip('Basic progress bar')
    +:set_maximum(5)
    +:new_event('on_click',defines.events.on_gui_click)
    +:on_click(function(event)
    +    event.concept:increment(event.element)
    +end)
    +:set_delay_completion(true)
    +:on_completion(function(event)
    +    event.concept:reset(event.element)
    +end)
    + + +
+
+
+
+ # + scroll +
+
+
+
+ +

Similar to a flow but includes the ability to show and use scroll bars.

+

+ + + Properties / Events: +
    -
  • - (LuaGuiElement) - the frame that was drawn, the inner gui flow which contains the content + + + + + +
  • + + horizontal_scroll + + : + + (string) + + the horizontal scroll policy for this scroll pane +
  • + + + + + +
  • + + vertical_scroll + + : + + (string) + + the vertical scroll policy for this scroll pane + +
  • + +
- - - - - - - - -
-
-
-
- # - PopupFrames.close_progress -
-
-
-
- -

Progress bar which when depleted will close the popup frame

-

- - @@ -3732,23 +1670,122 @@ + Usage: +
-- Making a basic flow, contains a label with hello world
+local basic_scroll =
+Gui.new_concept('scroll')
+:define_draw(function(properties,parent,element)
+    element.style.hieght = 50
+    for i = 1,10 do
+        element.add{
+            type = 'label',
+            caption = i
+        }
+    end
+end)
- # - PopupFrames.close_button + # + slider
-

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

+

A number picker.

+ Properties / Events: + +
    + + + + + +
  • + + on_value_changed + + : + + + fired when the value of the slider is changed + +
  • + + + + + +
  • + + value_step + + : + + (number) + + the minimum amount by which the value of the slider can be changed + +
  • + + + + + +
  • + + default + + : + + (number or function) + + the default value of the slider or a function which returns the default value + +
  • + + + + + +
  • + + discrete_slider + + : + + (boolean) + + makes this slider a discrete slider, this means that the slider button will stop at the same interval as the values do + +
  • + + + + + +
  • + + range + + : + + (number or function) + + accepts two params the minimum and the maximum for this slider, or a single function to return both + +
  • + + +
+ @@ -3759,20 +1796,571 @@ + Usage: +
-- Making a basic slider
+local basic_slider =
+Gui.new_concept('slider')
+:set_range(1,10)
+:on_value_changed(function(event)
+    event.player.print('Basic slider is now: '..event.element.slider_value)
+end)
+
-- Making a discrete_slider
+local discrete_slider =
+Gui.new_concept('slider')
+:set_range(1,10)
+:set_value_step(1)
+:set_discrete_slider(true)
+:on_value_changed(function(event)
+    event.player.print('Interval slider is now: '..event.element.slider_value)
+end)
- # - PopupFrames.new_popup([name]) + # + table
-

Creates a new popup frame define

+

An invisible container that lays out children in a specific number of columns.

+

Column width is given by the largest element contained in that row.

+ + + Properties / Events: + +
    + + + + + +
  • + + column_count + + : + + (number or function) + + the column count of the table or a function that returns the count being given then parent element + +
  • + + + + + +
  • + + vertical_lines + + : + + (boolean) + + when true vertical lines will be drawn on the table + +
  • + + + + + +
  • + + horizontal_lines + + : + + (boolean) + + when true horizontal lines will be drawn on the table + +
  • + + + + + +
  • + + header_lines + + : + + (boolean) + + when true horizontal lines will be drawn under the first row + +
  • + + + + + +
  • + + vertical_centering + + : + + (boolean) + + when true element will be vertically centered with in the table + +
  • + + +
+ + + + + + + + + + + + Usage: +
-- Making a basic table, contains 25 labels
+local basic_table =
+Gui.new_concept('table')
+:set_column_count(5)
+:define_draw(function(properties,parent,element)
+    for i = 1,25 do
+        element.add{
+            type = 'lable',
+            caption = i
+        }
+    end
+end)
+ + +
+
+
+
+ # + text_box +
+
+
+
+ +

A multi-line text box that supports selection and copy-paste.

+

+ + + Properties / Events: + +
    + + + + + +
  • + + on_text_changed + + : + + + fired when the text within the text box is changed + +
  • + + + + + +
  • + + tooltip + + : + + (string or LocalisedString) + + the tooltip that shows when a player hovers over the text box + +
  • + + + + + +
  • + + default + + : + + (string or function) + + the default text that will appear in the text box, or a function that returns it + +
  • + + + + + +
  • + + rich_text + + : + + (defines.rich_text_setting) + + how this element handles rich text + +
  • + + + + + +
  • + + clear_on_rmb + + : + + (boolean) + + if the text box will be cleared and forcused on a right click + +
  • + + + + + +
  • + + is_selectable + + : + + (boolean) + + when true the text inside the box can be selected + +
  • + + + + + +
  • + + has_word_wrap + + : + + (boolean) + + when true the text will wrap onto the next line if it reachs the end + +
  • + + + + + +
  • + + is_read_only + + : + + (boolean) + + when true the text inside the box can not be edited by the player + +
  • + + +
+ + + + + + + + + + + + Usage: +
-- Making a text box
+local basic_text_box =
+Gui.new_concept('text_box')
+:set_default('I am the text that will show in the text box')
+
-- Making a text box which can be edited
+local editible_text_box =
+Gui.new_concept('text_box')
+:set_is_read_only(false)
+:set_default('I am the text that will show in the text box')
+:on_confirmation(function(event)
+    event.player.print('Editible text box is now: '..event.element.text)
+end)
+ + +
+
+
+
+ # + text_field +
+
+
+
+ +

Boxes of text the user can type in.

+

+ + + Properties / Events: + +
    + + + + + +
  • + + on_text_changed + + : + + + fired when the text within the text field is changed + +
  • + + + + + +
  • + + on_confirmation + + : + + + fired when the player presses enter with the text field forcused + +
  • + + + + + +
  • + + tooltip + + : + + (string or LocalisedString) + + the tooltip that shows when a player hovers over the text field + +
  • + + + + + +
  • + + default + + : + + (string or function) + + the default text that will appear in the text field, or a function that returns it + +
  • + + + + + +
  • + + rich_text + + : + + (defines.rich_text_setting) + + how this element handles rich text + +
  • + + + + + +
  • + + clear_on_rmb + + : + + (boolean) + + if the text field will be cleared and forcused on a right click + +
  • + + + + + +
  • + + lose_forcus + + : + + (boolean) + + if the text field will lose forcus after the confirmation event + +
  • + + + + + +
  • + + is_number + + : + + (boolean) + + if this text field contains a number value, can be ignored if is_decimal or is_negitive is used + +
  • + + + + + +
  • + + is_decimal + + : + + (boolean) + + if this text field contains a decimal value + +
  • + + + + + +
  • + + is_negative + + : + + (boolean) + + if this text field contains a negative value + +
  • + + + + + +
  • + + is_password + + : + + (boolean) + + if this text field contains a password value + +
  • + + +
+ + + + + + + + + + + + Usage: +
-- Making a text field
+local basic_text_field =
+Gui.new_concept('text_field')
+:on_confirmation(function(event)
+    event.player.print('Basic text field is now: '..event.element.text)
+end)
+
-- Making a text field which will clear on right click and un forcus on confirmation
+local better_text_field =
+Gui.new_concept('text_field')
+:set_clear_on_rmb(true)
+:set_lose_forcus(true)
+:on_confirmation(function(event)
+    event.player.print('Better text field is now: '..event.element.text)
+end)
+
-- Making a decimal input
+local decimal_text_field =
+Gui.new_concept('text_field')
+:set_is_decimal(true)
+:on_confirmation(function(event)
+    event.player.print('Decimal text field is now: '..event.element.text)
+end)
+ + +
+
+

Dropdowns

+
+
+
+
+ # + set_dropdown_value(element, value) +
+
+
+
+ +

Selects the index of a dropdown with this value

@@ -3786,18 +2374,186 @@
  • - name + element : - (string) + (LuaGuiElement) - the optional debug name that can be added + the dropdown that you want to set the selection for + +
  • + + + + + +
  • + + value + + : + + (string or LocalisedString) + + the value that you want selected + +
  • + + + + + + + + Returns: +
      +
    • + (boolean) + if an item with this value was found +
    • +
    + + + + + + + + Usage: +
    -- Selecting the item with the value 'foo'
    +Gui.set_dropdown_value(element,'foo')
    + + +
    +
    +
    +
    + # + get_dropdown_value(element) +
    +
    +
    +
    + +

    Gets the selected item value of a dropdown

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the dropdown that you want the selected value of + +
    • + + +
    + + + + + Returns: + + + + + + + + + Usage: +
    -- Getting the selected value
    +local selected_value = Gui.get_dropdown_value(element)
    + + +
    +
    +
    +
    + # + add_dropdown_items(element[, start_index], new_items) +
    +
    +
    +
    + +

    Adds the given items into the list of items for this dropdown

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the dropdown that you want to add the items to + +
    • + + + + + +
    • + + start_index + + : + + (number) + + the index at which the items will be added, if not given appened to the end (optional)
    • + + + +
    • + + new_items + + : + + (table) + + the list of new items that you want to add + +
    • + +
    @@ -3807,7 +2563,7 @@
    • (table) - the new popup frame define + the list of items that the element now has
    @@ -3817,20 +2573,28 @@ + Usage: +
    -- Add the items 'foo' and 'bar' to the end
    +Gui.add_dropdown_items(element,{'foo','bar'})
    +
    -- Add the items 'foo' and 'bar' to the start
    +Gui.add_dropdown_items(element,1,{'foo','bar'})
    +
    +

    Progress Bars

    +
    - # - PopupFrames._prototype:set_default_open_time(amount) + # + progress_bar:increment(element[, amount=1])
    -

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

    +

    Will increase the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances

    @@ -3842,6 +2606,22 @@ +
  • + + element + + : + + (LuaGuiElement or string) + + either the element that is changed or the category that is being changed (only if an instance store is defined) + +
  • + + + + +
  • amount @@ -3850,8 +2630,9 @@ (number) - the number of ticks, by default, the popup will be open for + the amount that will bar will increase, note that this amount must be less than the max + (default: 1)
  • @@ -3863,8 +2644,8 @@ Returns:
    • - (table) - the define to allow for chaining + (number or nil) + the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed
    @@ -3874,20 +2655,25 @@ + Usage: +
    -- Incrementing progress bar with no instance store
    +local new_value = progress_bar:increment(element)
    +
    -- Incrementing progress bar with an instance store
    +progress_bar:increment(category)
    - # - PopupFrames._prototype:open(player[, open_time], ...) + # + progress_bar:decrement(element[, amount=1])
    -

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

    +

    Will decrease the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances

    @@ -3901,13 +2687,13 @@
  • - player + element : - (LuaPlayer) + (LuaGuiElement or string) - the player to open the popup for + either the element that is changed or the category that is being changed (only if an instance store is defined)
  • @@ -3917,30 +2703,76 @@
  • - open_time + amount : (number) - the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default + the amount that will bar will decrease, note that this amount must be less than the max - (optional) + (default: 1)
  • + + + + + + Returns: +
      +
    • + (number) + the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed +
    • +
    + + + + + + + + Usage: +
    -- Decrementing progress bar with no instance store
    +local new_value = progress_bar:decrement(element)
    +
    -- Decrementing progress bar with an instance store
    +progress_bar:decrement(category)
    + + +
    +
    +
    +
    + # + progress_bar:reset(element) +
    +
    +
    +
    + +

    Resets the progress back to 0% for this element, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances

    +

    + + + Parameters: + +
      + +
    • - ... + element : - (any) + (LuaGuiElement or string) - the other params that you want to pass to your on_draw event + either the element that is changed or the category that is being changed (only if an instance store is defined)
    • @@ -3953,190 +2785,58 @@ Returns:
      • + (number or nil) + the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed +
      • +
      + + + + + + + + Usage: +
      -- Reseting a progress bar with no instance store
      +local new_value = progress_bar:reset(element)
      +
      -- Reseting a progress bar with an instance store
      +progress_bar:reset(category)
      + + +
    +
    +
    +
    + # + increment_progress_bar(element[, amount=0.01]) +
    +
    +
    +
    + +

    Increment any progress bar by the given percentage

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + (LuaGuiElement) - the frame that was drawn, the inner gui flow which contains the content + + the progress bar that you want to update +
    • -
    - - - - - - - - - -
    -
    -

    Toolbar

    -
    -
    -
    -
    - # - expcore.gui.core -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.gui.elements.buttons -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.roles -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.event -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - mod-gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - Toolbar.new_button([name]) -
    -
    -
    -
    - -

    Adds a new button to the toolbar

    -

    - - - Parameters: - -
      @@ -4144,15 +2844,15 @@
    • - name + amount : - (string) + (number) - when given allows an alias to the button for the permission system + the percentage that you want to increment the progress bar by - (optional) + (default: 0.01)
    • @@ -4164,309 +2864,8 @@ 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 - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -
    -
    - # - Toolbar.update(player) -
    -
    -
    -
    - -

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

    -

    - - - Parameters: - -
      - - - - - -
    • - - player - - : - - (LuaPlayer) - - the player to update the toolbar for - -
    • - - -
    - - - - - - - - - - - - - -
    -
    -

    Core

    -
    -
    -
    -
    - # - utils.gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - new_define(prototype[, debug_name]) -
    -
    -
    -
    - -

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

    -

    - - - Parameters: - -
      - - - - - -
    • - - prototype - - : - - (table) - - the class prototype that will be used for the element define - -
    • - - - - - -
    • - - debug_name - - : - - (string) - - the name that you want to see while debuging - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the new element define with all functions accessed via __index metamethod -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - get_define(name[, internal]) -
    -
    -
    -
    - -

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

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string or table) - - the uid, debug name or define for the element define to get - -
    • - - - - - -
    • - - internal - - : - (boolean) - - when true the error trace is one level higher (used internally) - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the element define that was found or an error + true if the bar is now full
    @@ -4476,20 +2875,23 @@ + Usage: +
    -- Increment any progress bar by 10%
    +Gui.increment_progress_bar(element,0.1)
    - # - categorize_by_player(element) + # + decrement_progress_bar(element[, amount=0.01])
    -

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

    +

    Decrement any progress bar by the given percentage

    @@ -4509,11 +2911,28 @@ (LuaGuiElement) - the element that will be converted to a string + the progress bar that you want to update + + + +
  • + + amount + + : + + (number) + + the percentage that you want to decrement the progress bar by + + (default: 0.01) +
  • + + @@ -4522,8 +2941,8 @@ Returns:
    • - (string) - the player's name who owns this element + (boolean) + true if the bar is now empty
    @@ -4533,20 +2952,26 @@ + Usage: +
    -- Decrement any progress bar by 10%
    +Gui.decrement_progress_bar(element,0.1)
    +
    +

    Concept Control

    +
    - # - categorize_by_force(element) + # + require_concept(concept_name)
    -

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

    +

    Loads a concept from the concepts file

    @@ -4560,13 +2985,13 @@
  • - element + concept_name : - (LuaGuiElement) + (string) - the element that will be converted to a string + the name of the concept to require
  • @@ -4576,13 +3001,6 @@ - Returns: -
      -
    • - (string) - the player's force name who owns this element -
    • -
    @@ -4590,20 +3008,23 @@ + Usage: +
    -- Load a base concept
    +Gui.require_concept('frame') --- @dep Gui.concept.frame
    - # - categorize_by_surface(element) + # + require_style(style_name)
    -

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

    +

    Loads a set of concepts from the styles file

    @@ -4617,13 +3038,13 @@
  • - element + style_name : - (LuaGuiElement) + (string) - the element that will be converted to a string + the name of the style to require
  • @@ -4633,13 +3054,6 @@ - Returns: -
      -
    • - (string) - the player's surface name who owns this element -
    • -
    @@ -4647,20 +3061,23 @@ + Usage: +
    -- Load a base style
    +Gui.require_concept('expgaming') --- @dep Gui.style.frame
    - # - draw(name, element) + # + get_concept(name)
    -

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

    +

    Gets a gui concept from name, id, or its self

    @@ -4678,9 +3095,172 @@ : - (string or table) + (string, number or table) - the uid, debug name or define for the element define to draw + the name, id, or the concept you want to get + + + + + + + + + + + + + + + + + Usage: +
    -- Getting a gui concept
    +local button = Gui.get_concept('Button')
    + + +
    +
    +
    +
    + # + Prototype:save_as(save_name) +
    +
    +
    +
    + +

    Used to save the concept to the main gui module to allow access from other files

    +

    + + + Parameters: + +
      + + + + + +
    • + + save_name + + : + + (string) + + the new name of the concept + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Save a concept to allow access in another file
    +button:save_as('button')
    +
    -- Access concept after being saved
    +Gui.concepts.button
    +Gui.get_concept('button')
    + + +
    +
    +
    +
    + # + new_concept([base_concept]) +
    +
    +
    +
    + +

    Returns a new gui concept, option to provide a base concept to copy properties and draw functions from

    +

    + + + Parameters: + +
      + + + + + +
    • + + base_concept + + : + + (string, number or table) + + the concept that you want to copy the details of + + (optional) +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Making a new button, see module usage
    +local button = Gui.new_concept('Button')
    + + +
    +
    +
    +
    + # + draw_concept(concept, parent) +
    +
    +
    +
    + +

    Used to draw a concept to a parent element

    +

    + + + Parameters: + +
      + + + + + +
    • + + concept + + : + + (string, number or table) + + the name of the concept that you want to draw
    • @@ -4690,13 +3270,13 @@
    • - element + parent : - (LuaGuiEelement) + (LuaGuiElement) - the parent element that it the define will be drawn to + the element that will act as a parent for the new element
    • @@ -4710,7 +3290,7 @@
      • (LuaGuiElement) - the new element that was created + the element that was created
      @@ -4720,6 +3300,192 @@ + Usage: +
      -- Drawing a new element
      +Gui.draw_concept('Button',element)
      + + +
    +
    +

    Element Control

    +
    +
    +
    +
    + # + get_player_from_element(element) +
    +
    +
    +
    + +

    Gets the player who owns this element

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to get the player of + +
    • + + +
    + + + + + Returns: +
      +
    • + (LuaPlayer) + the player who owns this element +
    • +
    + + + + + + + + Usage: +
    -- Getting the player of an element
    +local player = Gui.get_player_from_element(element)
    + + +
    +
    +
    +
    + # + valid(element) +
    +
    +
    +
    + +

    Simple check for if an element is valid

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to check is valid + +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + true if the element is valid +
    • +
    + + + + + + + + Usage: +
    -- Return if not valid
    +if not Gui.valid(element) then return end
    + + +
    +
    +
    +
    + # + destroy(element) +
    +
    +
    +
    + +

    Destroies and element if it is valid

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to destroy + +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + true if the element was valid and was destoried +
    • +
    + + + + + + + + Usage: +
    -- Destoring an element
    +Gui.destroy(element)
    @@ -4733,7 +3499,7 @@
    -

    Will toggle the enabled state of an element

    +

    Toggles the enabled state of an element

    @@ -4753,7 +3519,7 @@ (LuaGuiElement) - the gui element to toggle + the element that you want to toggle the enabled state of @@ -4767,7 +3533,7 @@
    • (boolean) - the new state that the element has + the new enabled state of the element
    @@ -4777,6 +3543,9 @@ + Usage: +
    -- Toggle the enabled state of an element
    +Gui.toggle_enabled(element)
    @@ -4790,7 +3559,7 @@
    -

    Will toggle the visiblity of an element

    +

    Toggles the visible state of an element

    @@ -4810,7 +3579,7 @@ (LuaGuiElement) - the gui element to toggle + the element that you want to toggle the visible state of @@ -4824,7 +3593,7 @@
    • (boolean) - the new state that the element has + the new visible state of the element
    @@ -4834,6 +3603,9 @@ + Usage: +
    -- Toggle the visible state of an element
    +Gui.toggle_visible(element)
    @@ -4881,9 +3653,9 @@ : - (number) + (number or boolean) - the amount of padding on the top + the amount of padding on the top, true leaves unchanged (default: 0) @@ -4898,1628 +3670,45 @@ : - (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 - - (optional) -
    • - - - - - -
    • - - horizontal_align - - : - - (string) - - the horizontal alignment of the elements in this flow - - (default: 'right') -
    • - - - - - -
    • - - vertical_align - - : - - (string) - - the vertical alignment of the elements in this flow - - (default: 'center') -
    • - - -
    - - - - - Returns: - - - - - - - - - - -
    -
    -
    -
    - # - destroy_if_valid(element) -
    -
    -
    -
    - -

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

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (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 - -
    • - - - - - -
    • - - table_size - - : - - (number) - - the number of columns in the table - -
    • - - - - - -
    • - - maximal_height - - : - - (number) - - the max hieght of the scroll - -
    • - - - - - -
    • - - name - - : - - (string) - - the name of the scoll element - - (default: 'scroll') -
    • - - -
    - - - - - Returns: - - - - - - - - - - -
    -
    -
    -
    - # - create_header(element, caption[, tooltip][, right_align][, name='header']) -
    -
    -
    -
    - -

    Creates a header section with a label and button area

    -

    - - - Parameters: - -
      - - - - - -
    • - - element - - : - - (LuaGuiElement) - - the element to add this header into - -
    • - - - - - -
    • - - caption - - : - - (localeString) - - the caption that is used as the title - -
    • - - - - - -
    • - - tooltip - - : - - (localeString) - - the tooltip that is shown on the caption - - (optional) -
    • - - - - - -
    • - - right_align - - : - - (boolean) - - when true will include the right align area - - (optional) -
    • - - - - - -
    • - - name - - : - - (string) - - the name of the header area - - (default: 'header') -
    • - - -
    - - - - - Returns: -
      -
    • - (LuaGuiElement) - the header that was made, or the align area if that was created -
    • -
    - - - - - - - - - -
    -
    -

    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(name, callback, categorize) -
    -
    -
    -
    - -

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

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the option set, must be unique - -
    • - - - - - -
    • - - 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 + the amount of padding on the bottom, true leaves unchanged - (default: false) + (default: 0) +
    • + + + + + +
    • + + left + + : + + (number or boolean) + + the amount of padding on the left, true leaves unchanged + + (default: 0) +
    • + + + + + +
    • + + right + + : + + (number or boolean) + + the amount of padding on the right, true leaves unchanged + + (default: 0)
    • @@ -6528,13 +3717,6 @@ - Returns: -
        -
      • - (boolean) - true if successful -
      • -
      @@ -6542,433 +3724,30 @@ + Usage: +
      -- Remove all padding of an element
      +Gui.set_padding(element)
      +
      -- Remove side padding but keep vertical padding
      +Gui.set_padding(element,true,true)
      +
      -- Remove all padding but set right to 2
      +Gui.set_padding(element,false,false,false,2)
    -

    Dropdowns

    +

    Store Categories

    - # - expcore.gui.core + # + categorize_by_player(element)
    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - 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

    +

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

    @@ -6988,23 +3767,7 @@ (LuaGuiElement) - the element that contains the option - - - - - - - -
  • - - value - - : - - (string) - - the option to select from the dropdown + the element that will be converted to a string
  • @@ -7017,8 +3780,8 @@ Returns:
    • - (number) - the key where the value was + (string) + the player's name who owns this element
    @@ -7028,20 +3791,24 @@ + Usage: +
    -- Storing data on a per player basis, can be used with instances
    +Gui.get_concept('CustomButton')
    +:define_data_store(Gui.categorize_by_player)
    - # - Dropdown.get_selected_value(element) + # + categorize_by_force(element)
    -

    Returns the currently selected value rather than index

    +

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

    @@ -7061,7 +3828,7 @@ (LuaGuiElement) - the gui element that you want to get the value of + the element that will be converted to a string @@ -7075,7 +3842,7 @@
    • (string) - the value that is currently selected + the player's force name who owns this element
    @@ -7085,24 +3852,240 @@ + Usage: +
    -- Storing data on a per force basis, can be used with instances
    +Gui.get_concept('CustomButton')
    +:define_data_store(Gui.categorize_by_force)
    + + +
    +
    +
    +
    + # + categorize_by_surface(element) +
    +
    +
    +
    + +

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

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that will be converted to a string + +
    • + + +
    + + + + + Returns: +
      +
    • + (string) + the player's surface name who owns this element +
    • +
    + + + + + + + + Usage: +
    -- Storing data on a per surface basis, can be used with instances
    +Gui.get_concept('CustomButton')
    +:define_data_store(Gui.categorize_by_surface)
    -

    Elem Buttons

    +

    Concept Base

    - # - expcore.gui.core + # + Prototype:clone(concept_name)
    +

    Used to copy all the settings from one concept to another and removing links to the orginal

    +

    + Parameters: + +
      + + + + + +
    • + + concept_name + + : + + (string) + + the name of the new concept; must be unique + +
    • + + +
    + + + + + Returns: +
      +
    • + (GuiConcept) + the base for building a custom gui +
    • +
    + + + + + + + + Usage: +
    -- Clones the base Button concept to make a alternative button
    +local custom_button =
    +Gui.get_concept(Gui.concepts.button):clone()
    + + +
    +
    +
    +
    + # + Prototype:define_clone(clone_callback) +
    +
    +
    +
    + +

    Use to add your own callbacks to the clone function, for example adding to a local table

    +

    + + + Parameters: + +
      + + + + + +
    • + + clone_callback + + : + + (function) + + the function which is called with the concept to have something done to it + +
    • + + +
    + + + + + Returns: +
      +
    • + (table) + self to allow chaining +
    • +
    + + + + + + + + Usage: +
    -- Adding concept to a local table
    +local buttons = {}
    +local button =
    +Gui.get_concept('Button')
    +:define_clone(function(concept)
    +    buttons[concept.name] = concept
    +end)
    + + +
    +
    +
    +
    + # + Prototype:save_as(save_name) +
    +
    +
    +
    + +

    Used to save the concept to the main gui module to allow access from other files

    +

    + + + Parameters: + +
      + + + + + +
    • + + save_name + + : + + (string) + + the new name of the concept + +
    • + + +
    + @@ -7113,70 +4096,26 @@ + Usage: +
    -- Save a concept to allow access in another file
    +button:save_as('button')
    +
    -- Access concept after being saved
    +Gui.concepts.button
    +Gui.get_concept('button')
    - # - expcore.gui.prototype + # + Prototype:debug(name)
    - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.game -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - ElemButton.new_elem_button([name]) -
    -
    -
    -
    - -

    Creates a new elem button element define

    +

    Sets a debug name that can be used with error handlers

    @@ -7196,1331 +4135,8 @@ (string) - the optional debug name that can be added + the name that will be used in error messages - (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)
    • @@ -8533,7 +4149,7 @@
      • (self) - the define to allow chaining + to allow chaining
      @@ -8543,1204 +4159,23 @@ + Usage: +
      -- Set the debug name
      +unsaved_concept:debug('Example button')
    - # - Slider._prototype:draw_label(element) + # + Prototype:new_event(event_name[, factorio_event][, event_condition])
    -

    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 categorise function; must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - name - - : - - (string) - - the name of the instance group - -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if there is a categorise 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[, categorise]) -
    -
    -
    -
    - -

    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 - -
    • - - - - - -
    • - - categorise - - : - - (function) - - function used to turn the element into a string - categorise param - element LuaGuiElement - the gui element to be turned into a string - categorise return - string - the category that the element will be added to like the player's name or force's name - - (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 categorise 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 categorise 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

    +

    Adds a new event trigger to the concept which can be linked to a factorio event

    @@ -9760,122 +4195,25 @@ (string) - the name of the event that callbacks will be added to + the name of the event to add, must be unique, recomented to start with "on_" - - - - - - 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 + factorio_event : - (table) + (defines.events) - the prototype that you want to add the functions to - -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - the same prototype but with the new functions added -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - Constructor.store(sync, callback) -
    -
    -
    -
    - -

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

    -

    - - - Parameters: - -
      - - - - - -
    • - - sync - - : - - (boolean) - - if the function should create a synced store + when given will fire the custom event when the factorio event is raised + (optional)
    • @@ -9884,102 +4222,13 @@
    • - callback + event_condition : (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 + used to filter when a factorio event triggers the custom event; if the event contains a reference to an element then names are automatically filtered (optional)
    • @@ -9993,8 +4242,8 @@ Returns:
      • - (function) - the function that will check the type and set the value + (GuiConcept) + to allow chaining of functions
      @@ -10004,407 +4253,27 @@ + Usage: +
      -- Adds an on_admin_clicked event to fire when ever an admin clicks the button
      +local custom_button =
      +Gui.get_concept('Button'):clone('CustomButton')
      +:new_event('on_admin_clicked',defines.events.on_gui_click,function(event)
      +    return event.player.admin -- only raise custom event when an admin clicks the button
      +end)
    - # - Prototype:uid() + # + Prototype:on_custom_event(handler)
    -

    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

    +

    Adds a custom event handler, replace with the name of the event

    @@ -10418,87 +4287,13 @@
  • - style - - : - - (string) - - the style that will be used for this element when drawn - -
  • - - - - - -
  • - - callback + handler : (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 + the function which will recive the event
    • @@ -10511,8 +4306,8 @@ Returns:
      • - (self) - the element define to allow chaining + (GuiConcept) + to allow chaining of functions
      @@ -10522,6 +4317,13 @@ + Usage: +
      -- When an admin clicks the button a message is printed
      +local custom_button =
      +Gui.get_concept('CustomButton')
      +:on_admin_clicked(function(event)
      +    game.print(event.player.name..' pressed my admin button')
      +end)
    @@ -10529,13 +4331,13 @@
    # - Prototype:raise_event(event_name, ...) + Prototype:raise_event(event_name[, event={}][, from_factorio=false])
    -

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

    +

    Raises a custom event, folowing keys included automaticlly: concept, event name, game tick, player from player_index, element if valid

    @@ -10565,13 +4367,197 @@
  • - ... + event + + : + + (table) + + table containg data you want to send with the event, some keys already included + + (default: {}) +
  • + + + + + +
  • + + from_factorio + + : + + (boolean) + + internal use, if the raise came from the factorio event handler + + (default: false) +
  • + + + + + + + + + + + + + + + Usage: +
    -- Raising the custom event on_admin_clicked
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +-- Note that this is an example and would not work due it expecting a valid element for event.element
    +-- this will however work fine if you can provide all expected keys, or its not linked to any factorio event
    +custom_button:raise_event('on_admin_clicked',{
    +    player_index = game.player.index
    +})
    + + +
    +
    +
    +
    + # + Prototype:new_property(property_name[, setter_callback][, default]) +
    +
    +
    +
    + +

    Adds a new property to the concept, such as caption, tooltip, or some custom property you want to control

    +

    + + + Parameters: + +
      + + + + + +
    • + + property_name + + : + + (string) + + the name of the new property, must be unique + +
    • + + + + + +
    • + + setter_callback + + : + + (function) + + this function is called when set is called, if not provided then key in concept.properties is updated to new value + + (optional) +
    • + + + + + +
    • + + default : (any) - any params that you want to pass to the event + use this as the default value, will call the setter callback if defined + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (GuiConcept) + to allow chaining of functions +
    • +
    + + + + + + + + Usage: +
    -- Adding caption, sprite, and tooltip to the base button concept
    +local button =
    +Gui.get_concept('Button')
    +:new_property('tooltip')
    +:new_property('caption',nil,function(properties,value)
    +    properties.caption = value
    +    properties.sprite = nil
    +    properties.type = 'button'
    +end)
    +:new_property('sprite',nil,function(properties,value)
    +    properties.image = value
    +    properties.caption = nil
    +    properties.type = 'sprite-button'
    +end)
    + + +
    +
    +
    +
    + # + Prototype:set_custom_property(value) +
    +
    +
    +
    + +

    Sets a new value for a property, triggers setter method if provided, replace with property name

    +

    + + + Parameters: + +
      + + + + + +
    • + + value + + : + + (any) + + the value that you want to set for this property
    • @@ -10584,8 +4570,8 @@ Returns:
      • - (number) - the number of handlers that were registered + (GuiConcept) + to allow chaining of functions
      @@ -10595,21 +4581,315 @@ + Usage: +
      -- Setting the caption on the base button concept after a cloning
      +local custom_button =
      +Gui.get_concept('Button')
      +:set_caption('Default Button')
      +
      -- In our examples CustomButton is cloned from Button, this means the caption property already exists
      +-- note that what ever values that properties have at the time of cloning are also copied
      +local custom_button =
      +Gui.get_concept('CustomButton')
      +:set_caption('Custom Button')
    - # - Prototype:draw_to(element) + # + Prototype:define_draw(draw_callback)
    -

    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

    +

    Used to define how the concept is turned into an ingame element or "instance" as we may refer to them

    +

    + + + Parameters: + +
      + + + + + +
    • + + draw_callback + + : + + (function) + + the function that will be called to draw/update the instance; this function must return the instance or the new acting instance + +
    • + + +
    + + + + + Returns: +
      +
    • + (GuiConcept) + to allow chaining of functions +
    • +
    + + + + + + + + Usage: +
    -- Adding the draw define for the base button concept, we then return the element
    +local button =
    +Gui.get_concept('Button')
    +:define_draw(function(properties,parent,element)
    +    -- Properties will include all the information that you need to draw the element
    +    -- Parent is the parent element for the element, this may have been altered by previous draw functions
    +    -- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function
    +    -- You can also pass any other arguments that you want to this function from the draw call
    +    if properties.type == 'button' then
    +        element = parent.add{
    +            type = properties.type,
    +            name = properties.name,
    +            caption = properties.caption,
    +            tooltip = properties.tooltip
    +        }
    +
    +    else
    +        element = parent.add{
    +            type = properties.type,
    +            name = properties.name,
    +            sprite = properties.sprite,
    +            tooltip = properties.tooltip
    +        }
    +
    +    end
    +
    +    -- If you return element or parent then their values will be updated for the next draw function in the chain
    +    -- It is best practice to always return the values if you have made any changes to them
    +    return element, parent
    +end)
    + + +
    +
    +
    +
    + # + Prototype:draw(parent_element) +
    +
    +
    +
    + +

    Calls all the draw functions in order to create this concept in game; will also store and sync the instance if stores are used

    +

    + + + Parameters: + +
      + + + + + +
    • + + parent_element + + : + + (LuaGuiElement) + + the element that the concept will use as a base + +
    • + + +
    + + + + + Returns: +
      +
    • + (LuaGuiElement) + the element that was created and then passed though and returned by the draw functions +
    • +
    + + + + + + + + Usage: +
    -- Drawing the custom button concept
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +-- Note that the draw function from button was cloned, so unless we want to alter the base button we dont need a new draw define
    +custom_button:draw(game.player.gui.left)
    + + +
    +
    +

    Concept Instances

    +
    +
    +
    +
    + # + Prototype:define_instance_store([category_callback]) +
    +
    +
    +
    + +

    Adds an instance store to the concept; when a new instance is made it is stored so you can access it later

    +

    + + + Parameters: + +
      + + + + + +
    • + + category_callback + + : + + (function) + + when given will act as a way to turn an element into a string to act as a key; keys returned can over lap + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (GuiConcept) + to allow chaining of functions +
    • +
    + + + + + + + + Usage: +
    -- Allowing storing instances of the custom button; stored by the players index
    +-- Note even thou this is a copy of Button; if Button had an instance store it would not be cloned over
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +:define_instance_store(function(element)
    +    return element.player_index -- The instances are stored based on player id
    +end)
    + + +
    +
    +
    +
    + # + Prototype.get_instances([category]) +
    +
    +
    +
    + +

    Gets all insatnces in a category, category may be nil to return all

    +

    + + + Parameters: + +
      + + + + + +
    • + + category + + : + + (string or LuaGuiElement) + + the category to get, can only be nil if categories are not used + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (table) + a table which contains all the instances +
    • +
    + + + + + + + + Usage: +
    -- Getting all the instances of the player with index 1
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +custom_button.get_instances(1) -- player index 1
    + + +
    +
    +
    +
    + # + Prototype.add_instance(element[, category]) +
    +
    +
    +
    + +

    Adds an instance to this concept, used automatically during concept:draw

    @@ -10629,23 +4909,33 @@ (LuaGuiElement) - the element that the define will draw a instance of its self onto + the element that will be added as an instance + + + +
  • + + category + + : + + (string) + + the category to add this element under, if nil the category callback is used to assign one + + (optional) +
  • + + - Returns: - @@ -10653,20 +4943,26 @@ + Usage: +
    -- Adding an element as a instance for this concept, mostly for internal use
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +custom_button.add_instance(element) -- normally not needed due to use in concept:draw
    - # - Prototype:get_store(category) + # + Prototype.update_instances([category], update_callback)
    -

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

    +

    Applies an update function to all instances, simialr use to what table.forEach would be

    @@ -10684,10 +4980,155 @@ : - (string) + (string or LuaGuiElement) - [opt] the category to get such as player name or force name + the category to get, can only be nil if categories are not used + (optional) + + + + + + +
  • + + update_callback + + : + + (function) + + the function which is called on each instance, recives other args passed to update_instances + +
  • + + + + + + + + + + + + + + + Usage: +
    -- Changing the font color of all instances for player 1
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +custom_button.update_instances(1,function(element)
    +    element.style.font_color = {r=1,g=0,b=0}
    +end)
    + + +
    +
    +

    Concept Data

    +
    +
    +
    +
    + # + Prototype:define_data_store([category_callback]) +
    +
    +
    +
    + +

    Adds a data store to this concept which allows you to store synced/percistent data between instances

    +

    + + + Parameters: + +
      + + + + + +
    • + + category_callback + + : + + (function) + + when given will act as a way to turn an element into a string to act as a key; keys returned can over lap + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (GuiConcept) + to allow chaining of functions +
    • +
    + + + + + + + + Usage: +
    -- Adding a way to store data for this concept; each player has their own store
    +-- Note even thou this is a copy of Button; if Button had an data store it would not be cloned over
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +:define_data_store(function(element)
    +    return element.player_index -- The data is stored based on player id
    +end)
    + + +
    +
    +
    +
    + # + Prototype.get_data([category]) +
    +
    +
    +
    + +

    Gets the data that is stored for this category

    +

    + + + Parameters: + +
      + + + + + +
    • + + category + + : + + (string or LuaGuiElement) + + the category to get, can only be nil if categories are not used + + (optional)
    • @@ -10700,7 +5141,7 @@
      • (any) - the value that is stored for this define + the data that you had stored in this location
      @@ -10710,20 +5151,26 @@ + Usage: +
      -- Getting the stored data for player 1
      +local custom_button =
      +Gui.get_concept('CustomButton')
      +
      +custom_button.get_data(1) -- player index 1
    - # - Prototype:set_store(category, value) + # + Prototype.set_data([category], value)
    -

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

    +

    Sets the data that is stored for this category

    @@ -10741,10 +5188,11 @@ : - (string) + (string or LuaGuiElement) - [opt] the category to get such as player name or force name + the category to set, can only be nil if categories are not used + (optional) @@ -10759,7 +5207,7 @@ (any) - the value to set for this define, must be valid for its type ie for checkbox etc + the data that you want to stored in this location @@ -10769,13 +5217,6 @@ - Returns: -
      -
    • - (boolean) - true if the value was set -
    • -
    @@ -10783,20 +5224,31 @@ + Usage: +
    -- Setting the data for player 1 to a table with two keys
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +-- A table is used to show correct way to use a table with self.update_data
    +-- but a table is not required and can be any data, however upvalues may cause desyncs
    +custom_button.set_data(1,{
    +    clicks = 0,
    +    required_clicks = 100
    +}) -- player index 1
    - # - Prototype:clear_store([category]) + # + Prototype.clear_data([category])
    -

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

    +

    Clears the data that is stored for this category

    @@ -10814,14 +5266,171 @@ : - (string) + (string or LuaGuiElement) - the category to get such as player name or force name + the category to clear, can only be nil if categories are not used (optional) + + + + + + + + + + + + + Usage: +
    -- Clearing the data for player 1
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +custom_button.clear_data(1) -- player index 1
    + + +
    +
    +
    +
    + # + Prototype.update_data([category], update_callback) +
    +
    +
    +
    + +

    Updates the data that is stored for this category

    +

    + + + Parameters: + +
      + + + + + +
    • + + category + + : + + (string or LuaGuiElement) + + the category to clear, can only be nil if categories are not used + + (optional) +
    • + + + + + +
    • + + update_callback + + : + + (function) + + the function which is called to update the data + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Updating the clicks key in the concept data for player 1
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +custom_button.update_data(1,function(tbl)
    +    tbl.clicks = tbl.clicks + 1 -- here we are incrementing the clicks by 1
    +end) -- player index 1
    +
    +
    -- Updating a value when a table is not used, alterative to get set
    +-- so for this example assume that we did custom_button.set_data(1,0)
    +custom_button.update_data(1,function(value)
    +    return value + 1 -- here we are incrementing the value by 1, we may only be tracking clicks
    +end) -- player index 1
    + + +
    +
    +

    Concept Combined Instances

    +
    +
    +
    +
    + # + Prototype:define_combined_store([category_callback], sync_callback) +
    +
    +
    +
    + +

    Used to add a both instance and data store which are linked together, new instances are synced to the current value, changing the stored value will change all instances

    +

    + + + Parameters: + +
      + + + + + +
    • + + category_callback + + : + + (function) + + when given will act as a way to turn an element into a string to act as a key; keys returned can over lap + + (optional) +
    • + + + + + +
    • + + sync_callback + + : + + (function) + + the function which is called to update an instance to match the store, this is called on all instances when concept.set_data or update_data is used + +
    • + +
    @@ -10830,8 +5439,8 @@ Returns:
    • - (boolean) - true if the value was set + (GuiConcept) + to allow chaining of functions
    @@ -10841,124 +5450,136 @@ + Usage: +
    -- Adding a check box which is a "global setting" synced between all players
    +local custom_button =
    +Gui.get_concept('checkbox'):clone('my_checkbox')
    +:set_caption('My Checkbox')
    +:set_tooltip('Clicking this check box will change it for everyone')
    +:on_state_changed(function(event)
    +    local element = event.element
    +    event.concept.set_data(element,element.state) -- Update the stored data to trigger an update of all other instances
    +end)
    +:define_combined_store(function(element,state) -- We could add a category function here if we wanted to
    +    element.state = state or false -- Note that the value passed may be nil if there is no stored value and no default set
    +end)
    + + +
    +
    +
    +
    + # + Prototype.sync_instance(element) +
    +
    +
    +
    + +

    Will sync an instance to match the stored value based on the given sync callback

    +

    + + + Parameters: + +
      + + + + + +
    • + + element + + : + + (LuaGuiElement) + + the element that you want to have update + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Setting the caption of this element to be the same as the stored value
    +local custom_button =
    +Gui.get_concept('CustomButton')
    +
    +-- Used internally when first draw and automatically when the store updates
    +custom_button.sync_instance(element)
    -

    Test

    +

    Tests

    - # - expcore.gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.common -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - resources.color_presets -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.event -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.store + # + run_tests(player[, category])
    +

    Runs a set of gui tests to ensure that the system is working

    +

    + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that the guis are made for and who recives the results + +
    • + + + + + +
    • + + category + + : + + (string) + + when given only tests in this category are ran + + (optional) +
    • + + +
    + @@ -10969,6 +5590,9 @@ + Usage: +
    -- Run all gui tests
    +Gui.run_tests(game.player)
    @@ -10987,7 +5611,7 @@ generated by LDoc diff --git a/docs/core/Permissions-Groups.html b/docs/core/Permissions-Groups.html index f2878f57..6095d508 100644 --- a/docs/core/Permissions-Groups.html +++ b/docs/core/Permissions-Groups.html @@ -60,6 +60,7 @@ + @@ -1432,7 +1433,7 @@ generated by LDoc diff --git a/docs/core/Roles.html b/docs/core/Roles.html index a6a994fb..3e6a7fa4 100644 --- a/docs/core/Roles.html +++ b/docs/core/Roles.html @@ -64,6 +64,7 @@ + @@ -3152,7 +3153,7 @@ generated by LDoc diff --git a/docs/core/Store.html b/docs/core/Store.html index eb815f53..6fd3ab97 100644 --- a/docs/core/Store.html +++ b/docs/core/Store.html @@ -57,6 +57,7 @@ + @@ -234,73 +235,46 @@

    Usage

    
    ----- Basic Use
    -    -- At the most basic level this allows for the naming of locations to store in the global table, the second feature is that you are
    -    -- able to listen for updates of this value, which means that when ever the set function is called it will trigger the update callback.
    -
    -    -- This may be useful when storing config values and when they get set you want to make sure it is taken care of, or maybe you want
    -    -- to have a value that you can trigger an update of from different places.
    -
    -    -- This will register a new location called 'scenario.difficulty'
    -    -- note that setting a start value is optional and we could take nil to mean normal
    -    Store.register('scenario.difficulty',function(value)
    -        game.print('The scenario difficulty has be set to: '..value)
    -    end)
    +-- The data store module is designed to be an alterative way to store data in the global table
    +-- each piece of data is stored at a location and optional key of that location
    +-- it is recomented that you use a local varible to store the location
    +local scenario_difficuly = Store.uid_location()
    +local team_scores = 'team-scores'
     
    -    -- This will set the value in the store to 'hard' and will trigger the update callback which will print a message to the game
    -    Store.set('scenario.difficulty','hard')
    +-- Setting and getting data is then as simple as
    +-- note that when storing a table you must use Store.update
    +Store.set(scenario_difficuly,'Hard')
    +Store.set(team_scores,game.player.force.name,20)
     
    -    -- This will return 'hard'
    -    Store.get('scenario.difficulty')
    -
    
    ----- Using Children
    -    -- One limitation of store is that all locations must be registered to avoid desyncs, to get round this issue "children" can be used.
    -    -- When you set the value of a child it does not have its own update callback so rather the "parent" location which has been registered
    -    -- will have its update value called with a second param of the name of that child.
    +Store.get(scenario_difficuly) -- returns 'Hard'
    +Store.get(team_scores,game.player.force.name) -- returns 20
     
    -    -- This may be useful when you want a value of each player or force and since you cant register every player at the start you must use
    -    -- the players name as the child name.
    -
    -    -- This will register the location 'scenario.score' where we plan to use force names as the child
    -    Store.register('scenario.score',function(value,child)
    -        game.print(child..' now has a score of '..value)
    -    end)
    +Store.update(team_scores,game.player.force.name,function(value,key)
    +    return value + 10 -- add 10 to the score
    +end)
     
    -    -- This will return nil, but will not error as children don't need to be registered
    -    Store.get('scenario.score','player')
    +-- The reason for using stores over global is the abilty to watch for updates
    +-- for stores to work you must register them, often at the end of the file
    +Store.register(scenario_difficuly,function(value)
    +    game.print('Scenario difficulty has been set to: '..value)
    +end)
     
    -    -- This will set 'player' to have a value of 10 for 'scenario.score' and trigger the game message print
    -    Store.set('scenario.score','player',10)
    +Store.register(team_scores,function(value,key)
    +    game.print('Team '..key..' now has a score of '..value)
    +end)
     
    -    -- This would be the similar to Store.get however this will return the names of all the children
    -    Store.get_children('scenario.score')
    -
    
    ----- Using Sync
    -    -- There is the option to use synced values which is the same as a normal value however you can combine this with an external script
    -    -- which can read the output from 'script-output/log/store.log' and have it send rcon commands back to the game allowing for cross instance
    -    -- syncing of values.
    -
    -    -- This may be useful when you want to have a value change effect multiple instances or even if you just want a database to store values so
    -    -- you can sync data between map resets.
    -
    -    -- This example will register the location 'statistics.total-play-time' where we plan to use plan names as the child
    -    -- note that the location must be the same across instances
    -    Store.register('statistics.total-play-time',true,function(value,child)
    -        game.print(child..' now has now played for '..value)
    -    end)
    +-- This can be very powerful when working with data that can be changed for a number of locations
    +-- with this module you can enable any location to output its changes to a file
    +-- say we wanted team scores to be synced across servers or between saves
    +-- although you will need to set up a method of storing the data outside the game
    +Store.register(team_scores,true,function(value,key)
    +    game.print('Team '..key..' now has a score of '..value)
    +end)
     
    -    -- Use of set and are all the same as non synced but you should include from_sync as true
    -
    -
    
    ----- Alternative method
    -    -- Some people may prefer to use a variable rather than a string for formating reasons here is an example. Also for any times when
    -    -- there will be little external input Store.uid_location() can be used to generate non conflicting locations, uid_location will also
    -    -- be used if you give a nil location.
    -
    -    local store_game_speed =
    -    Store.register(function(value)
    -        game.print('The game speed has been set to: '..value)
    -    end)
    +-- If you want multiple handlers on one store location then you can register to the raw event +Event.add(Store.events.on_value_changed,function(event) + game.print('Store '..event.location..'/'..event.key..' was updated to: '..event.value) +end) @@ -333,33 +307,41 @@ + register([location][, synced=false][, callback]) + Registers a new location with an update callback which is triggered when the value updates + + + get(location[, key]) + Gets the value stored at a location, this location must be registered + + + set(location[, key], value[, from_sync=false][, from_internal=false]) + Sets the value at a location, this location must be registered + + + update(location[, key][, update_callback]) + Allows for updating a value based on the current value; only valid way to change tables in a store + + + update_all(location[, update_callback]) + Allows for updating all values at a location based on the current value; only valid way to change tables in a store + + + clear(location[, key][, from_sync=false]) + Sets the value at a location to nil, this location must be registered + + + get_keys(location) + Gets all non nil keys at a location, keys can be added and removed during runtime +this is similar to Store.get but will always return a table even if it is empty + + is_registered(location) Check for if a location is registered uid_location() Returns a unique name that can be used for a store - - - register([location][, synced][, callback]) - Registers a new location with an update callback which is triggered when the value updates - - - get(location[, child][, allow_unregistered=false]) - Gets the value stored at a location, this location must be registered - - - set(location[, child], value[, from_sync]) - Sets the value at a location, this location must be registered - - - clear(location[, child][, from_sync]) - Sets the value at a location to nil, this location must be registered - - - get_children(location) - Gets all non nil children at a location, children can be added and removed during runtime - this is similar to Store.get but will always return a table even if it is empty @@ -476,6 +458,643 @@
    + # + register([location][, synced=false][, callback]) +
    +
    +
    +
    + +

    Registers a new location with an update callback which is triggered when the value updates

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + string a unique that points to the data, string used rather than token to allow migration + + (optional) +
    • + + + + + +
    • + + synced + + : + + (boolean) + + when true will output changes to a file so it can be synced + + (default: false) +
    • + + + + + +
    • + + callback + + : + + (function) + + when given the callback will be automatically registered to the update of the value + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (string) + the location that is being used +
    • +
    + + + + + + + + Usage: +
    -- Registering a new store location
    +local store_id = Store.register()
    +
    -- Registering a new store location, with custom update callback
    +local store_id = Store.uid_location()
    +Store.register(store_id,function(value,key)
    +    game.print('Store '..store_id..'/'..key..' was updated to: '..value)
    +end)
    + + +
    +
    +
    +
    + # + get(location[, key]) +
    +
    +
    +
    + +

    Gets the value stored at a location, this location must be registered

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + the location to get the data from + +
    • + + + + + +
    • + + key + + : + + (string) + + the key location if used + + (optional) +
    • + + +
    + + + + + Returns: +
      +
    • + (any) + the data which was stored at the location +
    • +
    + + + + + + + + Usage: +
    -- Getting the data at a store location
    +local data = Store.get(store_id_no_keys)
    +local data = Store.get(store_id_with_keys,'key_one')
    + + +
    +
    +
    +
    + # + set(location[, key], value[, from_sync=false][, from_internal=false]) +
    +
    +
    +
    + +

    Sets the value at a location, this location must be registered

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + the location to set the data to + +
    • + + + + + +
    • + + key + + : + + (string) + + the key location if used + + (optional) +
    • + + + + + +
    • + + value + + : + + (any) + + the new value to set at the location, value may be reverted if there is a watch callback, cant be nil + +
    • + + + + + +
    • + + from_sync + + : + + (boolean) + + set this true to avoid an output to the sync file + + (default: false) +
    • + + + + + +
    • + + from_internal + + : + + (boolean) + + set this true to add one to the error stack offset + + (default: false) +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + true if it was successful +
    • +
    + + + + + + + + Usage: +
    -- Setting the data at a store location
    +Store.set(store_id_no_keys,'Hello, World!')
    +Store.set(store_id_with_keys,'key_one','Hello, World!')
    + + +
    +
    +
    +
    + # + update(location[, key][, update_callback]) +
    +
    +
    +
    + +

    Allows for updating a value based on the current value; only valid way to change tables in a store

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + the location to set the data to + +
    • + + + + + +
    • + + key + + : + + (string) + + the key location if required + + (optional) +
    • + + + + + +
    • + + update_callback + + : + + (function) + + the function called to update the value stored, rtn value to set new value + + (optional) +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Updating a value stored at a location
    +Store.update(store_id_no_keys,function(value)
    +    return value + 1
    +end)
    +Store.update(store_id_with_keys,'key_one',function(value)
    +    return value + 1
    +end)
    +
    -- Updating a table stored at a location
    +Store.update(store_id_no_keys,function(value)
    +    value.ctn = value.ctn + 1
    +end)
    +Store.update(store_id_with_keys,'key_one',function(value)
    +    value.ctn = value.ctn + 1
    +end)
    + + +
    +
    +
    +
    + # + update_all(location[, update_callback]) +
    +
    +
    +
    + +

    Allows for updating all values at a location based on the current value; only valid way to change tables in a store

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + the location to set the data to + +
    • + + + + + +
    • + + update_callback + + : + + (function) + + the function called to update the value stored + + (optional) +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Updating all values at a location
    +Store.update(store_id_with_keys,function(value)
    +    return value + 1
    +end)
    +
    -- Updating all tables at a location
    +Store.update(store_id_with_keys,function(value)
    +    value.ctn = value.ctn + 1
    +end)
    + + +
    +
    +
    +
    + # + clear(location[, key][, from_sync=false]) +
    +
    +
    +
    + +

    Sets the value at a location to nil, this location must be registered

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + the location to set the data to + +
    • + + + + + +
    • + + key + + : + + (string) + + the key location if used + + (optional) +
    • + + + + + +
    • + + from_sync + + : + + (boolean) + + set this true to avoid an output to the sync file + + (default: false) +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + true if it was successful +
    • +
    + + + + + + + + Usage: +
    -- Clear the data at a location
    +Store.clear(store_id_no_keys)
    +Store.clear(store_id_with_keys,'key_one')
    + + +
    +
    +
    +
    + # + get_keys(location) +
    +
    +
    +
    + +

    Gets all non nil keys at a location, keys can be added and removed during runtime +this is similar to Store.get but will always return a table even if it is empty

    +

    + + + Parameters: + +
      + + + + + +
    • + + location + + : + + (string) + + the location to get the keys of + +
    • + + +
    + + + + + Returns: +
      +
    • + (table) + a table containing all the keys names +
    • +
    + + + + + + + + Usage: +
    -- Get all keys at a store location
    +local keys = Store.get_keys(store_id_with_keys)
    + + +
    +
    +
    +
    # is_registered(location)
    @@ -527,6 +1146,9 @@ + Usage: +
    -- Check that a store is registered
    +local registerd = Store.is_registered(store_id)
    @@ -561,445 +1183,9 @@ - - - -
    -
    -
    - # - register([location][, synced][, callback]) -
    -
    -
    -
    - -

    Registers a new location with an update callback which is triggered when the value updates

    -

    - - - Parameters: - -
      - - - - - -
    • - - location - - : - - (string) - - string a unique that points to the data, string used rather than token to allow migration - - (optional) -
    • - - - - - -
    • - - synced - - : - - (boolean) - - when true will output changes to a file so it can be synced - - (optional) -
    • - - - - - -
    • - - callback - - : - - (function) - - when given the callback will be automatically registered to the update of the value - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (string) - the location that is being used -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - get(location[, child][, allow_unregistered=false]) -
    -
    -
    -
    - -

    Gets the value stored at a location, this location must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - location - - : - - (string) - - the location to get the data from - -
    • - - - - - -
    • - - child - - : - - (string) - - the child location if required - - (optional) -
    • - - - - - -
    • - - allow_unregistered - - : - - (boolean) - - when true no error is returned if the location is not registered - - (default: false) -
    • - - -
    - - - - - Returns: -
      -
    • - (any) - the data which was stored at the location -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - set(location[, child], value[, from_sync]) -
    -
    -
    -
    - -

    Sets the value at a location, this location must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - location - - : - - (string) - - the location to set the data to - -
    • - - - - - -
    • - - child - - : - - (string) - - the child location if required - - (optional) -
    • - - - - - -
    • - - value - - : - - (any) - - the new value to set at the location, value may be reverted if there is a watch callback, cant be nil - -
    • - - - - - -
    • - - from_sync - - : - - (boolean) - - set this true to avoid an output to the sync file - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if it was successful -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - clear(location[, child][, from_sync]) -
    -
    -
    -
    - -

    Sets the value at a location to nil, this location must be registered

    -

    - - - Parameters: - -
      - - - - - -
    • - - location - - : - - (string) - - the location to set the data to - -
    • - - - - - -
    • - - child - - : - - (string) - - the child location if required - - (optional) -
    • - - - - - -
    • - - from_sync - - : - - (boolean) - - set this true to avoid an output to the sync file - - (optional) -
    • - - -
    - - - - - Returns: -
      -
    • - (boolean) - true if it was successful -
    • -
    - - - - - - - - - -
    -
    -
    -
    - # - get_children(location) -
    -
    -
    -
    - -

    Gets all non nil children at a location, children can be added and removed during runtime - this is similar to Store.get but will always return a table even if it is empty

    -

    - - - Parameters: - -
      - - - - - -
    • - - location - - : - - (string) - - the location to get the children of - -
    • - - -
    - - - - - Returns: -
      -
    • - (table) - a table containing all the children names -
    • -
    - - - - - - - + Usage: +
    -- Get a new unique store id
    +local store_id = Store.uid_location()
    @@ -1018,7 +1204,7 @@ generated by LDoc diff --git a/docs/core/Sudo.html b/docs/core/Sudo.html index b57f5340..9f4c83f9 100644 --- a/docs/core/Sudo.html +++ b/docs/core/Sudo.html @@ -57,6 +57,7 @@ + @@ -544,7 +545,7 @@ generated by LDoc diff --git a/docs/core/Toolbar.html b/docs/core/Toolbar.html new file mode 100644 index 00000000..2db838da --- /dev/null +++ b/docs/core/Toolbar.html @@ -0,0 +1,1668 @@ + + + + + + + + Toolbar core + + + + + + + +
    +
    + + + + + + + +
    + + + + + + + + +

    Toolbar core

    +

    Core Module - Toolbar

    +

    + + + + + + + + + + + + + +

    Dependencies

    + + + + + + + + + + + + + + + + + + + + + + +
    expcore.gui
    expcore.roles
    utils.event
    utils.game
    mod-gui
    Gui.concept.button
    + + +

    Permissions

    + + + + + + + + + + + + +
    allowed(player, concept_name)Used to test if a player is allowed to use a button on the toolbar, if you are not using expcore.roles then change this function
    set_permission_alias(concept_name, alias)Use to add an alias for the allowed test, alias is what is tested for rather than the concept name
    + + +

    Buttons

    + + + + + + + + + + + + + + + + + + + + +
    add_button_concept(concept)Adds a concept to be drawn to the button area and allows it to be toggled with the toggle toolbar button
    update_buttons(player)Updates all the buttons for a player, this means hide and show buttons based on permissions
    get_visible_buttons(player)Returns an array of buttons names that the given player is able to see, returns none if toolbar hidden
    toolbar-buttonThe base element to be used with the toolbar, others can be used but this is recomented
    + + +

    Frames

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    add_frame_concept(concept)Adds a frame concept to the toolbar frame area, this will not add a button to the toolbar
    hide_frames(player)Hides all the frames for a player
    get_visible_frames(player)Gets an array of the names of all the visible frames for a player
    toolbar-frameThe base toolbar frame, others can be used but this is recomented
    Toolbar.frame:get_content(player)Gets the content area of the frame concept for this player, each player only has one area
    Toolbar.frame:toggle_visible_state(player)Toggles the visibilty of this concept for the given player
    Toolbar.frame:get_visible_state(player)Gets the current visibilty state of this conept for this player
    Toolbar.frame:update(player[, event])Triggers an update of the content within the concept for this player, uses on_update handlers
    Toolbar.frame:update_all([event])Triggers an update of the content with in this frame for all players
    + + +

    Other Elements

    + + + + + + + + + + + + + + + + +
    toolbarThe main toolbar element, draws, updates, and controls the other concepts
    toolbar-toggleButton which toggles the the visible state of all toolbar buttons, triggers on_button_update
    toolbar-clearButton which hides all visible toolbar frames, triggers on_hide_frames
    + + +
    + + +

    Dependencies

    +
    +
    +
    +
    + # + expcore.gui +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + # + expcore.roles +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + # + utils.event +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + # + utils.game +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + # + mod-gui +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + # + Gui.concept.button +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    +
    +

    Permissions

    +
    +
    +
    +
    + # + allowed(player, concept_name) +
    +
    +
    +
    + +

    Used to test if a player is allowed to use a button on the toolbar, if you are not using expcore.roles then change this function

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player you want ot test is allowed to use this button + +
    • + + + + + +
    • + + concept_name + + : + + (string) + + the name of the button concept that you want to see if the player is allowed to use + +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + true if the player is allowed to use it +
    • +
    + + + + + + + + Usage: +
    -- Test if a player can use 'test-player-list'
    +local allowed = Toolbar.allowed(game.player,'test-player-list')
    + + +
    +
    +
    +
    + # + set_permission_alias(concept_name, alias) +
    +
    +
    +
    + +

    Use to add an alias for the allowed test, alias is what is tested for rather than the concept name

    +

    + + + Parameters: + +
      + + + + + +
    • + + concept_name + + : + + (string) + + the name of the concept that will point to this alias + +
    • + + + + + +
    • + + alias + + : + + (string) + + the permission string that will be tested when this concept is used with Toolbar.allowed + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Adding an alias for the 'test-player-list' concept
    +Toolbar.set_permission_alias('test-player-list','gui/player-list')
    + + +
    +
    +

    Buttons

    +
    +
    +
    +
    + # + add_button_concept(concept) +
    +
    +
    +
    + +

    Adds a concept to be drawn to the button area and allows it to be toggled with the toggle toolbar button

    +

    + + + Parameters: + +
      + + + + + +
    • + + concept + + : + + (table) + + the gui concept that you want to add to the button area + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Adding a basic button to the toolbar
    +local new_button =
    +Gui.new_concept('button')
    +:set_caption('Click Me')
    +:on_click(function(event)
    +    event.player.print('You Clicked Me!!')
    +end)
    +
    +Toolbar.add_button_concept(new_button)
    + + +
    +
    +
    +
    + # + update_buttons(player) +
    +
    +
    +
    + +

    Updates all the buttons for a player, this means hide and show buttons based on permissions

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player to update the toolbar buttons for + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Updating your toolbar
    +Toolbar.update_buttons(player)
    + + +
    +
    +
    +
    + # + get_visible_buttons(player) +
    +
    +
    +
    + +

    Returns an array of buttons names that the given player is able to see, returns none if toolbar hidden

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player you want to get the visible buttons of + +
    • + + +
    + + + + + Returns: +
      +
    • + (table) + an array of names of the visible buttons +
    • +
    + + + + + + + + Usage: +
    -- Get a list of all your visible buttons
    +Toolbar.get_visible_buttons(game.player)
    + + +
    +
    +
    +
    + # + toolbar-button +
    +
    +
    +
    + +

    The base element to be used with the toolbar, others can be used but this is recomented

    +

    + + + Properties / Events: + +
      + + + + + +
    • + + permission_alias + + : + + (string) + + the alias used with Toolbar.allowed + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Adding a basic button to the toolbar, note no need to call Toolbar.add_button_concept
    +Gui.new_concept('toolbar-button')
    +:set_caption('Click Me')
    +:on_click(function(event)
    +    event.player.print('You Clicked Me!!')
    +end)
    + + +
    +
    +

    Frames

    +
    +
    +
    +
    + # + add_frame_concept(concept) +
    +
    +
    +
    + +

    Adds a frame concept to the toolbar frame area, this will not add a button to the toolbar

    +

    + + + Parameters: + +
      + + + + + +
    • + + concept + + : + + (table) + + the gui concept that you want to add to the toolbar frame area + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Adding a basic frame to the frame area
    +local new_frame =
    +Gui.new_concept('frame')
    +:set_title('Test')
    +
    +Toolbar.add_frame_concept(new_frame)
    + + +
    +
    +
    +
    + # + hide_frames(player) +
    +
    +
    +
    + +

    Hides all the frames for a player

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player to hide the frames for + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Hiding all your frames
    +Toolbar.hide_frames(game.player)
    + + +
    +
    +
    +
    + # + get_visible_frames(player) +
    +
    +
    +
    + +

    Gets an array of the names of all the visible frames for a player

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to get the visible frames of + +
    • + + +
    + + + + + Returns: +
      +
    • + (table) + an array of names of the visible frames for the given player +
    • +
    + + + + + + + + Usage: +
    -- Get all your visible frames
    +Toolbar.get_visible_frames(game.player)
    + + +
    +
    +
    +
    + # + toolbar-frame +
    +
    +
    +
    + +

    The base toolbar frame, others can be used but this is recomented

    +

    + + + Properties / Events: + +
      + + + + + +
    • + + on_update + + : + + + fired when the frame is to have its content updated + +
    • + + + + + +
    • + + open_by_default + + : + + (boolean) + + weather the frame should be open when a player first joins + +
    • + + + + + +
    • + + use_container + + : + + (boolean) + + true by default and will place a container inside the frame for content + +
    • + + + + + +
    • + + direction + + : + + (string) + + the direction that the items in the frame are added + +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Adding a basic player list
    +local player_list =
    +Gui.new_concept('toolbar-frame')
    +:set_permission_alias('player_list')
    +:set_caption('Player List')
    +:toggle_with_click()
    +
    +:define_draw(function(properties,parent,element)
    +    local list_area =
    +    element.add{
    +        name = 'scroll',
    +        type = 'scroll-pane',
    +        direction = 'vertical',
    +        horizontal_scroll_policy = 'never',
    +        vertical_scroll_policy = 'auto-and-reserve-space'
    +    }
    +    Gui.set_padding(list_area,1,1,2,2)
    +    list_area.style.horizontally_stretchable = true
    +    list_area.style.maximal_height = 200
    +
    +    for _,player in pairs(game.connected_players) do
    +        list_area.add{
    +            type='label',
    +            caption=player.name
    +        }
    +    end
    +end)
    +
    +:on_update(function(event)
    +    local list_area = event.element.scroll
    +    list_area.clear()
    +
    +    for _,player in pairs(game.connected_players) do
    +        list_area.add{
    +            type='label',
    +            caption=player.name
    +        }
    +    end
    +end)
    + + +
    +
    +
    +
    + # + Toolbar.frame:get_content(player) +
    +
    +
    +
    + +

    Gets the content area of the frame concept for this player, each player only has one area

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to get the frame content for + +
    • + + +
    + + + + + Returns: +
      +
    • + (LuaGuiElement) + the content area of this concept for this player +
    • +
    + + + + + + + + Usage: +
    -- Get the content area of a concept
    +local frame = player_list:get_content(game.player)
    + + +
    +
    +
    +
    + # + Toolbar.frame:toggle_visible_state(player) +
    +
    +
    +
    + +

    Toggles the visibilty of this concept for the given player

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want to toggle the frame for + +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + the new state of the visibilty of this concept for the player +
    • +
    + + + + + + + + Usage: +
    -- Toggle the frame for your self
    +player_list:toggle_visible_state(game.player)
    + + +
    +
    +
    +
    + # + Toolbar.frame:get_visible_state(player) +
    +
    +
    +
    + +

    Gets the current visibilty state of this conept for this player

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player that you want the visibilty state for + +
    • + + +
    + + + + + Returns: +
      +
    • + (boolean) + the current visiblity state of this concept to the player +
    • +
    + + + + + + + + Usage: +
    -- Getting the current visiblity state
    + + +
    +
    +
    +
    + # + Toolbar.frame:update(player[, event]) +
    +
    +
    +
    + +

    Triggers an update of the content within the concept for this player, uses on_update handlers

    +

    + + + Parameters: + +
      + + + + + +
    • + + player + + : + + (LuaPlayer) + + the player to update the concept content for + +
    • + + + + + +
    • + + event + + : + + (table) + + the event data that you want to pass to the update handlers + + (optional) +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Updating the frame for your player
    +player_list:update(game.player)
    + + +
    +
    +
    +
    + # + Toolbar.frame:update_all([event]) +
    +
    +
    +
    + +

    Triggers an update of the content with in this frame for all players

    +

    + + + Parameters: + +
      + + + + + +
    • + + event + + : + + (table) + + the event data that you want to pass to the update handlers + + (optional) +
    • + + +
    + + + + + + + + + + + + Usage: +
    -- Update the grame for all players
    +player_list:update_all()
    + + +
    +
    +

    Other Elements

    +
    +
    +
    +
    + # + toolbar +
    +
    +
    +
    + +

    The main toolbar element, draws, updates, and controls the other concepts

    +

    + + + Properties / Events: + +
      + + + + + +
    • + + on_button_update + + : + + + fired when the buttons are updated for a player + +
    • + + + + + +
    • + + on_hide_frames + + : + + + fired when the frames are hidden for a player + +
    • + + +
    + + + + + + + + + + + + + +
    +
    +
    +
    + # + toolbar-toggle +
    +
    +
    +
    + +

    Button which toggles the the visible state of all toolbar buttons, triggers on_button_update

    +

    + + + + + + + + + + + + + + +
    +
    +
    +
    + # + toolbar-clear +
    +
    +
    +
    + +

    Button which hides all visible toolbar frames, triggers on_hide_frames

    +

    + + + + + + + + + + + + + + +
    +
    + + + +
    +
    +
    + + + + diff --git a/docs/guis/Player-List.html b/docs/guis/Player-List.html index 15f04345..e80e3022 100644 --- a/docs/guis/Player-List.html +++ b/docs/guis/Player-List.html @@ -69,6 +69,7 @@ + @@ -626,7 +627,7 @@ generated by LDoc diff --git a/docs/guis/Rocket-Info.html b/docs/guis/Rocket-Info.html index a0c8e321..65b15a82 100644 --- a/docs/guis/Rocket-Info.html +++ b/docs/guis/Rocket-Info.html @@ -69,6 +69,7 @@ + @@ -629,7 +630,7 @@ generated by LDoc diff --git a/docs/guis/Science-Info.html b/docs/guis/Science-Info.html index 46a7c6ba..567731c0 100644 --- a/docs/guis/Science-Info.html +++ b/docs/guis/Science-Info.html @@ -69,6 +69,7 @@ + @@ -449,7 +450,7 @@ generated by LDoc diff --git a/docs/guis/Task-List.html b/docs/guis/Task-List.html index 044ce929..28d1ef22 100644 --- a/docs/guis/Task-List.html +++ b/docs/guis/Task-List.html @@ -69,6 +69,7 @@ + @@ -632,7 +633,7 @@ generated by LDoc diff --git a/docs/guis/Warps-List.html b/docs/guis/Warps-List.html index 70ad4fae..91e2640e 100644 --- a/docs/guis/Warps-List.html +++ b/docs/guis/Warps-List.html @@ -69,6 +69,7 @@ + @@ -837,7 +838,7 @@ generated by LDoc diff --git a/docs/index.html b/docs/index.html index 8d881fce..a2c82dd5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -56,11 +56,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 + Core Module - Gui Permissions-Groups @@ -82,6 +78,10 @@ Core Module - Sudo - An extention of task and token to allow a single require to register and run functions bypassing all permissions. + + Toolbar + Core Module - Toolbar +

    Addons

    @@ -514,7 +514,7 @@ see ./expcore/commands.lua for more detailsgenerated by LDoc diff --git a/docs/modules/Gui.html b/docs/modules/Gui.html index 493c008e..7f2d9a40 100644 --- a/docs/modules/Gui.html +++ b/docs/modules/Gui.html @@ -41,8 +41,7 @@ @@ -52,20 +51,6 @@ @@ -237,9 +221,7 @@

    Gui module

    -

    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

    +

    Core Module - Gui

    @@ -254,71 +236,17 @@
    -

    Dependencies

    +

    Functions

    - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    expcore.gui.coreon_custom_event(handler)Adds a custom event handler, replace with the name of the event
    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
    - - -

    Test

    - - - - - - - - - - - - - - - - - + +
    expcore.gui
    expcore.common
    resources.color_presets
    utils.event
    expcore.storeset_custom_property(value)Sets a new value for a property, triggers setter method if provided, replace with property name
    @@ -327,23 +255,56 @@
    -

    Dependencies

    +

    Functions

    - # - expcore.gui.core + # + on_custom_event(handler)
    +

    Adds a custom event handler, replace with the name of the event

    +

    + Parameters: + +
      + + + + + +
    • + + handler + + : + + (function) + + the function which will recive the event + +
    • + + +
    + + Returns: +
      +
    • + (GuiConcept) + to allow chaing of functions +[[@usage +
    • +
    @@ -357,421 +318,51 @@
    - # - 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 -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -

    Test

    -
    -
    -
    -
    - # - expcore.gui -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.common -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - resources.color_presets -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - utils.event -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    -
    -
    -
    - # - expcore.store + # + set_custom_property(value)
    +

    Sets a new value for a property, triggers setter method if provided, replace with property name

    +

    + Parameters: + +
      + + + + + +
    • + + value + + : + + (any) + + the value that you want to set for this property + +
    • + + +
    + + Returns: +
      +
    • + (GuiConcept) + to allow chaing of functions +[[@usage +
    • +
    @@ -797,7 +388,7 @@ generated by LDoc
    diff --git a/docs/modules/control.html b/docs/modules/control.html index 2e7d23d6..4fb5d84e 100644 --- a/docs/modules/control.html +++ b/docs/modules/control.html @@ -76,6 +76,7 @@ + @@ -351,7 +352,7 @@ generated by LDoc diff --git a/docs/modules/expcore.gui.html b/docs/modules/expcore.gui.html index 580de83b..78739a7f 100644 --- a/docs/modules/expcore.gui.html +++ b/docs/modules/expcore.gui.html @@ -37,35 +37,13 @@ - @@ -419,7 +420,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 415f1982..7087a571 100644 --- a/docs/modules/utils.core.html +++ b/docs/modules/utils.core.html @@ -78,6 +78,7 @@ + @@ -1164,7 +1165,7 @@ generated by LDoc diff --git a/docs/modules/utils.debug.html b/docs/modules/utils.debug.html index 126749ed..1d9e7fdc 100644 --- a/docs/modules/utils.debug.html +++ b/docs/modules/utils.debug.html @@ -76,6 +76,7 @@ + @@ -241,7 +242,7 @@ - Debug.print(message, stack_traceback) + Debug.print(message, trace_levels) Shows the given message if debug is enabled. @@ -280,7 +281,7 @@
    # - Debug.print(message, stack_traceback) + Debug.print(message, trace_levels)
    @@ -315,7 +316,7 @@
  • - stack_traceback + trace_levels : @@ -654,7 +655,7 @@ generated by LDoc diff --git a/docs/modules/utils.dump_env.html b/docs/modules/utils.dump_env.html index a4994d60..c4da3636 100644 --- a/docs/modules/utils.dump_env.html +++ b/docs/modules/utils.dump_env.html @@ -76,6 +76,7 @@
  • + @@ -323,7 +324,7 @@ generated by LDoc diff --git a/docs/modules/utils.event.html b/docs/modules/utils.event.html index 7043beae..bc1f5698 100644 --- a/docs/modules/utils.event.html +++ b/docs/modules/utils.event.html @@ -77,6 +77,7 @@ + @@ -1292,7 +1293,7 @@ generated by LDoc diff --git a/docs/modules/utils.event_core.html b/docs/modules/utils.event_core.html index 2fc2bf78..b53537ea 100644 --- a/docs/modules/utils.event_core.html +++ b/docs/modules/utils.event_core.html @@ -76,6 +76,7 @@ + @@ -434,7 +435,7 @@ generated by LDoc diff --git a/docs/modules/utils.math.html b/docs/modules/utils.math.html index 3f4d0920..b74b9490 100644 --- a/docs/modules/utils.math.html +++ b/docs/modules/utils.math.html @@ -76,6 +76,7 @@ + @@ -241,7 +242,7 @@ - calculate_y_intercept(x, slope) + calculate_y_intercept(x, y, slope) Calculates the y-intercept of a line @@ -257,7 +258,7 @@
    # - calculate_y_intercept(x, slope) + calculate_y_intercept(x, y, slope)
    @@ -282,7 +283,22 @@ : - , y numbers - coordinates of point on line + number - coordinates of point on line + + + + + + + +
  • + + y + + : + + + number - coordinates of point on line
  • @@ -338,7 +354,7 @@ generated by LDoc diff --git a/docs/modules/utils.recipe_locker.html b/docs/modules/utils.recipe_locker.html index 45474def..59449178 100644 --- a/docs/modules/utils.recipe_locker.html +++ b/docs/modules/utils.recipe_locker.html @@ -77,6 +77,7 @@ + @@ -441,7 +442,7 @@ generated by LDoc diff --git a/docs/modules/utils.state_machine.html b/docs/modules/utils.state_machine.html index b15d99e6..9a60f448 100644 --- a/docs/modules/utils.state_machine.html +++ b/docs/modules/utils.state_machine.html @@ -77,6 +77,7 @@ + @@ -276,7 +277,7 @@ NOTICE: This function will invoke an error if called after init. - Module.register_transition_callback(self, state, state, callback) + Module.register_transition_callback(self, old, new, callback) Register a handler that will be invoked by StateMachine.transition You may register multiple handlers for the same transition NOTICE: This function will invoke an error if called after init. @@ -590,7 +591,7 @@
    # - Module.register_transition_callback(self, state, state, callback) + Module.register_transition_callback(self, old, new, callback)
    @@ -627,12 +628,12 @@
  • - state + old : - number/string entering state + number/string exiting state
  • @@ -642,7 +643,7 @@
  • - state + new : @@ -752,7 +753,7 @@ generated by LDoc diff --git a/docs/modules/utils.table.html b/docs/modules/utils.table.html index 499ad887..eaec6291 100644 --- a/docs/modules/utils.table.html +++ b/docs/modules/utils.table.html @@ -78,6 +78,7 @@
  • + @@ -289,12 +290,12 @@ because this uses math.random, it cannot be used outside of events - get_random_weighted(weight_table, item_index, weight_index) + get_random_weighted(weighted_table, item_index, weight_index) Chooses a random entry from a weighted table because this uses math.random, it cannot be used outside of events - shuffle_table(t) + shuffle_table(t, rng) Creates a fisher-yates shuffle of a sequential number-indexed table because this uses math.random, it cannot be used outside of events if no rng is supplied from: http://www.sdknews.com/cross-platform/corona/tutorial-how-to-shuffle-table-items @@ -551,6 +552,12 @@ + Returns: +
      +
    • + the index of the element or nil +
    • +
    @@ -615,6 +622,12 @@ + Returns: +
      +
    • + the index of the element or nil +
    • +
    @@ -679,6 +692,12 @@ + Returns: +
      +
    • + indicating success +
    • +
    @@ -743,6 +762,12 @@ + Returns: +
      +
    • + indicating success +
    • +
    @@ -907,7 +932,7 @@
    # - get_random_weighted(weight_table, item_index, weight_index) + get_random_weighted(weighted_table, item_index, weight_index)
    @@ -928,7 +953,7 @@
  • - weight_table + weighted_table : @@ -983,9 +1008,6 @@ - See also: -
      -
    @@ -996,7 +1018,7 @@
    # - shuffle_table(t) + shuffle_table(t, rng)
    @@ -1028,6 +1050,21 @@
  • + + + +
  • + + rng + + : + + + to provide random numbers + +
  • + + @@ -1382,7 +1419,7 @@ generated by LDoc diff --git a/docs/modules/utils.task.html b/docs/modules/utils.task.html index e84aa88a..e853536f 100644 --- a/docs/modules/utils.task.html +++ b/docs/modules/utils.task.html @@ -77,6 +77,7 @@ + @@ -651,7 +652,7 @@ generated by LDoc diff --git a/docs/modules/utils.timestamp.html b/docs/modules/utils.timestamp.html index 201f2509..97e2409e 100644 --- a/docs/modules/utils.timestamp.html +++ b/docs/modules/utils.timestamp.html @@ -76,6 +76,7 @@ + @@ -442,7 +443,7 @@ generated by LDoc diff --git a/docs/topics/license.html b/docs/topics/license.html index 7843e890..219ecba4 100644 --- a/docs/topics/license.html +++ b/docs/topics/license.html @@ -57,6 +57,7 @@ + @@ -789,7 +790,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 31de4f66..24b2d167 100644 --- a/docs/topics/readme.md.html +++ b/docs/topics/readme.md.html @@ -57,6 +57,7 @@ + @@ -239,7 +240,7 @@

    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).

    ## 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]. 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. @@ -248,7 +249,8 @@

    ## Releases

    | Scenario Version* | Version Name | Factorio Version** | |---|---|---| -| [v5.7][s5.8] | Home and Chat Bot | [v0.17.47][f0.17.49] | +| [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] | | [v5.6][s5.6] | Information Guis | [v0.17.44][f0.17.44] | | [v5.5][s5.5] | Gui System | [v0.17.43][f0.17.43] | @@ -264,7 +266,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.8]: https://github.com/explosivegaming/scenario/releases/tag/5.8.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 [s5.5]: https://github.com/explosivegaming/scenario/releases/tag/5.5.0 @@ -278,7 +281,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.49]: https://wiki.factorio.com/Version_history/0.17.0#0.17.49 +

    [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 [f0.17.43]: https://wiki.factorio.com/Version_history/0.17.0#0.17.43 @@ -293,7 +297,8 @@ [f0.14]: https://wiki.factorio.com/Version_history/0.14.0

    ## License

    The Explosive Gaming codebase is licensed under the [GNU General Public License v3.0](LICENSE) -

    [issues]: https://github.com/explosivegaming/scenario/issues/new/choose +

    [docs]: https://explosivegaming.github.io/scenario/ +[issues]: https://github.com/explosivegaming/scenario/issues/new/choose [website]: https://explosivegaming.nl [discord]: https://discord.explosivegaming.nl [wiki]: https://wiki.explosivegaming.nl @@ -329,7 +334,7 @@ generated by LDoc

    diff --git a/expcore/common.lua b/expcore/common.lua index 19cd711b..1d9ebef0 100644 --- a/expcore/common.lua +++ b/expcore/common.lua @@ -611,4 +611,93 @@ function Common.format_chat_player_name(player,raw_string) end end +--- Returns a desync safe file path for the current file +-- @tparam[opt=0] number offset the offset in the stack to get, 0 is current file +-- @treturn string the file path +function Common.get_file_path(offset) + offset = offset or 0 + return debug.getinfo(offset+2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) +end + +--[[-- Much faster method for inserting items into an array +@tparam table tbl the table that will have the values added to it +@tparam[opt] number start_index the index at which values will be added, nil means end of the array +@tparam table values the new values that will be added to the table +@treturn table the table that was passed as the first argument +@usage-- Adding 1000 values into the middle of the array +local tbl = {} +local values = {} +for i = 1,1000 do tbl[i] = i values[i] = i end +Common.array_insert(tbl,500,values) -- around 0.4ms +]] +function Common.array_insert(tbl,start_index,values) + if not values then + values = start_index + start_index = nil + end + + if start_index then + local starting_length = #tbl + local adding_length = #values + local move_to = start_index+adding_length+1 + for offset = starting_length-start_index, 0, -1 do + tbl[move_to+offset] = tbl[starting_length+offset] + end + start_index = start_index-1 + else + start_index = #tbl + end + + for offset, item in ipairs(values) do + tbl[start_index+offset] = item + end + + return tbl +end + +--[[-- Much faster method for inserting keys into a table +@tparam table tbl the table that will have keys added to it +@tparam[opt] number start_index the index at which values will be added, nil means end of the array, numbered indexs only +@tparam table tbl2 the table that may contain both string and numbered keys +@treturn table the table passed as the first argument +@usage-- Merging two tables +local tbl = {} +local tbl2 = {} +for i = 1,100 do tbl[i] = i tbl['_'..i] = i tbl2[i] = i tbl2['__'..i] = i end +Common.table_insert(tbl,50,tbl2) +]] +function Common.table_insert(tbl,start_index,tbl2) + if not tbl2 then + tbl2 = start_index + start_index = nil + end + + Common.array_insert(tbl,start_index,tbl2) + for key, value in pairs(tbl2) do + if not tonumber(key) then + tbl[key] = value + end + end + + return tbl +end + +--[[-- Used to resolve a value that could also be a function returning that value +@tparam any value the value which you want to test is not nil and if it is a function then call the function +@treturn any the value given or returned by value if it is a function +@usage-- Default value handling +-- if default value is not a function then it is returned +-- if it is a function then it is called with the first argument being self +local value = Common.resolve_value(self.defaut_value,self) +]] +function Common.resolve_value(value,...) + if value then + if type(value) == 'function' then + return value(...) + else + return value + end + end +end + return Common \ No newline at end of file diff --git a/expcore/gui.lua b/expcore/gui.lua index 6cf395f1..18584b47 100644 --- a/expcore/gui.lua +++ b/expcore/gui.lua @@ -1,284 +1,71 @@ --[[-- Core Module - Gui - - This file is used to require all the different elements of the gui module - - each module has an outline here but for more details see their separate files in ./gui - - please read the files for more documentation that cant be shown here - - please note there is a rework planned but not started @core Gui @alias Gui + +@usage-- Making the base button concept +local button = +Gui.new_concept() -- Make a new empty concept +:save_as('button') -- Save it as Gui.concepts.button so it can be used in other files +:new_event('on_click',defines.events.on_gui_click) -- Add an on click event for this concept +:new_property('tooltip') -- Add a property with the default setter method called tooltip +:new_property('caption',function(properties,value) -- Add a property with a custom setter method called caption + properties.caption = value + properties.sprite = nil + properties.type = 'button' +end) +:new_property('sprite',function(properties,value) -- Add a property with a custom setter method called sprite + properties.image = value + properties.caption = nil + properties.type = 'sprite-button' +end) +:define_draw(function(properties,parent,element) -- Add the draw function to create the element from the concept + -- Properties will include all the information that you need to draw the element + -- Parent is the parent element for the element, this may have been altered by previous draw functions + -- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function + if properties.type == 'button' then + element = parent.add{ + type = properties.type, + name = properties.name, + caption = properties.caption, + tooltip = properties.tooltip + } + + else + element = parent.add{ + type = properties.type, + name = properties.name, + sprite = properties.sprite, + tooltip = properties.tooltip + } + + end + + -- If you return element or parent then their values will be updated for the next draw function in the chain + -- It is best practice to always return the values if you have made any changes to them + return element, parent +end) + +@usage-- Making a new button which has a custom style +local custom_button = +Gui.new_concept('button') -- We can use button here since we used save as on the concept +-- button:clone() -- If we had not used save as then this is how we would use it as a base +:set_caption('Custom Button') -- Set the caption of the concept, this is possible as we added caption as a property +:set_tooltip('Only admins can press this button') -- Set the tooltip of the concept, this is possible as we added tooltip as a property +:on_click(function(event) -- Register a handler to the click event we added with new event + if not event.player.admin then + event.player.print('You must be admin to use this button') + end +end) +:new_event('on_admin_clicked',defines.events.on_gui_click,function(event) -- Add a click event which has a filter function + return event.player.admin -- Check if the player is admin +end) +:on_admin_clicked(function(event) -- Register a handler to the admin click event we have just created + -- The admin click event is only an example, because of how sinmple the filter is we could have just used an if else statement + game.print(event.player.name..' pressed my admin button') +end) + +@usage-- Drawing a concept +custom_button:draw(game.player.gui.left) ]] -local Gui = require 'expcore.gui.core' --- @dep expcore.gui.core - ---[[ - Core - - Gui.new_define(prototype) --- Used internally to create new element defines from a class prototype - Gui.draw(name,element) --- Draws a copy of the element define to the parent element, see draw_to - - Gui.categorize_by_player(element) --- A categorize function to be used with add_store, each player has their own value - Gui.categorize_by_force(element) --- A categorize function to be used with add_store, each force has its own value - Gui.categorize_by_surface(element) --- A categorize function to be used with add_store, each surface has its own value - - Gui.toggle_enabled(element) --- Will toggle the enabled state of an element - Gui.toggle_visible(element) --- Will toggle the visibility of an element - Gui.set_padding(element,up,down,left,right) --- Sets the padding for a gui element - Gui.set_padding_style(style,up,down,left,right) --- Sets the padding for a gui style - Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into - Gui.destroy_if_valid(element) --- Destroys an element but tests for it being present and valid first - Gui.create_scroll_table(element,table_size,maximal_height,name) --- Creates a scroll area with a table inside, table can be any size - Gui.create_header(element,caption,tooltip,right_align,name) --- Creates a header section with a label and button area - - Prototype Constructor - - Constructor.event(event_name) --- Creates a new function to add functions to an event handler - Constructor.extend(new_prototype) --- Extents a prototype with the base functions of all gui prototypes, no metatables - Constructor.store(sync,callback) --- Creates a new function which adds a store to a gui define - Constructor.setter(value_type,key,second_key) --- Creates a setter function that checks the type when a value is set - - Base Prototype - - Prototype:uid() --- Gets the uid for the element define - Prototype:debug_name(value) --- Sets a debug alias for the define - Prototype:set_caption(value) --- Sets the caption for the element define - Prototype:set_tooltip(value) --- Sets the tooltip for the element define - Prototype:set_style(style,callback) --- Sets the style for the element define - Prototype:set_embedded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function - - Prototype:set_pre_authenticator --- Sets an authenticator that blocks the draw function if check fails - Prototype:set_post_authenticator --- Sets an authenticator that disables the element if check fails - - Prototype:raise_event(event_name,...) --- Raises a custom event for this define, any number of params can be given - Prototype:draw_to(element,...) --- The main function for defines, when called will draw an instance of this define to the given element - - Prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used - Prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used - Prototype:clear_store(category) --- Sets the value in this elements store to nil, category needed if categorize function used -]] - -local Instances = require 'expcore.gui.instances' --- @dep expcore.gui.instances -Gui.new_instance_group = Instances.registers -Gui.get_instances = Instances.get_elements -Gui.add_instance = Instances.get_elements -Gui.update_instances = Instances.apply_to_elements -Gui.classes.instances = Instances ---[[ - Instances.has_categories(name) --- Returns if a instance group has a categorise function; must be registered - Instances.is_registered(name) --- Returns if the given name is a registered instance group - Instances.register(name,categorise) --- Registers the name of an instance group to allow for storing element instances - - Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered - Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered - Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid - - Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered - Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered -]] - -local Button = require 'expcore.gui.elements.buttons' --- @dep expcore.gui.elements.buttons -Gui.new_button = Button.new_button -Gui.classes.button = Button ---[[ - Button.new_button(name) --- Creates a new button element define - - Button._prototype:on_click(player,element) --- Registers a handler for when the button is clicked - Button._prototype:on_left_click(player,element) --- Registers a handler for when the button is clicked with the left mouse button - Button._prototype:on_right_click(player,element) --- Registers a handler for when the button is clicked with the right mouse button - - Button._prototype:set_sprites(sprite,hovered_sprite,clicked_sprite) --- Adds sprites to a button making it a sprite button - Button._prototype:set_click_filter(filter,...) --- Adds a click / mouse button filter to the button - Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button -]] - -local Checkbox = require 'expcore.gui.elements.checkbox' --- @dep expcore.gui.elements.checkbox -Gui.new_checkbox = Checkbox.new_checkbox -Gui.new_radiobutton = Checkbox.new_radiobutton -Gui.new_radiobutton_option_set = Checkbox.new_option_set -Gui.draw_option_set = Checkbox.draw_option_set -Gui.classes.checkbox = Checkbox ---[[ - Checkbox.new_checkbox(name) --- Creates a new checkbox element define - Checkbox._prototype_checkbox:on_element_update(callback) --- Registers a handler for when an element instance updates - Checkbox._prototype_checkbox:on_store_update(callback) --- Registers a handler for when the stored value updates - - Checkbox.new_radiobutton(name) --- Creates a new radiobutton element define - Checkbox._prototype_radiobutton:on_element_update(callback) --- Registers a handler for when an element instance updates - Checkbox._prototype_radiobutton:on_store_update(callback) --- Registers a handler for when the stored value updates - Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) --- Adds this radiobutton to be an option in the given option set (only one can be true at a time) - - Checkbox.new_option_set(name,callback,categorize) --- Registers a new option set that can be linked to radiobuttons (only one can be true at a time) - Checkbox.draw_option_set(name,element) --- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work) - - Checkbox.reset_radiobutton(element,exclude,recursive) --- Sets all radiobuttons in a element to false (unless excluded) and can act recursively -]] - -local Dropdown = require 'expcore.gui.elements.dropdown' --- @dep expcore.gui.elements.dropdown -Gui.new_dropdown = Dropdown.new_dropdown -Gui.new_list_box = Dropdown.new_list_box -Gui.classes.dropdown = Dropdown ---[[ - Dropdown.new_dropdown(name) --- Creates a new dropdown element define - Dropdown.new_list_box(name) --- Creates a new list box element define - - Dropdown._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - Dropdown._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - Dropdown._prototype:new_static_options(options,...) --- Adds new static options to the dropdown which will trigger the general callback - Dropdown._prototype:new_dynamic_options(callback) --- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options) - Dropdown._prototype:add_option_callback(option,callback) --- Adds a case specific callback which will only run when that option is selected (general case still triggered) - - Dropdown.select_value(element,value) --- Selects the option from a dropdown or list box given the value rather than key - Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index -]] - -local Slider = require 'expcore.gui.elements.slider' --- @dep expcore.gui.elements.slider -Gui.new_slider = Slider.new_slider -Gui.classes.slider = Slider ---[[ - Slider.new_slider(name) --- Creates a new slider element define - - Slider._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - Slider._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - Slider._prototype:set_range(min,max) --- Sets the range of a slider, if not used will use default values for a slider - Slider._prototype:draw_label(element) --- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player - Slider._prototype:enable_auto_draw_label(state) --- Enables auto draw of the label, the label will share the same parent element as the slider -]] - -local Text = require 'expcore.gui.elements.text' --- @dep expcore.gui.elements.text -Gui.new_text_filed = Text.new_text_field -Gui.new_text_box = Text.new_text_box -Gui.classes.text = Text ---[[ - Text.new_text_field(name) --- Creates a new text field element define - Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates - Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates - - Text.new_text_box(name) --- Creates a new text box element define - Text._prototype_field:on_element_update(callback) --- Registers a handler for when an element instance updates - Text._prototype_field:on_store_update(callback) --- Registers a handler for when the stored value updates - Text._prototype_box:set_selectable(state) --- Sets the text box to be selectable - Text._prototype_box:set_word_wrap(state) --- Sets the text box to have word wrap - Text._prototype_box:set_read_only(state) --- Sets the text box to be read only -]] - -local ElemButton = require 'expcore.gui.elements.elem-button' --- @dep expcore.gui.elements.elem-button -Gui.new_elem_button = ElemButton.new_elem_button -Gui.classes.elem_button = ElemButton ---[[ - ElemButton.new_elem_button(name) --- Creates a new elem button element define - - ElemButton._prototype:on_element_update(callback) --- Registers a handler for when an element instance updates - ElemButton._prototype:on_store_update(callback) --- Registers a handler for when the stored value updates - - ElemButton._prototype:set_type(type) --- Sets the type of the elem button, the type is required so this must be called at least once - ElemButton._prototype:set_default(value) --- Sets the default value for the elem button, this may be a function or a string -]] - -local ProgressBar = require 'expcore.gui.elements.progress-bar' --- @dep expcore.gui.elements.progress-bar -Gui.new_progressbar = ProgressBar.new_progressbar -Gui.set_progressbar_maximum = ProgressBar.set_maximum -Gui.increment_progressbar = ProgressBar.increment -Gui.decrement_progressbar = ProgressBar.decrement -Gui.classes.progressbar = ProgressBar ---[[ - ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar - ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented - ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decreased - - ProgressBar.new_progressbar(name) --- Creates a new progressbar element define - ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar - ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0 - ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar - ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store - ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar - ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store - ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store - ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0 - - ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element completes (hits 0 or 1) - ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1) - ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggers, can filter which elements are incremented - ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggers, can filter which elements are decremented -]] - -local Toolbar = require 'expcore.gui.concepts.toolbar' --- @dep expcore.gui.concepts.toolbar -Gui.new_toolbar_button = Toolbar.new_button -Gui.add_button_to_toolbar = Toolbar.add_button -Gui.update_toolbar = Toolbar.update -Gui.classes.toolbar = Toolbar ---[[ - Toolbar.new_button(name) --- Adds a new button to the toolbar - Toolbar.add_button(button) --- Adds an existing buttton to the toolbar - Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return -]] - -local LeftFrames = require 'expcore.gui.concepts.left' --- @dep expcore.gui.concepts.left -Gui.get_left_frame_flow = LeftFrames.get_flow -Gui.toggle_left_frame = LeftFrames.toggle_frame -Gui.new_left_frame = LeftFrames.new_frame -Gui.classes.left_frames = LeftFrames ---[[ - LeftFrames.get_flow(player) --- Gets the left frame flow for a player - LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name - LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button - LeftFrames.toggle_frame(name,player,state) --- Toggles the visibility of a left frame, or sets its visibility state - - LeftFrames.new_frame(permission_name) --- Creates a new left frame define - LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean - LeftFrames._prototype:set_direction(direction) --- Sets the direction of the frame, either vertical or horizontal - LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow - LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible - LeftFrames._prototype:toggle(player) --- Toggles the visibility of the left frame - - LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, other wise will clear and redraw - LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update - LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame - LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw - - LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame - LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it - LeftFrames._prototype:on_player_toggle(player,frame) --- Triggered when the player toggle the left frame - LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add -]] - -local CenterFrames = require 'expcore.gui.concepts.center' --- @dep expcore.gui.concepts.center -Gui.get_center_flow = CenterFrames.get_flow -Gui.toggle_center_frame = CenterFrames.toggle_frame -Gui.draw_center_frame = CenterFrames.draw_frame -Gui.redraw_center_frame = CenterFrames.redraw_frames -Gui.new_center_frame = CenterFrames.new_frame -Gui.classes.center_frames = CenterFrames ---[[ - CenterFrames.get_flow(player) --- Gets the center flow for a player - CenterFrames.clear_flow(player) --- Clears the center flow for a player - CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing - CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destroy it and redraw - CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open - - CenterFrames.new_frame(permission_name) --- Sets the frame to be the current active gui when opened and closes all other frames - CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame - CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames - CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame) - CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame) - CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it - CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add -]] - -local PopupFrames = require 'expcore.gui.concepts.popups' --- @dep expcore.gui.concepts.popups -Gui.get_popup_flow = PopupFrames.get_flow -Gui.open_popup = PopupFrames.open -Gui.new_popup = PopupFrames.new_popup -Gui.classes.popup_frames = PopupFrames ---[[ - PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames - PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function - - PopupFrames.close_progress --- Progress bar which when depleted will close the popup frame - PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out - - PopupFrames.new_popup(name) --- Creates a new popup frame define - PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open - PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function -]] - -return Gui \ No newline at end of file +return require 'expcore.gui.core' \ No newline at end of file diff --git a/expcore/gui/concepts/button.lua b/expcore/gui/concepts/button.lua new file mode 100644 index 00000000..4cbcc6cd --- /dev/null +++ b/expcore/gui/concepts/button.lua @@ -0,0 +1,90 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Clickable elements that fire on_gui_click when clicked. +@element button + +@param on_click fired when the player clicks the button +@param on_left_click fired when the player clicks with the left mouse button +@param on_left_click fired when the player clicks with the right mouse button + +@tparam ?string|Concepts.LocalisedString caption the message that is shown on the button +@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the button +@tparam Concepts.SpritePath sprite upto three sprites in the order: default, hovered, clicked + +@usage-- Making a basic button +local basic_button = +Gui.new_concept('button') +:set_caption('Basic Button') +:set_tooltip('Basic button') +:on_click(function(event) + event.player.print('You pressed basic button!') +end) + +@usage-- Making a sprite button +local sprite_button = +Gui.new_concept('button') +:set_sprite('utility/warning_icon') +:set_tooltip('Sprite button') +:on_click(function(event) + event.player.print('You pressed sprite button!') +end) + +]] + +Gui.new_concept() +:save_as('button') + +-- Events +:new_event('on_click',defines.events.on_gui_click) +:new_event('on_left_click',defines.events.on_gui_click,function(event) + return event.mouse_button == defines.mouse_button_type.left +end) +:new_event('on_right_click',defines.events.on_gui_click,function(event) + return event.mouse_button == defines.mouse_button_type.right +end) + +-- Properties +:new_property('tooltip') +:new_property('caption',function(properties,value) + properties.caption = value + properties.type = 'button' +end) +:new_property('sprite',function(properties,value,hovered_sprite,clicked_sprite) + properties.sprite = value + properties.hovered_sprite = hovered_sprite + properties.clicked_sprite = clicked_sprite + properties.type = 'sprite-button' +end) + +-- Draw +:define_draw(function(properties,parent,element) + -- Check if it should be a sprite button + if properties.type == 'sprite-button' then + -- Draw a sprite button + element = parent.add{ + name = properties.name, + type = 'sprite-button', + sprite = properties.sprite, + hovered_sprite = properties.hovered_sprite, + clicked_sprite = properties.clicked_sprite, + tooltip = properties.tooltip + } + + else + -- Draw a button + element = parent.add{ + name = properties.name, + type = 'button', + caption = properties.caption, + tooltip = properties.tooltip + } + + end + + return element +end) \ 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/checkbox.lua b/expcore/gui/concepts/checkbox.lua new file mode 100644 index 00000000..364d9624 --- /dev/null +++ b/expcore/gui/concepts/checkbox.lua @@ -0,0 +1,62 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Clickable elements with a cross in the middle that can be turned off or on. +@element checkbox + +@param on_state_changed fired when the state of the element is changed + +@tparam ?string|Concepts.LocalisedString caption the message that is shown next to the checkbox +@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the checkbox +@tparam ?boolean|function default the default state of this checkbox, or a function which returns the default state +@tparam boolean use_radio setting to true will use radio buttons rather than checkboxs + +@usage-- Making a basic checkbox +local basic_checkbox = +Gui.new_concept('checkbox') +:set_caption('Basic Checkbox') +:set_tooltip('Basic checkbox') +:on_state_changed(function(event) + event.player.print('Basic checkbox is now: '..tostring(event.element.state)) +end) + +]] + +Gui.new_concept() +:save_as('checkbox') + +-- Events +:new_event('on_state_changed',defines.events.on_gui_checked_state_changed) + +-- Properties +:new_property('tooltip') +:new_property('caption') +:new_property('default',nil,false) +:new_property('use_radio',nil,false) + +-- Draw +:define_draw(function(properties,parent,element) + local default = properties.default + local state = type(default) == 'boolean' and default + + -- Draw a checkbox + element = parent.add{ + name = properties.name, + type = properties.use_radio and 'radiobutton' or 'checkbox', + caption = properties.caption, + tooltip = properties.tooltip, + state = state + } + + -- Set the default state + default = Gui.resolve_property(default,element) + if default and default ~= state then + element.state = default + end + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/dropdown.lua b/expcore/gui/concepts/dropdown.lua new file mode 100644 index 00000000..40e10afc --- /dev/null +++ b/expcore/gui/concepts/dropdown.lua @@ -0,0 +1,169 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' +local array_insert = ext_require('expcore.common','array_insert') + +--[[-- A drop down list of other elements. +@element dropdown + +@param on_selection_changed fired when the selected value is changed + +@tparam ?string|Concepts.LocalisedString|function default the option which is selected by default, or a function which returns the default +@tparam boolean use_list_box when true a list box will be used rather than a dropdown menu +@tparam ?nil|table static_items when called with a table the values will be added as items for the dropdown, if called with nil then all items are cleared +@tparam function dynamic_items the given function will be called to return a list of items and optional start index to add items to the dropdown when it is first drawn + + @usage-- Making a basic dropdown +local static_dropdown = +Gui.new_concept('dropdown') +:set_static_items{'Option 1','Option 2','Option 3'} +:on_selection_changed(function(event) + local value = Gui.get_dropdown_value(event.element) + event.player.print('Static dropdown is now: '..value) +end) + +@usage-- Making a dropdown with dynamic items, example is name of online players +local dynamic_dropdown = +Gui.new_concept('dropdown') +:set_dynamic_items(function(element) + local items = {} + for _,player in pairs(game.connected_players) do + items[#items+1] = player.name + end + return items +end) +:on_selection_changed(function(event) + local value = Gui.get_dropdown_value(event.element) + event.player.print('Dynamic dropdown is now: '..value) +end) + +]] + +Gui.new_concept() +:save_as('dropdown') + +-- Events +:new_event('on_selection_changed',defines.events.on_gui_selection_state_changed) + +-- Properties +:new_property('default') +:new_property('use_list_box',nil,false) +:new_property('static_items',function(properties,value,start_index) + -- Clear all items if value is nil + if not value then + properties.items = {} + end + + -- Convert value to a table + if type(value) ~= 'table' then + value = {value} + end + + -- If there are no items then set and return + local items = properties.items + if not items then + properties.items = value + return + end + + -- Otherwise insert into the array + array_insert(items,start_index,value) +end) +:new_property('dynamic_items',function(properties,value) + -- Check that a function value was given + if type(value) ~= 'function' then + error('Dynamic items must be a function') + end + + -- If no dynamic items then set and return + local items = properties.dynamic_items + if not items then + properties.dynamic_items = {value} + return + end + + -- Otherwise append to the end + items[#items+1] = value +end) + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a dropdown + element = parent.add{ + name = properties.name, + type = properties.use_list_box and 'list-box' or 'drop-down', + items = properties.items + } + + -- If there are dynamic items then add them + if properties.dynamic_items then + for _,callback in pairs(properties.dynamic_items) do + local dynamic_items, start_index = callback(element) + Gui.add_dropdown_items(element,start_index,dynamic_items) + end + end + + -- If there is a default, select it + local default = Gui.resolve_property(properties.default,element) + if default then + Gui.set_dropdown_value(element,default) + end + + return element +end) + +--- Dropdowns. +-- functions used with dropdowns +-- @section dropdowns + +--[[-- Selects the index of a dropdown with this value +@tparam LuaGuiElement element the dropdown that you want to set the selection for +@tparam ?string|Concepts.LocalisedString value the value that you want selected +@treturn boolean if an item with this value was found +@usage-- Selecting the item with the value 'foo' +Gui.set_dropdown_value(element,'foo') +]] +function Gui.set_dropdown_value(element,value) + for index, item in pairs(element.items) do + if item == value then + element.selected_index = index + return true + end + end + return false +end + +--[[-- Gets the selected item value of a dropdown +@tparam LuaGuiElement element the dropdown that you want the selected value of +@treturn ?string|Concepts.LocalisedString the value that is currently selected +@usage-- Getting the selected value +local selected_value = Gui.get_dropdown_value(element) +]] +function Gui.get_dropdown_value(element) + return element.items[element.selected_index] +end + +--[[-- Adds the given items into the list of items for this dropdown +@tparam LuaGuiElement element the dropdown that you want to add the items to +@tparam[opt] number start_index the index at which the items will be added, if not given appened to the end +@tparam table new_items the list of new items that you want to add +@treturn table the list of items that the element now has +@usage-- Add the items 'foo' and 'bar' to the end +Gui.add_dropdown_items(element,{'foo','bar'}) +@usage-- Add the items 'foo' and 'bar' to the start +Gui.add_dropdown_items(element,1,{'foo','bar'}) +]] +function Gui.add_dropdown_items(element,start_index,new_items) + if not new_items then + new_items = start_index + start_index = nil + end + + local items = element.items + element.items = array_insert(items,start_index,new_items) + + return items +end \ No newline at end of file diff --git a/expcore/gui/concepts/elem_button.lua b/expcore/gui/concepts/elem_button.lua new file mode 100644 index 00000000..4318b181 --- /dev/null +++ b/expcore/gui/concepts/elem_button.lua @@ -0,0 +1,51 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- A button that lets the player pick one of an: item, entity, tile, or signal similar to the filter-select window. +@element elem_button + +@param on_selection_changed fired when the selected value is changed + +@tparam ?string|Concepts.SignalID|function default the option which is selected by default, or a function which returns the default +@tparam string elem_type the type of elem selection that this is, default is item selection + +@usage-- Making a basic elem button +local basic_elem_button = +Gui.new_concept('elem_button') +:on_selection_changed(function(event) + event.player.print('Basic elem button is now: '..event.element.elem_value) +end) + +]] + +Gui.new_concept() +:save_as('elem_button') + +-- Events +:new_event('on_selection_changed',defines.events.on_gui_elem_changed) + +-- Properties +:new_property('default') +:new_property('elem_type',nil,'item') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a chose elem button + element = parent.add{ + name = properties.name, + type = 'choose-elem-button', + elem_type = properties.elem_type + } + + -- If there is a default, select it + local default = Gui.resolve_property(properties.default,element) + if default then + element.elem_value = default + end + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/empty.lua b/expcore/gui/concepts/empty.lua new file mode 100644 index 00000000..46c0233a --- /dev/null +++ b/expcore/gui/concepts/empty.lua @@ -0,0 +1,36 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- A empty widget that just exists. The root GUI element screen is an empty-widget. +@element empty + +@tparam string style the style that the element will have + +@usage-- Making a draggable space styled widget +local draggable_space = +Gui.new_concept('empty') +:set_style('draggable_space') + +]] + +Gui.new_concept() +:save_as('empty') + +-- Properties +:new_property('style') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw an empty widget + element = parent.add{ + name = properties.name, + type = 'empty-widget', + style = properties.style + } + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/flow.lua b/expcore/gui/concepts/flow.lua new file mode 100644 index 00000000..b4af20d4 --- /dev/null +++ b/expcore/gui/concepts/flow.lua @@ -0,0 +1,42 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Invisible containers that lay out children either horizontally or vertically. The root GUI elements (top, left and center; see LuaGui) are flows. +@element flow + +@tparam string direction the direction that children will be added + +@usage-- Making a basic flow, contains a label with hello world +local basic_flow = +Gui.new_concept('flow') +:define_draw(function(properties,parent,element) + element.add{ + type = 'label', + caption = 'Hello, World!' + } +end) + +]] + +Gui.new_concept() +:save_as('flow') + +-- Properties +:new_property('direction') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a flow + element = parent.add{ + name = properties.name, + type = 'flow', + caption = properties.title, + direction = properties.direction + } + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/frame.lua b/expcore/gui/concepts/frame.lua new file mode 100644 index 00000000..6a216353 --- /dev/null +++ b/expcore/gui/concepts/frame.lua @@ -0,0 +1,45 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Grey semi-transparent boxes that contain other elements. They have a caption, and, just like flows, they lay out children either horizontally or vertically. +@element frame + +@tparam ?string|Concepts.LocalisedString title the title that will show in the frame +@tparam string direction the direction that children will be added + +@usage-- Making a basic frame, contains a label with hello world +local basic_frame = +Gui.new_concept('frame') +:set_title('Basic Frame') +:define_draw(function(properties,parent,element) + element.add{ + type = 'label', + caption = 'Hello, World!' + } +end) + +]] + +Gui.new_concept() +:save_as('frame') + +-- Properties +:new_property('title') +:new_property('direction') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a frame + element = parent.add{ + name = properties.name, + type = 'frame', + caption = properties.title, + direction = properties.direction + } + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/label.lua b/expcore/gui/concepts/label.lua new file mode 100644 index 00000000..1cf70eac --- /dev/null +++ b/expcore/gui/concepts/label.lua @@ -0,0 +1,46 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- A piece of text. +@element frame + +@tparam ?string|Concepts.LocalisedString caption the caption that will show in the label +@tparam ?string|Concepts.LocalisedString description the description that will show on the label +@tparam defines.rich_text_setting rich_text how this element handles rich text + +@usage-- Making a basic label +local basic_label = +Gui.new_concept('label') +:set_caption('Hello, World!') + +]] +Gui.new_concept() +:save_as('label') + +-- Properties +:new_property('caption') +:new_property('description') +:new_property('rich_text') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a label + element = parent.add{ + name = properties.name, + type = 'label', + caption = properties.caption, + description = properties.description + } + + -- Change rich text setting if present + local rich_text = properties.rich_text + if rich_text then + element.style.rich_text_setting = rich_text + end + + return element +end) \ 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/line.lua b/expcore/gui/concepts/line.lua new file mode 100644 index 00000000..28f41cc7 --- /dev/null +++ b/expcore/gui/concepts/line.lua @@ -0,0 +1,35 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- A vertical or horizontal line. +@element line + +@tparam string direction the direction that children will be added + +@usage-- Making a basic frame, contains a label with hello world +local basic_line = +Gui.new_concept('line') + +]] + +Gui.new_concept() +:save_as('line') + +-- Properties +:new_property('direction') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a line + element = parent.add{ + name = properties.name, + type = 'line', + direction = properties.direction + } + + return element +end) \ 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/progress_bar.lua b/expcore/gui/concepts/progress_bar.lua new file mode 100644 index 00000000..4bcb0b8a --- /dev/null +++ b/expcore/gui/concepts/progress_bar.lua @@ -0,0 +1,168 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Indicate progress by displaying a partially filled bar. +@element progress_bar + +@param on_completion fired when increment reaches the maxium value set by set_maximum + +@tparam ?string|Concepts.LocalisedString tooltip the tooltip that will show for this element +@tparam number maximum the maxium amount an instance can be increased, default 100 +@tparam boolean delay_completion when true the progress will be completed untill after the maximum rather than at the maximum +@tparam boolean inverted although this will NOT effect how you use the functions it will make the element start full and reduce as you call increase, note issues with 0 detections + +@usage-- Making a basic progress bar, will increase when pressed then will reset when full +local basic_progress_bar = +Gui.new_concept('progress_bar') +:set_tooltip('Basic progress bar') +:set_maximum(5) +:new_event('on_click',defines.events.on_gui_click) +:on_click(function(event) + event.concept:increment(event.element) +end) +:set_delay_completion(true) +:on_completion(function(event) + event.concept:reset(event.element) +end) + +]] + +local progress_bar = +Gui.new_concept() +:save_as('progress_bar') + +-- Events +:new_event('on_completion') + +-- Properties +:new_property('tooltip') +:new_property('maximum',nil,100) +:new_property('delay_completion',nil,false) +:new_property('inverted',nil,false) + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a progress bar + element = parent.add{ + name = properties.name, + tooltip = properties.tooltip, + type = 'progressbar', + value = properties.inverted and 1 or 0 + } + + return element +end) + +--- Progress Bars. +-- functions used with progress bars +-- @section progress_bars + +-- logic for changing the value of a progress bar +local function raw_update(concept,element,amount) + local old_value = element.value + local new_value = old_value + amount + element.value = new_value + + local check_value = concept.properties.delay_completion and old_value or new_value + if amount < 0 and check_value <= 0 or amount > 0 and check_value >= 1 then + concept:raise_event('on_completion',{ + element = element + }) + else + return new_value + + end + +end + +--[[-- Will increase the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances +@tparam ?LuaGuiElement|string element either the element that is changed or the category that is being changed (only if an instance store is defined) +@tparam[opt=1] number amount the amount that will bar will increase, note that this amount must be less than the max +@treturn ?number|nil the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed +@usage-- Incrementing progress bar with no instance store +local new_value = progress_bar:increment(element) +@usage-- Incrementing progress bar with an instance store +progress_bar:increment(category) +]] +function progress_bar:increment(element,amount) + local properties = self.properties + local inverted = properties.inverted + local maximum = properties.maximum + amount = amount and amount/maximum or 1/maximum + amount = inverted and -amount or amount + + if self.instance_store and not self.sync_instance then + self.update_instances(element,function(next_element) + raw_update(self,next_element,amount) + end) + + else + return raw_update(self,element,amount) + + end +end + +--[[-- Will decrease the progress of a progress bar based on this concept, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances +@tparam ?LuaGuiElement|string element either the element that is changed or the category that is being changed (only if an instance store is defined) +@tparam[opt=1] number amount the amount that will bar will decrease, note that this amount must be less than the max +@treturn number the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed +@usage-- Decrementing progress bar with no instance store +local new_value = progress_bar:decrement(element) +@usage-- Decrementing progress bar with an instance store +progress_bar:decrement(category) +]] +function progress_bar:decrement(element,amount) + self:increment(element,-amount) +end + +--[[-- Resets the progress back to 0% for this element, if the concept has an instance store then element acts as the category, if you have a combined store it will NOT update all instances +@tparam ?LuaGuiElement|string element either the element that is changed or the category that is being changed (only if an instance store is defined) +@treturn ?number|nil the new value of the element, use this to sync a data store, if the return is nil then either a instance store was used or the new value may have changed +@usage-- Reseting a progress bar with no instance store +local new_value = progress_bar:reset(element) +@usage-- Reseting a progress bar with an instance store +progress_bar:reset(category) +]] +function progress_bar:reset(element) + local new_value = self.properties.inverted and 1 or 0 + if self.instacne_store and not self.sync_instance then + self.update_instances(element,function(next_element) + next_element.value = new_value + end) + + else + element.value = new_value + return new_value + + end +end + +--[[-- Increment any progress bar by the given percentage +@tparam LuaGuiElement element the progress bar that you want to update +@tparam[opt=0.01] number amount the percentage that you want to increment the progress bar by +@treturn boolean true if the bar is now full +@usage-- Increment any progress bar by 10% +Gui.increment_progress_bar(element,0.1) +]] +function Gui.increment_progress_bar(element,amount) + amount = amount or 0.01 + element.value = element.value + amount + return element.value >= 1 +end + +--[[-- Decrement any progress bar by the given percentage +@tparam LuaGuiElement element the progress bar that you want to update +@tparam[opt=0.01] number amount the percentage that you want to decrement the progress bar by +@treturn boolean true if the bar is now empty +@usage-- Decrement any progress bar by 10% +Gui.decrement_progress_bar(element,0.1) +]] +function Gui.decrement_progress_bar(element,amount) + amount = amount or 0.01 + element.value = element.value - amount + return element.value <= 0 +end \ No newline at end of file diff --git a/expcore/gui/concepts/scroll.lua b/expcore/gui/concepts/scroll.lua new file mode 100644 index 00000000..034766f7 --- /dev/null +++ b/expcore/gui/concepts/scroll.lua @@ -0,0 +1,47 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Similar to a flow but includes the ability to show and use scroll bars. +@element scroll + +@tparam string horizontal_scroll the horizontal scroll policy for this scroll pane +@tparam string vertical_scroll the vertical scroll policy for this scroll pane + +@usage-- Making a basic flow, contains a label with hello world +local basic_scroll = +Gui.new_concept('scroll') +:define_draw(function(properties,parent,element) + element.style.hieght = 50 + for i = 1,10 do + element.add{ + type = 'label', + caption = i + } + end +end) + +]] + +Gui.new_concept() +:save_as('scroll') + +-- Properties +:new_property('horizontal_scroll') +:new_property('vertical_scroll') + +-- Draw +:define_draw(function(properties,parent,element) + -- Draw a scroll pane + element = parent.add{ + name = properties.name, + type = 'scroll-pane', + horizontal_scroll_policy = properties.horizontal_scroll, + vertical_scroll_policy = properties.vertical_scroll + } + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/slider.lua b/expcore/gui/concepts/slider.lua new file mode 100644 index 00000000..703fe102 --- /dev/null +++ b/expcore/gui/concepts/slider.lua @@ -0,0 +1,91 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- A number picker. +@element slider + +@param on_value_changed fired when the value of the slider is changed + +@tparam number value_step the minimum amount by which the value of the slider can be changed +@tparam ?number|function default the default value of the slider or a function which returns the default value +@tparam boolean discrete_slider makes this slider a discrete slider, this means that the slider button will stop at the same interval as the values do +@tparam ?number|function range accepts two params the minimum and the maximum for this slider, or a single function to return both + +@usage-- Making a basic slider +local basic_slider = +Gui.new_concept('slider') +:set_range(1,10) +:on_value_changed(function(event) + event.player.print('Basic slider is now: '..event.element.slider_value) +end) + +@usage-- Making a discrete_slider +local discrete_slider = +Gui.new_concept('slider') +:set_range(1,10) +:set_value_step(1) +:set_discrete_slider(true) +:on_value_changed(function(event) + event.player.print('Interval slider is now: '..event.element.slider_value) +end) + +]] + +Gui.new_concept() +:save_as('slider') + +-- Events +:new_event('on_value_changed',defines.events.on_gui_value_changed) + +-- Properties +:new_property('value_step') +:new_property('default') +:new_property('discrete_slider',nil,false) +:new_property('range',function(properties,minimum,maximum) + if type(minimum) == 'function' then + properties.range = minimum + else + properties.minimum = minimum + properties.maximum = maximum + end +end) + +-- Draw +:define_draw(function(properties,parent,element) + local default = properties.default + local value = type(default) == 'number' and default + local value_step = properties.value_step + + -- Draw a slider + element = parent.add{ + name = properties.name, + type = 'slider', + caption = properties.caption, + minimum_value = properties.minimum, + maximum_value = properties.maximum, + discrete_slider = properties.discrete_slider, + discrete_values = value_step ~= nil, + value_step = value_step, + value = value + } + + -- Find the range for the slider and set it + local min, max = Gui.resolve_property(properties.range,element) + if min or max then + min = min or element.get_slider_minimum() + max = max or element.get_slider_maximum() + element.set_slider_minimum_maximum(min,max) + end + + -- If there is a default, select it + default = Gui.resolve_property(default,element) + if default and default ~= value then + element.slider_value = default + end + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/table.lua b/expcore/gui/concepts/table.lua new file mode 100644 index 00000000..3a7ae3bf --- /dev/null +++ b/expcore/gui/concepts/table.lua @@ -0,0 +1,58 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- An invisible container that lays out children in a specific number of columns. Column width is given by the largest element contained in that row. +@element table + +@tparam ?number|function column_count the column count of the table or a function that returns the count being given then parent element +@tparam boolean vertical_lines when true vertical lines will be drawn on the table +@tparam boolean horizontal_lines when true horizontal lines will be drawn on the table +@tparam boolean header_lines when true horizontal lines will be drawn under the first row +@tparam boolean vertical_centering when true element will be vertically centered with in the table + +@usage-- Making a basic table, contains 25 labels +local basic_table = +Gui.new_concept('table') +:set_column_count(5) +:define_draw(function(properties,parent,element) + for i = 1,25 do + element.add{ + type = 'lable', + caption = i + } + end +end) + +]] + +Gui.new_concept() +:save_as('table') + +-- Properties +:new_property('column_count') +:new_property('vertical_lines') +:new_property('horizontal_lines') +:new_property('header_lines') +:new_property('vertical_centering') + +-- Draw +:define_draw(function(properties,parent,element) + local column_count = Gui.resolve_property(properties.column_count,parent) + + -- Draw a table + element = parent.add{ + name = properties.name, + type = 'table', + column_count = column_count, + draw_vertical_lines = properties.vertical_lines, + draw_horizontal_lines = properties.horizontal_lines, + draw_horizontal_line_after_headers = properties.header_lines, + vertical_centering = properties.vertical_centering + } + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/text_box.lua b/expcore/gui/concepts/text_box.lua new file mode 100644 index 00000000..122ba17f --- /dev/null +++ b/expcore/gui/concepts/text_box.lua @@ -0,0 +1,84 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- A multi-line text box that supports selection and copy-paste. +@element text_box + +@param on_text_changed fired when the text within the text box is changed + +@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the text box +@tparam ?string|function default the default text that will appear in the text box, or a function that returns it +@tparam defines.rich_text_setting rich_text how this element handles rich text +@tparam boolean clear_on_rmb if the text box will be cleared and forcused on a right click +@tparam boolean is_selectable when true the text inside the box can be selected +@tparam boolean has_word_wrap when true the text will wrap onto the next line if it reachs the end +@tparam boolean is_read_only when true the text inside the box can not be edited by the player + +@usage-- Making a text box +local basic_text_box = +Gui.new_concept('text_box') +:set_default('I am the text that will show in the text box') + +@usage-- Making a text box which can be edited +local editible_text_box = +Gui.new_concept('text_box') +:set_is_read_only(false) +:set_default('I am the text that will show in the text box') +:on_confirmation(function(event) + event.player.print('Editible text box is now: '..event.element.text) +end) + +]] + +Gui.new_concept() +:save_as('text_box') + +-- Events +:new_event('on_text_changed',defines.events.on_gui_text_changed) + +-- Properties +:new_property('tooltip') +:new_property('default') +:new_property('rich_text') +:new_property('clear_on_rmb',nil,false) +:new_property('is_selectable',nil,true) +:new_property('has_word_wrap',nil,true) +:new_property('is_read_only',nil,true) + +-- Draw +:define_draw(function(properties,parent,element) + local default = properties.default + local text = type(default) == 'string' and default or nil + + -- Draw a text box + element = parent.add{ + name = properties.name, + type = 'text-box', + tooltip = properties.tooltip, + clear_and_focus_on_right_click = properties.clear_on_rmb, + text = text + } + + -- Set options for text box + element.selectable = properties.is_selectable + element.word_wrap = properties.has_word_wrap + element.read_only = properties.is_read_only + + -- If there is a default, set it + default = Gui.resolve_property(default,element) + if default and default ~= text then + element.text = default + end + + -- Change rich text setting if present + local rich_text = properties.rich_text + if rich_text then + element.style.rich_text_setting = rich_text + end + + return element +end) \ No newline at end of file diff --git a/expcore/gui/concepts/text_field.lua b/expcore/gui/concepts/text_field.lua new file mode 100644 index 00000000..dd8f862d --- /dev/null +++ b/expcore/gui/concepts/text_field.lua @@ -0,0 +1,100 @@ +--[[-- Core Module - Gui + @module Gui + @alias Gui +]] + +local Gui = require 'expcore.gui.core' + +--[[-- Boxes of text the user can type in. +@element text_field + +@param on_text_changed fired when the text within the text field is changed +@param on_confirmation fired when the player presses enter with the text field forcused + +@tparam ?string|Concepts.LocalisedString tooltip the tooltip that shows when a player hovers over the text field +@tparam ?string|function default the default text that will appear in the text field, or a function that returns it +@tparam defines.rich_text_setting rich_text how this element handles rich text +@tparam boolean clear_on_rmb if the text field will be cleared and forcused on a right click +@tparam boolean lose_forcus if the text field will lose forcus after the confirmation event +@tparam boolean is_number if this text field contains a number value, can be ignored if is_decimal or is_negitive is used +@tparam boolean is_decimal if this text field contains a decimal value +@tparam boolean is_negative if this text field contains a negative value +@tparam boolean is_password if this text field contains a password value + +@usage-- Making a text field +local basic_text_field = +Gui.new_concept('text_field') +:on_confirmation(function(event) + event.player.print('Basic text field is now: '..event.element.text) +end) + +@usage-- Making a text field which will clear on right click and un forcus on confirmation +local better_text_field = +Gui.new_concept('text_field') +:set_clear_on_rmb(true) +:set_lose_forcus(true) +:on_confirmation(function(event) + event.player.print('Better text field is now: '..event.element.text) +end) + +@usage-- Making a decimal input +local decimal_text_field = +Gui.new_concept('text_field') +:set_is_decimal(true) +:on_confirmation(function(event) + event.player.print('Decimal text field is now: '..event.element.text) +end) + +]] + +Gui.new_concept() +:save_as('text_field') + +-- Events +:new_event('on_text_changed',defines.events.on_gui_text_changed) +:new_event('on_confirmation',defines.events.on_gui_confirmed) + +-- Properties +:new_property('tooltip') +:new_property('default') +:new_property('rich_text') +:new_property('clear_on_rmb',nil,false) +:new_property('lose_forcus',nil,false) +:new_property('is_number',nil,false) +:new_property('is_decimal',nil,false) +:new_property('is_negative',nil,false) +:new_property('is_password',nil,false) + +-- Draw +:define_draw(function(properties,parent,element) + local default = properties.default + local text = type(default) == 'string' and default or nil + + -- Draw a text field + element = parent.add{ + name = properties.name, + type = 'textfield', + tooltip = properties.tooltip, + clear_and_focus_on_right_click = properties.clear_on_rmb, + lose_focus_on_confirm = properties.lose_forcus, + numeric = properties.is_number or properties.is_decimal or properties.is_negative, + allow_decimal = properties.is_decimal, + allow_negative = properties.is_negative, + is_password = properties.is_password, + text = text + } + + -- If there is a default, set it + default = Gui.resolve_property(default,element) + if default and default ~= text then + element.text = default + end + + -- Change rich text setting if present + local rich_text = properties.rich_text + if rich_text then + element.style.rich_text_setting = rich_text + end + + return element +end) \ 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 index 1fd93480..1edcd0b3 100644 --- a/expcore/gui/core.lua +++ b/expcore/gui/core.lua @@ -1,368 +1,250 @@ --[[-- Core Module - Gui @module Gui - @alias Prototype + @alias Gui ]] ---- Core. --- Core gui file for making element defines and element classes (use require 'expcore.gui') --- see utils.gui for event handlering --- see expcore.gui.test for examples for element defines --- @section core +local Game = require 'utils.game' -- @dep utils.game +local resolve_value = ext_require('expcore.common','resolve_value') -- @dep expcore.common +local Prototype = require 'expcore.gui.prototype' ---[[ ->>>> Basic useage with no defines - This module can be igroned if you are only wanting only event handlers as utils.gui adds the following: +local Gui = { + concepts = {} +} - 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 +--- Concept Control. +-- Functions that act as a landing point for the other funtions +-- @section concept-control - 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 +--[[-- Loads a concept from the concepts file +@tparam string concept_name the name of the concept to require +@usage-- Load a base concept +Gui.require_concept('frame') --- @dep Gui.concept.frame ]] -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 +function Gui.require_concept(concept_name) + require('expcore.gui.concepts.'..concept_name) 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] +--[[-- Loads a set of concepts from the styles file +@tparam string style_name the name of the style to require +@usage-- Load a base style +Gui.require_concept('expgaming') --- @dep Gui.style.frame +]] +function Gui.require_style(style_name) + require('expcore.gui.styles.'..style_name) +end + +--[[-- Gets a gui concept from name, id, or its self +@tparam ?string|number|table name the name, id, or the concept you want to get +@usage-- Getting a gui concept +local button = Gui.get_concept('Button') +]] +function Gui.get_concept(name) + if not name then return end + local vtype = type(name) + + if vtype == 'string' then + return Gui.concepts[name] + + elseif vtype == 'table' then + if name.draw_callbacks then + return name 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 + elseif vtype == 'number' then + for _,concept in pairs(Gui.concepts) do + if concept.name == name then + return concept + end + end 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 +--[[-- Used to save the concept to the main gui module to allow access from other files +@function Prototype:save_as +@tparam string save_name the new name of the concept +@usage-- Save a concept to allow access in another file +button:save_as('button') +@usage-- Access concept after being saved +Gui.concepts.button +Gui.get_concept('button') +]] +function Prototype:save_as(save_name) + Gui.concepts[save_name] = self + return self +end + +--[[-- Returns a new gui concept, option to provide a base concept to copy properties and draw functions from +@tparam[opt] ?string|number|table base_concept the concept that you want to copy the details of +@usage-- Making a new button, see module usage +local button = Gui.new_concept('Button') +]] +function Gui.new_concept(base_concept) + if base_concept then + base_concept = Gui.get_concept(base_concept) or error('Invalid gui concept "'..tostring(base_concept)..'"',2) + return base_concept:clone() + else + return Prototype:clone() + end +end + +--[[-- Used to draw a concept to a parent element +@tparam ?string|number|table concept the name of the concept that you want to draw +@tparam LuaGuiElement parent the element that will act as a parent for the new element +@treturn LuaGuiElement the element that was created +@usage-- Drawing a new element +Gui.draw_concept('Button',element) +]] +function Gui.draw_concept(concept,parent,...) + concept = Gui.get_concept(concept) or error('Invalid gui concept "'..tostring(concept)..'"',2) + return concept:draw(parent,...) +end + +--- Element Control. +-- Functions that aim to making working with gui elements easier +-- @section element-control + +--[[-- Gets the player who owns this element +@tparam LuaGuiElement element the element that you want to get the player of +@treturn LuaPlayer the player who owns this element +@usage-- Getting the player of an element +local player = Gui.get_player_from_element(element) +]] +function Gui.get_player_from_element(element) + return Game.get_player_by_index(element.player_index) +end + +--[[-- Simple check for if an element is valid +@tparam LuaGuiElement element the element that you want to check is valid +@treturn boolean true if the element is valid +@usage-- Return if not valid +if not Gui.valid(element) then return end +]] +function Gui.valid(element) + return element and element.valid or false +end + +--[[-- Destroies and element if it is valid +@tparam LuaGuiElement element the element that you want to destroy +@treturn boolean true if the element was valid and was destoried +@usage-- Destoring an element +Gui.destroy(element) +]] +function Gui.destroy(element) + if element and element.valid then + element.destroy() + return true + end + return false +end + +--[[-- Toggles the enabled state of an element +@tparam LuaGuiElement element the element that you want to toggle the enabled state of +@treturn boolean the new enabled state of the element +@usage-- Toggle the enabled state of an element +Gui.toggle_enabled(element) +]] +function Gui.toggle_enabled(element) + if not element or not element.valid then return end + if not element.enabled then + element.enabled = true + return true + else + element.enabled = false + return false + end +end + +--[[-- Toggles the visible state of an element +@tparam LuaGuiElement element the element that you want to toggle the visible state of +@treturn boolean the new visible state of the element +@usage-- Toggle the visible state of an element +Gui.toggle_visible(element) +]] +function Gui.toggle_visible(element) + if not element or not element.valid then return end + if not element.visible then + element.visible = true + return true + else + element.visible = false + return false + end +end + +--[[-- Sets the padding for a gui element +@tparam LuaGuiElement element the element to set the padding for +@tparam[opt=0] ?number|boolean up the amount of padding on the top, true leaves unchanged +@tparam[opt=0] ?number|boolean down the amount of padding on the bottom, true leaves unchanged +@tparam[opt=0] ?number|boolean left the amount of padding on the left, true leaves unchanged +@tparam[opt=0] ?number|boolean right the amount of padding on the right, true leaves unchanged +@usage-- Remove all padding of an element +Gui.set_padding(element) +@usage-- Remove side padding but keep vertical padding +Gui.set_padding(element,true,true) +@usage-- Remove all padding but set right to 2 +Gui.set_padding(element,false,false,false,2) +]] +function Gui.set_padding(element,up,down,left,right) + local style = element.style + style.top_padding = up == true and style.top_padding or up or 0 + style.bottom_padding = down == true and style.top_padding or down or 0 + style.left_padding = left == true and style.top_padding or left or 0 + style.right_padding = right == true and style.top_padding or right or 0 +end + +--[[ Used to check a property exists and if it is a function then call the function +@function Gui.resolve_property +@tparam any value the value that you are testing exists and call if its a function +@tparam LuaGuiElement element the element that is passed to the function if it is a function +@treturn any the value or what it returns if it is a function +@usage-- Getting the default value +local default = Gui.resolve_property(properties.default,element) +if default then + element.value = default +end +]] +Gui.resolve_property = resolve_value + +--- Store Categories. +-- Functions that are common types of categories +-- @section store-categories + +--[[-- A categorize function to be used with add_store, each player has their own category +@tparam LuaGuiElement element the element that will be converted to a string +@treturn string the player's name who owns this element +@usage-- Storing data on a per player basis, can be used with instances +Gui.get_concept('CustomButton') +:define_data_store(Gui.categorize_by_player) +]] 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 +--[[-- A categorize function to be used with add_store, each force has its own category +@tparam LuaGuiElement element the element that will be converted to a string +@treturn string the player's force name who owns this element +@usage-- Storing data on a per force basis, can be used with instances +Gui.get_concept('CustomButton') +:define_data_store(Gui.categorize_by_force) +]] 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 +--[[-- A categorize function to be used with add_store, each surface has its own category +@tparam LuaGuiElement element the element that will be converted to a string +@treturn string the player's surface name who owns this element +@usage-- Storing data on a per surface basis, can be used with instances +Gui.get_concept('CustomButton') +:define_data_store(Gui.categorize_by_surface) +]] 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/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 98f50811..00000000 --- a/expcore/gui/elements/checkbox.lua +++ /dev/null @@ -1,252 +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(false,store_update), - add_sync_store = Prototype.store(true,store_update) - }, - _prototype_radiobutton=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(false,store_update), - add_sync_store = Prototype.store(true,store_update) - } -} - ---- Creates a new checkbox element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new checkbox element define -function Checkbox.new_checkbox(name) - - local self = Gui.new_define(Checkbox._prototype_checkbox,name) - self.draw_data.type = 'checkbox' - self.draw_data.state = false - - self:on_draw(function(player,element) - if self.store then - local category = self.categorize and self.categorize(element) or nil - local state = self:get_store(category,true) - if state then element.state = true end - end - end) - - Gui.on_checked_state_changed(self.name,function(event) - local element = event.element - - if self.option_set then - local value = Checkbox.option_sets[self.option_set][element.name] - local category = self.categorize and self.categorize(element) - self:set_store(category,value) - - elseif self.store then - local value = element.state - local category = self.categorize and self.categorize(element) - self:set_store(category,value) - - else - self:raise_event('on_element_update',event.player,element,element.state) - - end - end) - - return self -end - ---- Creates a new radiobutton element define, has all functions checkbox has --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new button element define -function Checkbox.new_radiobutton(name) - local self = Checkbox.new_checkbox(name) - self.draw_data.type = 'radiobutton' - - local mt = getmetatable(self) - mt.__index = Checkbox._prototype_radiobutton - - return self -end - ---- Adds this radiobutton to be an option in the given option set (only one can be true at a time) --- @tparam string option_set the name of the option set to add this element to --- @tparam string option_name the name of this option that will be used to identify it --- @treturn self the define to allow chaining -function Checkbox._prototype_radiobutton:add_as_option(option_set,option_name) - self.option_set = option_set - self.option_name = option_name or self.name - - Checkbox.option_sets[option_set][self.option_name] = self.name - Checkbox.option_sets[option_set][self.name] = self.option_name - - self:add_store(Checkbox.option_categorize[option_set]) - - return self -end - ---- Gets the stored value of the radiobutton or the option set if present --- @tparam string category[opt] the category to get such as player name or force name --- @tparam boolean internal used to prevent stackover flow --- @treturn any the value that is stored for this define -function Checkbox._prototype_radiobutton:get_store(category,internal) - if not self.store then return end - local location = not internal and self.option_set or self.store - return Store.get(location,category) -end - ---- Sets the stored value of the radiobutton or the option set if present --- @tparam string category[opt] the category to get such as player name or force name --- @tparam boolean value the value to set for this define, must be valid for its type ie for checkbox etc --- @tparam boolean internal used to prevent stackover flow --- @treturn boolean true if the value was set -function Checkbox._prototype_radiobutton:set_store(category,value,internal) - if not self.store then return end - local location = not internal and self.option_set or self.store - return Store.set(location,category,value) -end - ---- Registers a new option set that can be linked to radiobuttons (only one can be true at a time) --- @tparam string name the name of the option set, must be unique --- @tparam function callback the update callback when the value of the option set changes --- callback param - value string - the new selected option for this option set --- callback param - category string - the category that updated if categorize was used --- @tparam function categorize the function used to convert an element into a string --- @treturn string the name of this option set to be passed to add_as_option -function Checkbox.new_option_set(name,callback,categorize) - - Store.register(name,function(value,category) - local options = Checkbox.option_sets[name] - for opt_name,define_name in pairs(options) do - if Gui.defines[define_name] then - local define = Gui.get_define(define_name) - local state = opt_name == value - define:set_store(category,state,true) - end - end - callback(value,category) - end) - - Checkbox.option_categorize[name] = categorize - Checkbox.option_sets[name] = {} - - return name -end - ---- Draws all radiobuttons that are part of an option set at once (Gui.draw will not work) --- @tparam string name the name of the option set to draw the radiobuttons of --- @tparam LuaGuiElement element the parent element that the radiobuttons will be drawn to -function Checkbox.draw_option_set(name,element) - if not Checkbox.option_sets[name] then return end - local options = Checkbox.option_sets[name] - - for _,option in pairs(options) do - if Gui.defines[option] then - Gui.defines[option]:draw_to(element) - end - end - -end - ---- Sets all radiobutton in a element to false (unless excluded) and can act recursively --- @tparam LuaGuiElement element the root gui element to start setting radio buttons from --- @tparam[opt] table exclude ?string|table the name of the radiobutton to exclude or a of radiobuttons where true will set the state true --- @tparam[opt=false] ?number|boolean recursive if true will recur as much as possible, if a will recur that number of times --- @treturn boolean true if successful -function Checkbox.reset_radiobuttons(element,exclude,recursive) - if not element or not element.valid then return end - exclude = type(exclude) == 'table' and exclude or exclude ~= nil and {[exclude]=true} or {} - recursive = type(recursive) == 'number' and recursive-1 or recursive - - for _,child in pairs(element.children) do - if child and child.valid and child.type == 'radiobutton' then - local state = exclude[child.name] or false - local define = Gui.defines[child.name] - - if define then - local category = define.categorize and define.categorize(child) or state - define:set_store(category,state) - - else - child.state = state - - end - - elseif child.children and (type(recursive) == 'number' and recursive >= 0 or recursive == true) then - Checkbox.reset_radiobutton(child,exclude,recursive) - - end - end - - return true -end - -return Checkbox \ 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 c56eb960..00000000 --- a/expcore/gui/elements/dropdown.lua +++ /dev/null @@ -1,187 +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(false,store_update), - add_sync_store = Prototype.store(true,store_update) - } -} - ---- Creates a new dropdown element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new dropdown element define -function Dropdown.new_dropdown(name) - - local self = Gui.new_define(Dropdown._prototype,name) - self.draw_data.type = 'drop-down' - - self:on_draw(function(player,element) - if self.dynamic_options then - local dynamic_options = self.dynamic_options(player,element) - local items = element.items - for _,v in pairs(dynamic_options) do - table.insert(items,v) - end - element.items = items - end - - if self.store then - local category = self.categorize and self.categorize(element) or nil - local value = self:get_store(category) - if value then Dropdown.select_value(element,value) end - end - end) - - Gui.on_selection_state_changed(self.name,function(event) - local element = event.element - local value = Dropdown.get_selected_value(element) - - if self.store then - local category = self.categorize and self.categorize(element) or value - self:set_store(category,value) - - else - local player = event.player - local option_callbacks = self.option_callbacks - self:raise_event('on_element_update',player,element,value) - if option_callbacks and option_callbacks[value] then - option_callbacks[value](player,element,value) - end - - end - - end) - - return self -end - ---- Creates a new list box element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new list box element define -function Dropdown.new_list_box(name) - local self = Dropdown.new_dropdown(name) - self.draw_data.type = 'list-box' - - return self -end - ---- Adds new static options to the dropdown which will trigger the general callback --- @tparam table options ?string|table either a of option strings or the first option string, with a table values are the options --- @tparam[opt] table ... when options is not a you can add the options one after each other --- @tparam self the define to allow chaining -function Dropdown._prototype:new_static_options(options,...) - if type(options) == 'string' then - options = {options} - for _,v in pairs({...}) do - table.insert(options,v) - end - end - - self.options = options - self.draw_data.items = options - return self -end -Dropdown._prototype.add_options = Dropdown._prototype.new_static_options - ---- Adds a callback which should return a table of values to be added as options for the dropdown (appended after static options) --- @tparam function callback the function that will run to get the options for the dropdown --- callback param - player LuaPlayer - the player that the element is being drawn to --- callback param - element LuaGuiElement - the element that is being drawn --- callback return - table - the values of this table will be appended to the static options of the dropdown --- @treturn self the define to allow chaining -function Dropdown._prototype:new_dynamic_options(callback) - if type(callback) ~= 'function' then - return error('Dynamic options callback must be a function',2) - end - self.dynamic_options = callback - return self -end -Dropdown._prototype.add_dynamic = Dropdown._prototype.new_dynamic_options - ---- Adds a case specific callback which will only run when that option is selected (general case still triggered) --- @tparam string option the name of the option to trigger the callback on; if not already added then will be added as an option --- @tparam function callback the function that will be called when that option is selected --- callback param - player LuaPlayer - the player who owns the gui element --- callback param - element LuaGuiElement - the element which is being effected --- callback param - value string - the new option that has been selected --- @treturn self the define to allow chaining -function Dropdown._prototype:add_option_callback(option,callback) - if not self.option_callbacks then self.option_callbacks = {} end - if not self.options then self.options = {} end - - self.option_callbacks[option] = callback - if not table.contains(self.options,option) then - table.insert(self.options,option) - end - - return self -end - ---- Selects the option from a dropdown or list box given the value rather than key --- @tparam LuaGuiElement element the element that contains the option --- @tparam string value the option to select from the dropdown --- @treturn number the key where the value was -function Dropdown.select_value(element,value) - for k,item in pairs(element.items) do - if item == value then - element.selected_index = k - return k - end - end -end -select_value = Dropdown.select_value - ---- Returns the currently selected value rather than index --- @tparam LuaGuiElement element the gui element that you want to get the value of --- @treturn string the value that is currently selected -function Dropdown.get_selected_value(element) - local index = element.selected_index - return element.items[index] -end - -return Dropdown \ 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 e61859bf..00000000 --- a/expcore/gui/elements/elem-button.lua +++ /dev/null @@ -1,99 +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(false,store_update), - add_sync_store = Prototype.store(true,store_update) - } -} - ---- Creates a new elem button element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new elem button element define -function ElemButton.new_elem_button(name) - - local self = Gui.new_define(ElemButton._prototype,name) - self.draw_data.type = 'choose-elem-button' - - self:on_draw(function(player,element) - if type(self.default) == 'function' then - element.elem_value = self.default(player,element) - end - - if self.store then - local category = self.categorize and self.categorize(element) or nil - local value = self:get_store(category) - if value then element.elem_value = value end - end - end) - - Gui.on_elem_changed(self.name,function(event) - local element = event.element - local value = element.elem_value - - if self.store then - local category = self.categorize and self.categorize(element) or value - self:set_store(category,value) - - else - self:raise_event('on_element_update',event.player,element,value) - - end - - end) - - return self -end - ---- Sets the type of the elem button, the type is required so this must be called at least once --- @tparam string type the type that this elem button is see factorio api --- @treturn the element define to allow for chaining -ElemButton._prototype.set_type = Prototype.setter('string','draw_data','elem_type') - ---- Sets the default value for the elem button, this may be a function or a string --- @tparam ?string|function value string a will be a static default and a function will be called when drawn to get the default --- @treturn the element define to allow for chaining -function ElemButton._prototype:set_default(value) - self.default = value - if type(value) ~= 'function' then - self.draw_data[self.draw_data.elem_type] = value - end - return self -end - -return ElemButton \ 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 671f11cb..00000000 --- a/expcore/gui/elements/progress-bar.lua +++ /dev/null @@ -1,390 +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(false,store_update), - add_sync_store = Prototype.store(true,store_update) - } -} - -Global.register({ - unregistered = ProgressBar.unregistered, - independent = ProgressBar.independent -},function(tbl) - ProgressBar.unregistered = tbl.unregistered - ProgressBar.independent = tbl.independent -end) - ---- Gets the define data, cant use Gui.get_define as it would error --- @tparam ?table|string define the define to get --- @treturn table the define or nil -local function get_define(define) - if type(define) == 'table' then - if define.name and Gui.defines[define.name] then - return Gui.defines[define.name] - end - end - - return Gui.defines[define] -end - ---- Gets the element data, used when there is no define --- @tparam LuaGuiElement element the element to get the data of --- @treturn table the element data similar to define -local function get_element(element) - if not element.valid then return end - local name = element.player_index..':'..element.index - - if ProgressBar.unregistered[name] then - return ProgressBar.unregistered[name] - end -end - ---- Sets the maximum value that represents the end value of the progress bar --- @tparam ?LuaGuiElement|string element either a gui element or a registered define --- @tparam number amount the amount to have set as the maximum -function ProgressBar.set_maximum(element,amount) - amount = amount > 0 and amount or error('amount must be greater than 0') - - local define = get_define(element) - if define then - define:set_default_maximum(amount) - - else - local element_data = get_element(element) - - if element_data then - element_data.maximum = amount - - else - local name = element.player_index..':'..element.index - ProgressBar.unregistered[name] = { - element=element, - maximum=amount or 1 - } - - end - - end -end - ---- Increases the value of the progressbar, if a define is given all of its instances have incremented --- @tparam ?LuaGuiElement|string element either a gui element or a registered define --- @tparam[opt=1] number amount the amount to increase the progressbar by -function ProgressBar.increment(element,amount) - amount = type(amount) == 'number' and amount or 1 - - local define = get_define(element) - if define then - define:increment(amount) - - else - local element_data = get_element(element) - - if element_data then - local real_amount = amount/element_data.maximum - element.value = element.value + real_amount - - if element.value >= 1 then - local name = element.player_index..':'..element.index - ProgressBar.unregistered[name] = nil - return true - end - end - - end -end - ---- Decreases the value of the progressbar, if a define is given all of its instances have decremented --- @tparam ?LuaGuiElement|string element either a gui element or a registered define --- @tparam[opt=1] number amount the amount to decrease the progressbar by -function ProgressBar.decrement(element,amount) - amount = type(amount) == 'number' and amount or 1 - - local define = get_define(element) - if define then - define:decrement(amount) - - else - local element_data = get_element(element) - - if element_data then - local real_amount = amount/element_data.maximum - element.value = element.value - real_amount - - if element.value <= 0 then - local name = element.player_index..':'..element.index - ProgressBar.unregistered[name] = nil - return true - end - end - - end -end - ---- Creates a new progressbar element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new progressbar element define -function ProgressBar.new_progressbar(name) - - local self = Gui.new_define(ProgressBar._prototype,name) - self.draw_data.type = 'progressbar' - - self:on_draw(function(player,element,maximum) - if self.store then - local category = self.categorize and self.categorize(element) or nil - local value = self:get_store(category) - if not value then - value = self.count_down and 1 or 0 - self:set_store(category,value) - end - element.value = value - - else - if self.count_down then - element.value = 1 - end - - if not ProgressBar.independent[self.name] then - ProgressBar.independent[self.name] = {} - end - - table.insert(ProgressBar.independent[self.name],{ - element = element, - maximum = maximum - }) - - end - - end) - - return self -end - ---- Sets the maximum value that represents the end value of the progress bar --- @tparam number amount the amount to have set as the maximum --- @treturn table the define to allow chaining -function ProgressBar._prototype:set_default_maximum(amount) - amount = amount > 0 and amount or error('amount must be greater than 0') - self.default_maximum = amount - return self -end - ---- Will set the progress bar to start at 1 and trigger when it hits 0 --- @tparam[opt=true] boolean state when true the bar will start filled, to be used with decrease --- @treturn table the define to allow chaining -function ProgressBar._prototype:use_count_down(state) - if state == false then - self.count_down = false - else - self.count_down = true - end - return self -end - ---- Main logic for changing the value of a progress bar, this only applies when its a registered define --- @tparam table self the define that is being changed --- @tparam number amount the amount which it is being changed by, may be negative --- @tparam[opt] string category the category to use with store --- @tparam[opt] function filter when given the filter must return true for the value of the element to be changed -local function change_value_prototype(self,amount,category,filter) - - local function reset_store() - local value = self.count_down and 1 or 0 - self:set_store(category,value) - end - - if self.store then - local value = self:get_store(category) or self.count_down and 1 or 0 - local maximum = self.default_maximum or 1 - local new_value = value + (amount/maximum) - - self:set_store(category,new_value) - - if self.count_down and new_value <= 0 - or not self.count_down and new_value >= 1 then - self:clear_store(category) - self:raise_event('on_store_complete',category,reset_store) - return - end - - return - end - - if ProgressBar.independent[self.name] then - for key,element_data in pairs(ProgressBar.independent[self.name]) do - local element = element_data.element - if not element or not element.valid then - ProgressBar.independent[self.name][key] = nil - - else - if not filter or filter(element) then - local maximum = element_data.maximum or self.default_maximum or 1 - element.value = element.value + (amount/maximum) - - if self.count_down and element.value <= 0 - or not self.count_down and element.value >= 1 then - ProgressBar.independent[self.name][key] = nil - event_call(self,element) - end - end - - end - end - end - -end - ---- Increases the value of the progressbar --- @tparam[opt=1] number amount the amount to increase the progressbar by --- @tparam[opt] string category the category that is used with a store -function ProgressBar._prototype:increment(amount,category) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,amount,category) -end - ---- Increases the value of the progressbar, if the filter condition is met, does not work with store --- @tparam[opt=1] number amount the amount to increase the progressbar by --- @tparam function filter the filter to be used -function ProgressBar._prototype:increment_filtered(amount,filter) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,amount,nil,filter) -end - ---- Decreases the value of the progressbar --- @tparam[opt=1] number amount the amount to decrease the progressbar by --- @tparam[opt] string category the category that is used with a store -function ProgressBar._prototype:decrement(amount,category) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,-amount,category) -end - ---- Decreases the value of the progressbar, if the filter condition is met, does not work with store --- @tparam[opt=1] number amount the amount to decrease the progressbar by --- @tparam function filter the filter to be used -function ProgressBar._prototype:decrement_filtered(amount,filter) - amount = type(amount) == 'number' and amount or 1 - change_value_prototype(self,-amount,nil,filter) -end - ---- Adds an element into the list of instances that will are waiting to complete, does not work with store --- note use store if you want persistent data, this only stores the elements not the values which they have --- @tparam LuaGuiElement element the element that you want to add into the waiting to complete list --- @tparam[opt] number maximum the maximum for this element if not given the default for this define is used -function ProgressBar._prototype:add_element(element,maximum) - if self.store then return end - if not ProgressBar.independent[self.name] then - ProgressBar.independent[self.name] = {} - end - table.insert(ProgressBar.independent[self.name],{ - element = element, - maximum = maximum - }) -end - ---- Resets an element, or its store, to be back at the start, either 1 or 0 --- @tparam LuaGuiElement element the element that you want to reset the progress of -function ProgressBar._prototype:reset_element(element) - if not element or not element.valid then return end - local value = self.count_down and 1 or 0 - if self.store then - local category = self.categorize and self.categorize(element) or value - self:set_store(category,value) - else - element.value = value - end -end - ---- Event handler factory that counts up by 1 every time the event triggers, can filter which elements have incremented --- @tparam[opt] function filter when given will use filtered increment --- @treturn function the event handler -function ProgressBar._prototype:event_counter(filter) - if type(filter) == 'function' then - return function() - self:increment_filtered(1,filter) - end - else - return function() - self:increment() - end - end -end - ---- Event handler factory that counts down by 1 every time the event triggers, can filter which elements have decremented --- @tparam[opt] function filter when given will use filtered decrement --- @treturn function the event handler -function ProgressBar._prototype:event_countdown(filter) - if type(filter) == 'function' then - return function() - self:decrement_filtered(1,filter) - end - else - return function() - self:decrement() - end - end -end - -return ProgressBar \ 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 110dd1bd..00000000 --- a/expcore/gui/elements/slider.lua +++ /dev/null @@ -1,177 +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(false,store_update), - add_sync_store = Prototype.store(true,store_update) - } -} - ---- Creates a new slider element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new slider element define -function Slider.new_slider(name) - - local self = Gui.new_define(Slider._prototype,name) - self.draw_data.type = 'slider' - - self:on_draw(function(player,element) - local min,max = element.get_slider_minimum(),element.get_slider_maximum() - - if type(self.min) == 'function' then - min = self.min(player,element) - end - - if type(self.max) == 'function' then - max = self.max(player,element) - end - - element.set_slider_minimum_maximum(min,max) - - if self.store then - local category = self.categorize and self.categorize(element) or nil - local value = self:get_store(category) - if value then element.slider_value = value end - end - - if self.auto_label then - self:draw_label(element.parent) - end - end) - - Gui.on_value_changed(self.name,function(event) - local element = event.element - local value = element.slider_value - - if self.store then - local category = self.categorize and self.categorize(element) or value - self:set_store(category,value) - - else - event_call(self,element,value) - - end - - end) - - return self -end - ---- Sets the range of a slider, if not used will use default values for a slider --- @tparam[opt] number min the minimum value that the slider can take --- @tparam[opt] number max the maximum value that the slider can take --- @treturn self the define to allow chaining -function Slider._prototype:set_range(min,max) - self.min = min - self.max = max - - if type(min) == 'number' then - self.draw_data.minimum_value = min - end - - if type(max) == 'number' then - self.draw_data.maximum_value = max - end - - return self -end - ---- Draws a new label and links its value to the value of this slider, if no store then it will only show one value per player --- @tparam LuaGuiElement element the parent element that the label will be drawn to --- @treturn LuaGuiElement the new label element so that styles can be applied -function Slider._prototype:draw_label(element) - local name = self.name..'-label' - if element[name] then return end - - local value = 0 - if self.store then - local category = self.categorize and self.categorize(element) or value - value = self:get_store(category) or 0 - end - - local new_element = element.add{ - name=name, - type='label', - caption=tostring(math.round(value,2)) - } - - local categorise = self.categorise or Gui.categorize_by_player - local category = categorise(new_element) - - Instances.unregistered_add_element(name,category,new_element) - - return new_element -end - ---- Enables auto draw of the label, the label will share the same parent element as the slider --- @tparam[opt=true] boolean state when false will disable the auto draw of the label --- @treturn self the define to allow chaining -function Slider._prototype:enable_auto_draw_label(state) - if state == false then - self.auto_label = false - else - self.auto_label = true - end - return self -end - -return Slider \ 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 406c4ea0..00000000 --- a/expcore/gui/elements/text.lua +++ /dev/null @@ -1,149 +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(false,store_update), - add_sync_store = Prototype.store(true,store_update) - }, - _prototype_box=Prototype.extend{ - on_element_update = Prototype.event, - on_store_update = Prototype.event, - add_store = Prototype.store(false,store_update), - add_sync_store = Prototype.store(true,store_update) - } -} - ---- Creates a new text field element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new text field element define -function Text.new_text_field(name) - - local self = Gui.new_define(Text._prototype_field,name) - self.draw_data.type = 'textfield' - - self:on_draw(function(player,element) - if self.selectable then - element.selectable = true - end - - if self.word_wrap then - element.word_wrap = true - end - - if self.read_only then - element.read_only = true - end - - if self.store then - local category = self.categorize and self.categorize(element) or nil - local value = self:get_store(category) - if value then element.text = value end - end - end) - - Gui.on_text_changed(self.name,function(event) - local element = event.element - local value = element.text - - if self.store then - local category = self.categorize and self.categorize(element) or value - self:set_store(category,value) - - else - self:raise_event('on_element_update',event.player,element,value) - - end - - end) - - return self -end - ---- Creates a new text box element define --- @tparam[opt] string name the optional debug name that can be added --- @treturn table the new text box element define -function Text.new_text_box(name) - local self = Text.new_text_field(name) - self.draw_data.type = 'text-box' - - local mt = getmetatable(self) - mt.__index = Text._prototype_box - - return self -end - ---- Sets the text box to be selectable --- @tparam[opt=true] boolean state when false will set the state to false --- @treturn self table the define to allow for chaining -function Text._prototype_box:set_selectable(state) - if state == false then - self.selectable = false - else - self.selectable = true - end - return self -end - ---- Sets the text box to have word wrap --- @tparam[opt=true] boolean state when false will set the state to false --- @treturn self table the define to allow for chaining -function Text._prototype_box:set_word_wrap(state) - if state == false then - self.word_wrap = false - else - self.word_wrap = true - end - return self -end - ---- Sets the text box to be read only --- @tparam[opt=true] boolean state when false will set the state to false --- @treturn self table the define to allow for chaining -function Text._prototype_box:set_read_only(state) - if state == false then - self.read_only = false - else - self.read_only = true - end - return self -end - -return Text \ No newline at end of file diff --git a/expcore/gui/instances.lua b/expcore/gui/instances.lua deleted file mode 100644 index 86fcd11f..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 categorise function which allows variants to be stored under one - name (like one for each force or player) - - -- categorise works in the same way as store categorise - -- so the function will world here but no value is stored only gui elements - Instances.register('score',Gui.categorize_by_force) - - Then when you draw the new element to a gui you will want to add the element to the group: - - Instances.add_element('score',new_element) - - Then when you want to get the instances you have two options; Instances.get_elements or Instances.apply_to_elements when you want loop - over the elements it is more efficient to use apply_to_elements: - - Instances.get_elements('score','player') -- returns all elements that were added with the 'player' category - Instances.apply_to_elements('score','player',function(element) -- runs the function on every valid element - element.caption = 0 - end) - - Note that if you don't give a categorise function then you don't need to give a category when getting the elements. - ->>>> Using unregistered instance groups - When using a registered group and the functions that go with them it is much simpler to use and more importantly includes error checking - for valid instance group names; the down side is that the group must be registered which can only be done during start-up and not during runtime. - To counter this there are two functions similar to those above in order to add and get instances but may lead to errors not being noticed due to - the error internal error checking being skipped to allow it to work. - - The main difference between the two groups of functions is that the category must always be present even if is nil; example below shows how a - instance group would work when registered vs unregistered: - - -- Registered with category - Instances.register('score',Gui.categorize_by_force) -- force_store will return the force name of an element - Instances.add_element('score',new_element) -- the new element is added to the category based on in force - Instances.apply_to_elements('score','player',function(element) - element.caption = '0' - end) -- gets all instances from the player force and sets the caption to 0 - - -- Unregistered with category - Instances.unregistered_add_element('score','player',new_element) -- adds the new element to the player category - Instances.unregistered_apply_to_elements('score','player',function(element) - element.caption = '0' - end) -- gets all instances from the player force and sets the caption to 0 - - -- Registered without category; note that category can just be ignored - Instances.register('score') -- all instances will be under one group with no categories - Instances.add_element('score',new_element) -- adds the new element to the instance list - Instances.apply_to_elements('score',function(element) - element.caption = '0' - end) -- gets all instances and sets the element caption to 0 - - -- Unregistered without category; note that category must be given as nil - Instances.unregistered_add_element('score',nil,new_element) -- adds the new element to a single group with no categories - Instances.unregistered_apply_to_elements('score',nil,function(element) - element.caption = '0' - end) -- gets all instances and sets the element caption to 0 - ->>>> Functions - Instances.has_categories(name) --- Returns if a instance group has a categorise function; must be registered - Instances.is_registered(name) --- Returns if the given name is a registered instance group - Instances.register(name,categorise) --- Registers the name of an instance group to allow for storing element instances - - Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered - Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered - Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid - - Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered - Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered -]] -local Global = require 'utils.global' --- @dep utils.global - -local Instances = { - categorise={}, - data={} -} -Global.register(Instances.data,function(tbl) - Instances.data = tbl -end) - ---- Returns if a instance group has a categorise function; must be registered --- @tparam string name the name of the instance group --- @treturn boolean true if there is a categorise function -function Instances.has_categories(name) - return type(Instances.categorise[name]) == 'function' -end - ---- Returns if the given name is a registered instance group --- @tparam string name the name of the instance group you are testing --- @treturn boolean true if the name is registered -function Instances.is_registered(name) - return Instances.categorise[name] ~= nil -end - ---- Registers the name of an instance group to allow for storing element instances --- @tparam string name the name of the instance group; must to unique --- @tparam[opt] function categorise function used to turn the element into a string --- categorise param - element LuaGuiElement - the gui element to be turned into a string --- categorise return - string - the category that the element will be added to like the player's name or force's name --- @treturn string the name that was added so it can be used as a variable -function Instances.register(name,categorise) - if _LIFECYCLE ~= _STAGE.control then - return error('Can only be called during the control stage', 2) - end - - if Instances.categorise[name] then - return error('Instances for '..name..' already exist.',2) - end - - categorise = type(categorise) == 'function' and categorise or true - - Instances.data[name] = {} - Instances.categorise[name] = categorise - - return name -end - ---- Adds an element to the instance group under the correct category; must be registered --- @tparam string name the name of the instance group to add the element to --- @tparam LuaGuiElement element the element to add the the instance group -function Instances.add_element(name,element) - if not Instances.categorise[name] then - return error('Invalid name for instance group: '..name,2) - end - - if Instances.has_categories(name) then - local category = Instances.categorise[name](element) - if not Instances.data[name][category] then Instances.data[name][category] = {} end - table.insert(Instances.data[name][category],element) - else - table.insert(Instances.data[name],element) - end -end - ---- Gets all element instances without first removing any invalid ones; used internally and must be registered --- @tparam string name the name of the instance group to get the instances of --- @tparam[opt] string category the category to get the instance from, not needed when no categorise function --- @treturn table the table of element instances of which some may be invalid -function Instances.get_elements_raw(name,category) - if not Instances.categorise[name] then - return error('Invalid name for instance group: '..name,2) - end - - if Instances.has_categories(name) then - return Instances.data[name][category] or {} - else - return Instances.data[name] - end -end - ---- Gets all valid element instances and has the option of running a callback on those that are valid --- @tparam string name the name of the instance group to get the instances of --- @tparam[opt] string category the category to get the instances of, not needed when no categorise function --- @tparam[opt] function callback when given the callback will be ran on all valid elements --- callback param - element LuaGuiElement - the current valid element --- @treturn table the table of element instances with all invalid ones removed -function Instances.get_valid_elements(name,category,callback) - if not Instances.categorise[name] then - return error('Invalid name for instance group: '..name,2) - end - - category = category or callback - local elements = Instances.get_elements_raw(name,category) - local categorise = Instances.has_categories(name) - - for key,element in pairs(elements) do - if not element or not element.valid then - elements[key] = nil - else - if categorise and callback then callback(element) - elseif category then category(element) end - end - end - - return elements -end -Instances.get_elements = Instances.get_valid_elements -Instances.apply_to_elements = Instances.get_valid_elements - ---- A version of add_element that does not require the group to be registered --- @tparam string name the name of the instance group to add the element to --- @tparam ?string|nil category the category to add the element to, can be nil but must still be given --- @tparam LuaGuiElement element the element to add to the instance group -function Instances.unregistered_add_element(name,category,element) - if not Instances.data[name] then Instances.data[name] = {} end - if category then - if not Instances.data[name][category] then Instances.data[name][category] = {} end - table.insert(Instances.data[name][category],element) - else - table.insert(Instances.data[name],element) - end -end - ---- A version of get_elements that does not require the group to be registered --- @tparam string name the name of the instance group to get the instances of --- @tparam ?string|nil category the category to get the instances of, can be nil but must still be given --- @tparam[opt] function callback when given will be called on all valid instances --- callback param - element LuaGuiElement - the current valid element --- @treturn table the table of element instances with all invalid ones removed -function Instances.unregistered_get_elements(name,category,callback) - local elements = Instances.data[name] - if elements and category then - elements = elements[category] - end - - if not elements then return {} end - - for key,element in pairs(elements) do - if not element or not element.valid then - elements[key] = nil - else - if callback then callback(element) end - end - end - - return elements -end -Instances.unregistered_apply_to_elements = Instances.runtime_get_elements - -return Instances \ No newline at end of file diff --git a/expcore/gui/prototype.lua b/expcore/gui/prototype.lua index 20624583..902aa4dc 100644 --- a/expcore/gui/prototype.lua +++ b/expcore/gui/prototype.lua @@ -3,309 +3,714 @@ @alias Prototype ]] ---- Prototype. --- Used to create new gui prototypes see elements and concepts --- @section prototype +--- Concept Base. +-- Functions that are used to make concepts +-- @section concept-base ---[[ - >>>> 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 Event = require 'utils.event' -- @dep utils.event +local Store = require 'expcore.store' -- @dep expcore.store +local Game = require 'utils.game' -- @dep utils.game +local Token = require 'utils.token' -- @dep utils.token - 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 +local Factorio_Events = {} +local Prototype = { + draw_callbacks = {}, + clone_callbacks = {}, + properties = {}, + factorio_events = {}, + events = {} +} - 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 +--- Acts as a gernal handler for any factorio event +local function factorio_event_handler(event) + local element = event.element + local rasied_event = event.name + local factorio_event_concepts = Factorio_Events[rasied_event] + if element then + if not element.valid then return end + local concept = factorio_event_concepts[element.name] + if concept then + for event_name, factorio_event in pairs(concept.factorio_events) do + if rasied_event == factorio_event then + concept:raise_event(event_name,event,true) + end + end + end - 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 + else + for _,concept in pairs(factorio_event_concepts) do + for event_name, factorio_event in pairs(concept.factorio_events) do + if rasied_event == factorio_event then + concept:raise_event(event_name,event,true) + end + end + end - 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 + end +end + +--[[-- Used to copy all the settings from one concept to another and removing links to the orginal +@tparam string concept_name the name of the new concept; must be unique +@treturn GuiConcept the base for building a custom gui +@usage-- Clones the base Button concept to make a alternative button +local custom_button = +Gui.get_concept(Gui.concepts.button):clone() ]] -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 Prototype:clone() + local concept = table.deep_copy(self) -local Constructor = {} -local Prototype = {} + -- Replace name of the concept + local uid = tostring(Token.uid()) + concept.name = uid + concept.debug_name = uid + concept.properties.name = uid ---- 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) + -- Remove all event handlers that were copied + concept.events = {} + for event_name,_ in pairs(self.events) do + concept.events[event_name] = {} + end + + -- Remakes even handlers for factorio + for _,factorio_event in pairs(concept.factorio_events) do + Factorio_Events[factorio_event][concept.name] = concept + end + + -- Remove all refrences to an instance store + if concept.instance_store then + concept.instance_store = nil + concept.get_instances = nil + concept.add_instance = nil + concept.update_instances = nil + end + + -- Remove all refrences to a data store + if concept.data_store then + concept.data_store = nil + concept.get_data = nil + concept.set_data = nil + concept.clear_data = nil + concept.update_data = nil + concept.on_data_store_update = nil + concept.events.on_data_store_update = nil + end + + -- Remove all refrences to a combined store + if concept.sync_instance then + concept.sync_instance = nil + concept.set_store_from_instance = nil + end + + -- Loop over all the clone defines, element is updated when a value is returned + for _,clone_callback in pairs(concept.clone_callbacks) do + local success, rtn = pcall(clone_callback,concept) + if not success then + error('Gui clone handler error with '..concept.debug_name..':\n\t'..rtn) + end + end + + return concept +end + +--[[-- Use to add your own callbacks to the clone function, for example adding to a local table +@tparam function clone_callback the function which is called with the concept to have something done to it +@treturn table self to allow chaining +@usage-- Adding concept to a local table +local buttons = {} +local button = +Gui.get_concept('Button') +:define_clone(function(concept) + buttons[concept.name] = concept +end) +]] +function Prototype:define_clone(clone_callback) + -- Check that it is a function that is being added + if type(clone_callback) ~= 'function' then + error('Draw define must be a function',2) + end + + -- Add the draw function + self.clone_callbacks[#self.clone_callbacks+1] = clone_callback + + return self +end + +--[[-- Used to save the concept to the main gui module to allow access from other files +@function Prototype:save_as +@tparam string save_name the new name of the concept +@usage-- Save a concept to allow access in another file +button:save_as('button') +@usage-- Access concept after being saved +Gui.concepts.button +Gui.get_concept('button') +]] +function Prototype:save_as(save_name) + -- over writen in core file + return self +end + +--[[-- Sets a debug name that can be used with error handlers +@tparam string name the name that will be used in error messages +@treturn self to allow chaining +@usage-- Set the debug name +unsaved_concept:debug('Example button') +]] +function Prototype:debug(name) + self.debug_name = name + return self +end + +--[[-- Adds a new event trigger to the concept which can be linked to a factorio event +@tparam string event_name the name of the event to add, must be unique, recomented to start with "on_" +@tparam[opt] defines.events factorio_event when given will fire the custom event when the factorio event is raised +@tparam[opt] function event_condition used to filter when a factorio event triggers the custom event; if the event contains a reference to an element then names are automatically filtered +@treturn GuiConcept to allow chaining of functions +@usage-- Adds an on_admin_clicked event to fire when ever an admin clicks the button +local custom_button = +Gui.get_concept('Button'):clone('CustomButton') +:new_event('on_admin_clicked',defines.events.on_gui_click,function(event) + return event.player.admin -- only raise custom event when an admin clicks the button +end) +]] +function Prototype:new_event(event_name,factorio_event,event_condition) + -- Check the event does not already exist + if self.events[event_name] then + error('Event is already defined',2) + end + +--[[-- Adds a custom event handler, replace with the name of the event +@function Prototype:on_custom_event +@tparam function handler the function which will recive the event +@treturn GuiConcept to allow chaining of functions +@usage-- When an admin clicks the button a message is printed +local custom_button = +Gui.get_concept('CustomButton') +:on_admin_clicked(function(event) + game.print(event.player.name..' pressed my admin button') +end) +]] + + -- Adds a handler table and the event handler adder, comment above not indented to look better in docs + self.events[event_name] = {} + self[event_name] = function(concept,handler) + if type(handler) ~= 'function' then + error('Event handler must be a function',2) end - local handlers = self.events[event_name] - if not handlers then - handlers = {} - self.events[event_name] = handlers + local handlers = concept.events[event_name] + handlers[#handlers+1] = handler + + return concept + end + + -- Adds the factorio event handler if this event is linked to one + if factorio_event then + self.factorio_events[event_name] = factorio_event + self.events[event_name].factorio_event_condition = event_condition + + local factorio_event_concepts = Factorio_Events[factorio_event] + if not factorio_event_concepts then + factorio_event_concepts = {} + Factorio_Events[factorio_event] = factorio_event_concepts + Event.add(factorio_event,factorio_event_handler) end - handlers[#handlers+1] = callback - return self + if not factorio_event_concepts[self.name] then + factorio_event_concepts[self.name] = self + end + end + + return self +end + +--[[-- Raises a custom event, folowing keys included automaticlly: concept, event name, game tick, player from player_index, element if valid +@tparam string event_name the name of the event that you want to raise +@tparam[opt={}] table event table containg data you want to send with the event, some keys already included +@tparam[opt=false] boolean from_factorio internal use, if the raise came from the factorio event handler +@usage-- Raising the custom event on_admin_clicked +local custom_button = +Gui.get_concept('CustomButton') + +-- Note that this is an example and would not work due it expecting a valid element for event.element +-- this will however work fine if you can provide all expected keys, or its not linked to any factorio event +custom_button:raise_event('on_admin_clicked',{ + player_index = game.player.index +}) +]] +function Prototype:raise_event(event_name,event,from_factorio) + -- Check that the event exists + if not self.events[event_name] then + error('Event is not defined',2) + end + + -- Setup the event table with automatic keys + event = event or {} + event.concept = self + event.name = event.name or event_name + event.tick = event.tick or game.tick + event.player = event.player_index and Game.get_player_by_index(event.player_index) or nil + if event.element and not event.element.valid then return end + + -- Get the event handlers + local handlers = self.events[event_name] + + -- If it is from factorio and the filter fails + if from_factorio and handlers.factorio_event_condition and not handlers.factorio_event_condition(event) then + return + end + + -- Trigger every handler + for _,handler in ipairs(handlers) do + local success, err = pcall(handler,event) + if not success then + error('Gui event handler error with '..self.debug_name..'/'..event_name..':\n\t'..err) + end end end ---- 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) +--[[-- Adds a new property to the concept, such as caption, tooltip, or some custom property you want to control +@tparam string property_name the name of the new property, must be unique +@tparam[opt] function setter_callback this function is called when set is called, if not provided then key in concept.properties is updated to new value +@tparam[opt] any default use this as the default value, will call the setter callback if defined +@treturn GuiConcept to allow chaining of functions +@usage-- Adding caption, sprite, and tooltip to the base button concept +local button = +Gui.get_concept('Button') +:new_property('tooltip') +:new_property('caption',nil,function(properties,value) + properties.caption = value + properties.sprite = nil + properties.type = 'button' +end) +:new_property('sprite',nil,function(properties,value) + properties.image = value + properties.caption = nil + properties.type = 'sprite-button' +end) +]] +function Prototype:new_property(property_name,setter_callback,default,...) + -- Check that the property does not already exist + if self.properties[property_name] then + error('Property is already defined',2) + end + + -- Check that setter is a function if present + if setter_callback and not type(setter_callback) == 'function' then + error('Setter callback must be a function') + end + +--[[-- Sets a new value for a property, triggers setter method if provided, replace with property name +@function Prototype:set_custom_property +@tparam any value the value that you want to set for this property +@treturn GuiConcept to allow chaining of functions +@usage-- Setting the caption on the base button concept after a cloning +local custom_button = +Gui.get_concept('Button') +:set_caption('Default Button') +@usage-- In our examples CustomButton is cloned from Button, this means the caption property already exists +-- note that what ever values that properties have at the time of cloning are also copied +local custom_button = +Gui.get_concept('CustomButton') +:set_caption('Custom Button') +]] + + self['set_'..property_name] = function(concept,value,...) + if setter_callback then + -- Call the setter method to update values if present + local success, err = pcall(setter_callback,concept.properties,value,...) + if not success then + error('Gui property handler error with '..concept.debug_name..'/'..property_name..':\n\t'..err) + end else - new_prototype[key] = value + -- Otherwise just update the key + concept.properties[property_name] = value end + + return concept end - for key,value in pairs(new_prototype) do - if value == Constructor.event then - new_prototype[key] = Constructor.event(key) - end + + -- If a default value if given then set the default value + if default ~= nil then + self['set_'..property_name](self,default,...) end - return new_prototype + + return self end ---- Creates a new function which adds a store to a gui define --- @tparam boolean sync if the function should create a synced store --- @tparam function callback the function called when needing to update the value of an element --- @treturn function the function that will add a store for this define -function Constructor.store(sync,callback) - --- Adds a store for the define that is shared between all instances of the define in the same category, categorize is a function that returns a string - -- @tparam self table the gui define being acted on - -- @tparam[opt] string location a unique location identifier, when omitted a uid location will be used, use when sync is set to true - -- @tparam[opt] function categorize function used to determine the category of a LuaGuiElement, when omitted all share one single category - -- categorize param - LuaGuiElement element - the element that needs to be converted - -- categorize return - string - a deterministic string that references to a category such as player name or force name - -- @treturn self the element define to allow chaining - return function(self,location,categorize) - if self.store then return end +--[[-- Used to define how the concept is turned into an ingame element or "instance" as we may refer to them +@tparam function draw_callback the function that will be called to draw/update the instance; this function must return the instance or the new acting instance +@treturn GuiConcept to allow chaining of functions +@usage-- Adding the draw define for the base button concept, we then return the element +local button = +Gui.get_concept('Button') +:define_draw(function(properties,parent,element) + -- Properties will include all the information that you need to draw the element + -- Parent is the parent element for the element, this may have been altered by previous draw functions + -- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function + -- You can also pass any other arguments that you want to this function from the draw call + if properties.type == 'button' then + element = parent.add{ + type = properties.type, + name = properties.name, + caption = properties.caption, + tooltip = properties.tooltip + } - if not sync then - categorize = location - location = Store.uid_location() + else + element = parent.add{ + type = properties.type, + name = properties.name, + sprite = properties.sprite, + tooltip = properties.tooltip + } + + end + + -- If you return element or parent then their values will be updated for the next draw function in the chain + -- It is best practice to always return the values if you have made any changes to them + return element, parent +end) +]] +function Prototype:define_draw(draw_callback) + -- Check that it is a function that is being added + if type(draw_callback) ~= 'function' then + error('Draw define must be a function',2) + end + + -- Add the draw function + self.draw_callbacks[#self.draw_callbacks+1] = draw_callback + + return self +end + +--[[ Used to define a draw callback that is ran before any other draw callbacks, see define_draw +@tparam function draw_callback the function that will be called to draw/update the instance; this function must return the instance or the new acting instance +@treturn GuiConcept to allow chaining of functions +@usage-- Placing a button into a flow +local button = +Gui.get_concept('Button') +:define_pre_draw(function(properties,parent,element) + -- Properties will include all the information that you need to draw the element + -- Parent is the parent element for the element, this may have been altered by previous draw functions + -- Element is the current element being made, this may have a nil value, if it is nil then this is the first draw function + -- You can also pass any other arguments that you want to this function from the draw call + parent = parent.add{ + type = 'flow' + } + + -- If you return element or parent then their values will be updated for the next draw function in the chain + -- It is best practice to always return the values if you have made any changes to them + return element, parent +end) +]] +function Prototype:define_pre_draw(draw_callback) + -- Check that it is a function that is being added + if type(draw_callback) ~= 'function' then + error('Draw define must be a function',2) + end + + -- Add the draw function + table.insert(self.draw_callbacks,1,draw_callback) + + return self +end + +--[[-- Calls all the draw functions in order to create this concept in game; will also store and sync the instance if stores are used +@tparam LuaGuiElement parent_element the element that the concept will use as a base +@treturn LuaGuiElement the element that was created and then passed though and returned by the draw functions +@usage-- Drawing the custom button concept +local custom_button = +Gui.get_concept('CustomButton') + +-- Note that the draw function from button was cloned, so unless we want to alter the base button we dont need a new draw define +custom_button:draw(game.player.gui.left) +]] +function Prototype:draw(parent_element,...) + local parent = parent_element + local element + + -- Loop over all the draw defines, element is updated when a value is returned + for _,draw_callback in pairs(self.draw_callbacks) do + local success, _element, _parent = pcall(draw_callback,self.properties,parent,element,...) + if success then + if _element then element = _element end + if _parent then parent = _parent end + elseif not success then + error('Gui draw handler error with '..self.debug_name..':\n\t'.._element) end + end - if Store.is_registered(location) then - return error('Location for store is already registered: '..location,2) + -- Adds the instance if instance store is used + if self.add_instance then + self.add_instance(element) + end + + -- Syncs the instance if there is a combined store + if self.sync_instance then + self.sync_instance(element) + end + + return element +end + +--- Concept Instances. +-- Functions that are used to make store concept instances +-- @section concept-instances + +--[[-- Adds an instance store to the concept; when a new instance is made it is stored so you can access it later +@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap +@treturn GuiConcept to allow chaining of functions +@usage-- Allowing storing instances of the custom button; stored by the players index +-- Note even thou this is a copy of Button; if Button had an instance store it would not be cloned over +local custom_button = +Gui.get_concept('CustomButton') +:define_instance_store(function(element) + return element.player_index -- The instances are stored based on player id +end) +]] +function Prototype:define_instance_store(category_callback) + self.instance_store = Store.register('gui_instances_'..self.name) + + local valid_category = category_callback and type(category_callback) == 'function' + local function get_category(category) + if type(category) == 'table' and type(category.__self) == 'userdata' then + return valid_category and category_callback(category) or nil + else + return category end + end - self.store = location - self.categorize = categorize +--[[-- Gets all insatnces in a category, category may be nil to return all +@function Prototype.get_instances +@tparam[opt] ?string|LuaGuiElement category the category to get, can only be nil if categories are not used +@treturn table a table which contains all the instances +@usage-- Getting all the instances of the player with index 1 +local custom_button = +Gui.get_concept('CustomButton') - Instances.register(self.name,self.categorize) +custom_button.get_instances(1) -- player index 1 +]] + function self.get_instances(category) + return Store.get(self.instance_store,get_category(category)) + end - Store.register(self.store,sync,function(value,category) - self:raise_event('on_store_update',value,category) +--[[-- Adds an instance to this concept, used automatically during concept:draw +@function Prototype.add_instance +@tparam LuaGuiElement element the element that will be added as an instance +@tparam[opt] string category the category to add this element under, if nil the category callback is used to assign one +@usage-- Adding an element as a instance for this concept, mostly for internal use +local custom_button = +Gui.get_concept('CustomButton') - if Instances.is_registered(self.name) then - Instances.apply_to_elements(self.name,category,function(element) - callback(self,element,value) - end) +custom_button.add_instance(element) -- normally not needed due to use in concept:draw +]] + function self.add_instance(element,category) + category = category or get_category(element) + if not valid_category then category = nil end + return Store.update(self.instance_store,category,function(tbl) + if type(tbl) ~= 'table' then + return {element} + else + table.insert(tbl,element) 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 +--[[-- Applies an update function to all instances, simialr use to what table.forEach would be +@function Prototype.update_instances +@tparam[opt] ?string|LuaGuiElement category the category to get, can only be nil if categories are not used +@tparam function update_callback the function which is called on each instance, recives other args passed to update_instances +@usage-- Changing the font color of all instances for player 1 +local custom_button = +Gui.get_concept('CustomButton') - 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) +custom_button.update_instances(1,function(element) + element.style.font_color = {r=1,g=0,b=0} +end) +]] + function self.update_instances(category,update_callback,...) + local args + if type(category) == 'function' then + args = {update_callback,...} + update_callback = category + category = nil end - if second_key then - self[key][second_key] = value + local instances = Store.get(self.instance_store,get_category(category)) or {} + for key,instance in pairs(instances) do + if not instance or not instance.valid then + instances[key] = nil + + else + if args then + update_callback(instance,unpack(args)) + else + update_callback(instance,...) + end + end + end + end + + return self +end + +--- Concept Data. +-- Functions that are used to store concept data +-- @section concept-data + +--[[-- Adds a data store to this concept which allows you to store synced/percistent data between instances +@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap +@treturn GuiConcept to allow chaining of functions +@usage-- Adding a way to store data for this concept; each player has their own store +-- Note even thou this is a copy of Button; if Button had an data store it would not be cloned over +local custom_button = +Gui.get_concept('CustomButton') +:define_data_store(function(element) + return element.player_index -- The data is stored based on player id +end) +]] +function Prototype:define_data_store(category_callback) + self:new_event('on_data_store_update') + self.data_store = Store.register('gui_data_'..self.name,function(value,key) + self:raise_event('on_data_store_update',{ + category = key, + value = value + }) + end) + + local valid_category = category_callback and type(category_callback) == 'function' + local function get_category(category) + if type(category) == 'table' and type(category.__self) == 'userdata' then + return valid_category and category_callback(category) or nil else - self[key] = value + return category 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 +--[[-- Gets the data that is stored for this category +@function Prototype.get_data +@tparam[opt] ?string|LuaGuiElement category the category to get, can only be nil if categories are not used +@treturn any the data that you had stored in this location +@usage-- Getting the stored data for player 1 +local custom_button = +Gui.get_concept('CustomButton') ---- 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) +custom_button.get_data(1) -- player index 1 +]] + function self.get_data(category) + return Store.get(self.data_store,get_category(category)) end + +--[[-- Sets the data that is stored for this category +@function Prototype.set_data +@tparam[opt] ?string|LuaGuiElement category the category to set, can only be nil if categories are not used +@tparam any value the data that you want to stored in this location +@usage-- Setting the data for player 1 to a table with two keys +local custom_button = +Gui.get_concept('CustomButton') + +-- A table is used to show correct way to use a table with self.update_data +-- but a table is not required and can be any data, however upvalues may cause desyncs +custom_button.set_data(1,{ + clicks = 0, + required_clicks = 100 +}) -- player index 1 +]] + function self.set_data(category,value) + return Store.set(self.data_store,get_category(category),value) + end + +--[[-- Clears the data that is stored for this category +@function Prototype.clear_data +@tparam[opt] ?string|LuaGuiElement category the category to clear, can only be nil if categories are not used +@usage-- Clearing the data for player 1 +local custom_button = +Gui.get_concept('CustomButton') + +custom_button.clear_data(1) -- player index 1 +]] + function self.clear_data(category) + return Store.clear(self.data_store,get_category(category)) + end + +--[[-- Updates the data that is stored for this category +@function Prototype.update_data +@tparam[opt] ?string|LuaGuiElement category the category to clear, can only be nil if categories are not used +@tparam function update_callback the function which is called to update the data +@usage-- Updating the clicks key in the concept data for player 1 +local custom_button = +Gui.get_concept('CustomButton') + +custom_button.update_data(1,function(tbl) + tbl.clicks = tbl.clicks + 1 -- here we are incrementing the clicks by 1 +end) -- player index 1 + +@usage-- Updating a value when a table is not used, alterative to get set +-- so for this example assume that we did custom_button.set_data(1,0) +custom_button.update_data(1,function(value) + return value + 1 -- here we are incrementing the value by 1, we may only be tracking clicks +end) -- player index 1 +]] + function self.update_data(category,update_callback,...) + return Store.update(self.data_store,get_category(category),update_callback,...) + end + return self 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 +--- Concept Combined Instances. +-- Functions that are used to make store concept instances and data +-- @section concept-instances + +--[[-- Used to add a both instance and data store which are linked together, new instances are synced to the current value, changing the stored value will change all instances +@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap +@tparam function sync_callback the function which is called to update an instance to match the store, this is called on all instances when concept.set_data or update_data is used +@treturn GuiConcept to allow chaining of functions +@usage-- Adding a check box which is a "global setting" synced between all players +local custom_button = +Gui.get_concept('checkbox'):clone('my_checkbox') +:set_caption('My Checkbox') +:set_tooltip('Clicking this check box will change it for everyone') +:on_state_changed(function(event) + local element = event.element + event.concept.set_data(element,element.state) -- Update the stored data to trigger an update of all other instances +end) +:define_combined_store(function(element,state) -- We could add a category function here if we wanted to + element.state = state or false -- Note that the value passed may be nil if there is no stored value and no default set +end) +]] +function Prototype:define_combined_store(category_callback,sync_callback) + if sync_callback == nil then + sync_callback = category_callback + category_callback = nil end + + self:define_data_store(category_callback) + self:define_instance_store(category_callback) + + -- Will update all instances when the data store updates + self:on_data_store_update(function(event) + self.update_instances(event.category,sync_callback,event.value) + end) + +--[[-- Will sync an instance to match the stored value based on the given sync callback +@function Prototype.sync_instance +@tparam LuaGuiElement element the element that you want to have update +@usage-- Setting the caption of this element to be the same as the stored value +local custom_button = +Gui.get_concept('CustomButton') + +-- Used internally when first draw and automatically when the store updates +custom_button.sync_instance(element) +]] + local properties = self.properties + function self.sync_instance(element) + local default = properties.default + local value = self.get_data(element) or type(default) == 'function' and default(element) or default + sync_callback(element,value) + end + return self end ---- Raises a custom event for this define, any number of params can be given --- @tparam string event_name the name of the event that you want to raise --- @tparam any ... any params that you want to pass to the event --- @treturn number the number of handlers that were registered -function Prototype:raise_event(event_name,...) - local handlers = self.events[event_name] - if handlers then - for _,handler in pairs(handlers) do - handler(...) - end - end - 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) - - if self.pre_authenticator then - if not self.pre_authenticator(player,self.name) then return end - end - - 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 - - local new_element = element.add(self.draw_data) - - self:raise_event('on_style_update',new_element.style) - - if self.post_authenticator then - new_element.enabled = self.post_authenticator(player,self.name) - end - - if Instances.is_registered(self.name) then - Instances.add_element(self.name,new_element) - end - - self:raise_event('on_draw',player,new_element) - - return new_element -end - ---- Gets the value in this elements store, category needed if categorize function used --- @tparam string category[opt] the category to get such as player name or force name --- @treturn any the value that is stored for this define -function Prototype:get_store(category) - if not self.store then return end - return Store.get(self.store,category) -end - ---- Sets the value in this elements store, category needed if categorize function used --- @tparam string category[opt] the category to get such as player name or force name --- @tparam any value the value to set for this define, must be valid for its type ie for checkbox etc --- @treturn boolean true if the value was set -function Prototype:set_store(category,value) - if not self.store then return end - return Store.set(self.store,category,value) -end - ---- Sets the value in this elements store to nil, category needed if categorize function used --- @tparam[opt] string category the category to get such as player name or force name --- @treturn boolean true if the value was set -function Prototype:clear_store(category) - if not self.store then return end - return Store.clear(self.store,category) -end - -return Constructor \ No newline at end of file +return Prototype \ No newline at end of file diff --git a/expcore/gui/test.lua b/expcore/gui/test.lua index 2e25c61b..e57b7ece 100644 --- a/expcore/gui/test.lua +++ b/expcore/gui/test.lua @@ -1,663 +1,717 @@ --[[-- Core Module - Gui @module Gui - @alias tests + @alias Gui ]] ---- 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 +--- Tests. +-- functions used to test +-- @section tests -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 Gui = require 'expcore.gui' +local Game = require 'utils.game' +local Event = require 'utils.event' +require 'expcore.toolbar' 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 +The main test frame ]] -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.require_concept('frame') -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' +local test_frame = +Gui.new_concept('frame') +:set_title('Gui Tests') +:define_draw(function(properties,parent,element) + for category, _ in pairs(tests) do + element.add{ + type = 'flow', + name = category, + 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 +Gui.new_concept('toolbar-button') +:set_permission_alias('gui-test') +:set_caption('Element Tests') +:on_click(function(event) + local player = event.player + if not Gui.destroy(player.gui.center[test_frame.name]) then + Gui.run_tests(event.player) + end end) -:set_open_by_default() -:on_creation(function(_player,frame) +local test_left_frame = +Gui.new_concept('toolbar-frame') +:set_permission_alias('gui-test') +:set_caption('Frame Test Left') +:define_draw(function(properties,parent,element) + local list_area = + element.add{ + name = 'scroll', + type = 'scroll-pane', + direction = 'vertical', + horizontal_scroll_policy = 'never', + vertical_scroll_policy = 'auto-and-reserve-space' + } + Gui.set_padding(list_area,1,1,2,2) + list_area.style.horizontally_stretchable = true + list_area.style.maximal_height = 200 + + -- Add player names for _,player in pairs(game.connected_players) do - frame.add{ + list_area.add{ + type='label', + caption=player.name + } + end +end) +:on_update(function(event) + local list_area = event.element.scroll + list_area.clear() + + -- Add player names + for _,player in pairs(game.connected_players) do + list_area.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') +Event.add(defines.events.on_player_joined_game,function(event) + test_left_frame:update_all(event) +end) +Event.add(defines.events.on_player_left_game,function(event) + test_left_frame:update_all(event) +end) + +--[[-- Runs a set of gui tests to ensure that the system is working +@tparam LuaPlayer player the player that the guis are made for and who recives the results +@tparam[opt] string category when given only tests in this category are ran +@usage-- Run all gui tests +Gui.run_tests(game.player) +]] +function Gui.run_tests(player,category) + local results = { + passed = 0, + failed = 0, + total = 0, + errors = {} + } + + if not category then + results.breakdown = {} + + for cat,_ in pairs(tests) do + local rtn = Gui.run_tests(player,cat) + results.passed = results.passed + rtn.passed + results.failed = results.failed + rtn.failed + results.total = results.total + rtn.total + + for test_name, err in pairs(rtn.errors) do + results.errors[cat..'/'..test_name] = err + end + + results.breakdown[cat] = rtn + end + + player.print(string.format('All Tests Complete. %d failed.',results.failed)) + + return results + end + + local frame = player.gui.center[test_frame.name] or test_frame:draw(player.gui.center) + local cat_tests = tests[category] + + results.total = #cat_tests + + local output = player.print + for test_name, concept in pairs(cat_tests) do + local success, err = pcall(concept.draw,concept,frame[category]) + + if success then + results.passed = results.passed + 1 + else + results.errors[test_name] = err + results.failed = results.failed + 1 + output(string.format('Test "%s / %s" failed:\n%s',category,test_name,err)) + end + + end + + output(string.format('Test Complete "%s". %d failed.',category,results.failed)) + + return results +end --[[ - Popup Test - > Allows opening a popup which contains the players name and tick it was opened +Buttons +> Basic Button -- Button with a caption and a tooltip +> Sprite Button -- Button with a single sprite and a tooltip +> Multi Sprite Button -- Button with three sprites and a tooltip +> Admin Button -- Button which is disabled if the player is not an admin ]] -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 - } +Gui.require_concept('button') + +local basic_button = +Gui.new_concept('button') +:debug('basic_button') +:set_caption('Basic Button') +:set_tooltip('Basic button') +:on_click(function(event) + event.player.print('You pressed basic button!') 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) +local sprite_button = +Gui.new_concept('button') +:debug('sprite_button') +:set_sprite('utility/warning_icon') +:set_tooltip('Sprite button') +:on_click(function(event) + event.player.print('You pressed sprite button!') 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)) +local multi_sprite_button = +Gui.new_concept('button') +:debug('multi_sprite_button') +:set_sprite('utility/warning_icon','utility/warning','utility/warning_white') +:set_tooltip('Multi-sprite button') +:on_click(function(event) + event.player.print('You pressed multi sprite 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') +local admin_button = +Gui.new_concept('button') +:debug('admin_button') +:set_caption('Admin Button') +:set_tooltip('Admin button') +:define_draw(function(properties,parent,element) + local player = Game.get_player_by_index(element.player_index) + if not player.admin then + element.enabled = false + element.tooltip = 'You must be admin to press this button' + end 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') +:on_click(function(event) + event.player.print('You pressed admin button!') end) tests.Buttons = { - ['No display']=button_no_display, - ['Caption']=button_with_caption, - ['Icons']=button_with_icon, - ['Auth']=button_with_auth + ['Basic Button'] = basic_button, + ['Sprite Button'] = sprite_button, + ['Multi Sprite Button'] = multi_sprite_button, + ['Admin Button'] = admin_button, } --[[ - 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 +Checkboxs +> Basic Checkbox -- Simple checkbox that can be toggled +> Game Stored Checkbox -- Checkbox which syncs its state between all players +> Force Stored Checkbox -- Checkbox which syncs its state with all players on the same force +> Player Stored Checkbox -- 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)) +Gui.require_concept('checkbox') + +local basic_checkbox = +Gui.new_concept('checkbox') +:debug('basic_checkbox') +:set_caption('Basic Checkbox') +:set_tooltip('Basic checkbox') +:on_state_changed(function(event) + event.player.print('Basic checkbox is now: '..tostring(event.element.state)) end) -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)) +local game_checkbox = +Gui.new_concept('checkbox') +:debug('game_checkbox') +:set_caption('Game Stored Checkbox') +:set_tooltip('Game stored checkbox') +:on_state_changed(function(event) + local element = event.element + event.concept.set_data(element,element.state) -- Update other instances + event.player.print('Game stored checkbox is now: '..tostring(element.state)) +end) +:define_combined_store(function(element,state) + element.state = state or false 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)) +local force_checkbox = +Gui.new_concept('checkbox') +:debug('force_checkbox') +:set_caption('Force Stored Checkbox') +:set_tooltip('Force stored checkbox') +:on_state_changed(function(event) + local element = event.element + event.concept.set_data(element,element.state) -- Update other instances + event.player.print('Force stored checkbox is now: '..tostring(element.state)) +end) +:define_combined_store(Gui.categorize_by_force,function(element,state) + element.state = state or false 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)) +local player_checkbox = +Gui.new_concept('checkbox') +:debug('player_checkbox') +:set_caption('Player Stored Checkbox') +:set_tooltip('Player stored checkbox') +:on_state_changed(function(event) + local element = event.element + event.concept.set_data(element,element.state) -- Update other instances + event.player.print('Player stored checkbox is now: '..tostring(element.state)) +end) +:define_combined_store(Gui.categorize_by_player,function(element,state) + element.state = state or false end) -tests.Checkboxes = { - ['Local']=checkbox_local, - ['Game store']=checkbox_game, - ['Force store']=checkbox_force, - ['Player store']=checkbox_player +tests.Checkboxs = { + ['Basic Checkbox'] = basic_checkbox, + ['Game Stored Checkbox'] = game_checkbox, + ['Force Stored Checkbox'] = force_checkbox, + ['Player Stored Checkbox'] = player_checkbox } --[[ - 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 +Dropdowns +> Static Dropdown -- Simple dropdown with all options being static +> Dynamic Dropdown -- Dropdown which has items based on when it is drawn +> Static Player Stored Dropdown -- Dropdown where the values is synced for each player +> Dynamic Player Stored Dropdown -- Same as above but now with dynamic options ]] -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)) +Gui.require_concept('dropdown') + +local static_dropdown = +Gui.new_concept('dropdown') +:debug('static_dropdown') +:set_static_items{'Option 1','Option 2','Option 3'} +:on_selection_changed(function(event) + local value = Gui.get_dropdown_value(event.element) + event.player.print('Static dropdown is now: '..value) end) -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('gui.test.share',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) +local dynamic_dropdown = +Gui.new_concept('dropdown') +:debug('dynamic_dropdown') +:set_dynamic_items(function(element) + local items = {} + for concept_name,_ in pairs(Gui.concepts) do + if concept_name:len() < 16 then + items[#items+1] = concept_name + end 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)) + return items +end) +:on_selection_changed(function(event) + local value = Gui.get_dropdown_value(event.element) + event.player.print('Dynamic dropdown is now: '..value) end) -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)) +local static_player_dropdown = +Gui.new_concept('dropdown') +:debug('static_player_dropdown') +:set_static_items{'Option 1','Option 2','Option 3'} +:on_selection_changed(function(event) + local element = event.element + local value = Gui.get_dropdown_value(element) + event.concept.set_data(element,value) + event.player.print('Static player stored dropdown is now: '..value) +end) +:define_combined_store(Gui.categorize_by_player,function(element,value) + Gui.set_dropdown_value(element,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)) +local dynamic_player_dropdown = +Gui.new_concept('dropdown') +:debug('dynamic_player_dropdown') +:set_dynamic_items(function(element) + local items = {} + for concept_name,_ in pairs(Gui.concepts) do + if concept_name:len() < 16 then + items[#items+1] = concept_name + end + end + return items 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)) +:on_selection_changed(function(event) + local element = event.element + local value = Gui.get_dropdown_value(element) + event.concept.set_data(element,value) + event.player.print('Dynamic player dropdown is now: '..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)) +:define_combined_store(Gui.categorize_by_player,function(element,value) + Gui.set_dropdown_value(element,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 + ['Static Dropdown'] = static_dropdown, + ['Dynamic Dropdown'] = dynamic_dropdown, + ['Static Player Stored Dropdown'] = static_player_dropdown, + ['Dynamic Player Stored Dropdown'] = dynamic_player_dropdown } --[[ - 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 +Listboxs +> Static Listbox -- Simple Listbox with all options being static +> Static Player Stored Listbox -- Listbox where the values is synced for each player ]] -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)) +local static_listbox = +Gui.new_concept('dropdown') +:debug('static_listbox') +:set_use_list_box(true) +:set_static_items{'Option 1','Option 2','Option 3'} +:on_selection_changed(function(event) + local value = Gui.get_dropdown_value(event.element) + event.player.print('Static listbox is now: '..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)) +local static_player_listbox = +Gui.new_concept('dropdown') +:debug('static_player_listbox') +:set_use_list_box(true) +:set_static_items{'Option 1','Option 2','Option 3'} +:on_selection_changed(function(event) + local element = event.element + local value = Gui.get_dropdown_value(element) + event.concept.set_data(element,value) + event.player.print('Static player stored listbox is now: '..value) +end) +:define_combined_store(Gui.categorize_by_player,function(element,value) + Gui.set_dropdown_value(element,value) end) -tests["List Boxes"] = { - ['Local']=list_box_local, - ['Player']=list_box_player +tests.Listboxs = { + ['Static Listbox'] = static_listbox, + ['Static Player Stored Listbox'] = static_player_listbox } --[[ - 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 +Elem Buttons +> Basic Elem Button -- Basic elem button +> Defaut Selection Elem Button -- Same as above but has a default selection +> Player Stored Elem Button -- Same as above but is stored per player ]] -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))) +Gui.require_concept('elem_button') + +local basic_elem_button = +Gui.new_concept('elem_button') +:debug('basic_elem_button') +:on_selection_changed(function(event) + event.player.print('Basic elem button is now: '..event.element.elem_value) 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))) +local default_selection_elem_button = +Gui.new_concept('elem_button') +:debug('default_selection_elem_button') +:set_elem_type('signal') +:set_default{type='virtual',name='signal-info'} +:on_selection_changed(function(event) + local value = event.element.elem_value + event.player.print('Default selection elem button is now: '..value.type..'/'..value.name) 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))) +local player_elem_button = +Gui.new_concept('elem_button') +:debug('player_elem_button') +:set_elem_type('technology') +:on_selection_changed(function(event) + local element = event.element + local value = element.elem_value + event.concept.set_data(element,value) + event.player.print('Player stored elem button is now: '..value) +end) +:define_combined_store(Gui.categorize_by_player,function(element,value) + element.elem_value = value 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 +tests['Elem Buttons'] = { + ['Basic Elem Button'] = basic_elem_button, + ['Defaut Selection Elem Button'] = default_selection_elem_button, + ['Player Stored Elem Button'] = player_elem_button +} + +--[[ +Progress Bars +> Basic Progress Bar -- will increse when pressed, when full then it will reset +> Inverted Progress Bar -- will increse when pressed, when empty then it will reset +> Game Instance Progress Bar -- will take 5 seconds to fill, when full it will reset, note instances are required due to on_tick +> Force Instance Progress Bar -- will increse when pressed, instance only means all instances will increse at same time but may not have the same value +> Force Stored Progress Bar -- will increse when pressed, unlike above all will increse at same time and will have the same value +]] + +Gui.require_concept('progress_bar') + +local basic_progress_bar = +Gui.new_concept('progress_bar') +:debug('basic_progress_bar') +:set_tooltip('Basic progress bar') +:set_maximum(5) +:new_event('on_click',defines.events.on_gui_click) +:on_click(function(event) + event.concept:increment(event.element) end) -:on_element_update(function(player,element,value,percent) - player.print('Slider dynamic range: '..tostring(math.round(value))..' '..tostring(math.round(percent,1))) +:set_delay_completion(true) +:on_completion(function(event) + event.concept:reset(event.element) 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))) +local inverted_progress_bar = +Gui.new_concept('progress_bar') +:debug('inverted_progress_bar') +:set_tooltip('Inverted progress bar') +:set_inverted(true) +:set_maximum(5) +:new_event('on_click',defines.events.on_gui_click) +:on_click(function(event) + event.concept:increment(event.element) +end) +:on_completion(function(event) + event.concept:reset(event.element) 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))) +local game_progress_bar = +Gui.new_concept('progress_bar') +:debug('game_progress_bar') +:set_tooltip('Game progress bar') +:set_maximum(300) +:new_event('on_tick',defines.events.on_tick) +:on_tick(function(event) + event.concept:increment(event.element) +end) +:set_delay_completion(true) +:on_completion(function(event) + event.concept:reset(event.element) +end) +:define_instance_store() + +local force_instance_progress_bar = +Gui.new_concept('progress_bar') +:debug('force_instance_progress_bar') +:set_tooltip('Force instance progress bar') +:set_maximum(5) +:new_event('on_click',defines.events.on_gui_click) +:on_click(function(event) + event.concept:increment(event.element) +end) +:set_delay_completion(true) +:on_completion(function(event) + event.concept:reset(event.element) +end) +:define_instance_store(Gui.categorize_by_force) + +local force_stored_progress_bar = +Gui.new_concept('progress_bar') +:debug('force_stored_progress_bar') +:set_tooltip('Force stored progress bar') +:set_maximum(5) +:new_event('on_click',defines.events.on_gui_click) +:on_click(function(event) + local element = event.element + local concept = event.concept + local new_value = concept:increment(element) + if new_value then concept.set_data(element,new_value) end +end) +:set_delay_completion(true) +:on_completion(function(event) + local element = event.element + local concept = event.concept + local new_value = concept:reset(element) + concept.set_data(element,new_value) +end) +:define_combined_store(Gui.categorize_by_force,function(element,value) + element.value = value or 0 +end) + +tests['Progress Bars'] = { + ['Basic Progress Bar'] = basic_progress_bar, + ['Inverted Progress Bar'] = inverted_progress_bar, + ['Game Instance Progress Bar'] = game_progress_bar, + ['Force Instance Progress Bar'] = force_instance_progress_bar, + ['Force Stored Progress Bar'] = force_stored_progress_bar +} + +--[[ +Sliders +> Basic Slider -- Just a basic slider with range 1 to 10 +> Interval Slider -- Same as above but can only be intergers +> Discrete Slider -- A discrete slider +> Dynamic Slider -- A slider which has a dynamic range +> Player Stored Slider -- Slider which stores the value per player, also goes 1 to 10 +]] + +Gui.require_concept('slider') + +local basic_slider = +Gui.new_concept('slider') +:debug('basic_slider') +:set_range(1,10) +:on_value_changed(function(event) + event.player.print('Basic slider is now: '..event.element.slider_value) +end) + +local interval_slider = +Gui.new_concept('slider') +:debug('interval_slider') +:set_range(1,10) +:set_value_step(1) +:on_value_changed(function(event) + event.player.print('Interval slider is now: '..event.element.slider_value) +end) + +local discrete_slider = +Gui.new_concept('slider') +:debug('discrete_slider') +:set_range(1,10) +:set_value_step(1) +:set_discrete_slider(true) +:on_value_changed(function(event) + event.player.print('Discrete slider is now: '..event.element.slider_value) +end) + +local dynamic_slider = +Gui.new_concept('slider') +:debug('dynamic_slider') +:set_range(function(element) + local player = Gui.get_player_from_element(element) + return 1, player.name:len() +end) +:set_value_step(1) +:set_discrete_slider(true) +:on_value_changed(function(event) + event.player.print('Dynamic slider is now: '..event.element.slider_value) +end) + +local player_slider = +Gui.new_concept('slider') +:debug('player_slider') +:set_range(1,10) +:set_value_step(1) +:set_discrete_slider(true) +:on_value_changed(function(event) + local element = event.element + local value = element.slider_value + event.concept.set_data(element,value) + event.player.print('Player stored slider is now: '..value) +end) +:define_combined_store(Gui.categorize_by_player,function(element,value) + element.slider_value = value or 0 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 + ['Basic Slider'] = basic_slider, + ['Interval Slider'] = interval_slider, + ['Discrete Slider'] = discrete_slider, + ['Dynamic Slider'] = dynamic_slider, + ['Player Stored Slider'] = player_slider } --[[ - 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 +Text Fields +> Basic Text Field -- Just a text field which text can be entered into +> Better Text Field -- Same as above but will clear on rmb and un forcus on confirmation +> Decimal Text Field -- Text field which accepts decimal values +> Password Text Field -- Text field which stars out the typed characters +> Player Stored Text Field - Same as basic but will store value per player ]] -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) +Gui.require_concept('text_field') + +-- Making a text field +local basic_text_field = +Gui.new_concept('text_field') +:debug('basic_text_field') +:set_tooltip('Basic text field') +:on_confirmation(function(event) + event.player.print('Basic text field is now: '..event.element.text) 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) +local better_text_field = +Gui.new_concept('text_field') +:debug('better_text_field') +:set_tooltip('Better text field') +:set_clear_on_rmb(true) +:set_lose_forcus(true) +:on_confirmation(function(event) + event.player.print('Better text field is now: '..event.element.text) end) -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) +local decimal_text_field = +Gui.new_concept('text_field') +:debug('decimal_text_field') +:set_tooltip('Decimal text field') +:set_is_decimal(true) +:on_confirmation(function(event) + event.player.print('Decimal text field is now: '..event.element.text) 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) +local password_text_field = +Gui.new_concept('text_field') +:debug('password_text_field') +:set_tooltip('Password text field') +:set_is_password(true) +:on_confirmation(function(event) + event.player.print('Password text field is now: '..event.element.text) end) -tests.Texts = { - ['Local field']=text_filed_local, - ['Store field']=text_filed_store, - ['Local box']=text_box_local, - ['Wrap box']=text_box_wrap +local player_text_field = +Gui.new_concept('text_field') +:debug('player_text_field') +:set_tooltip('Player stored text field') +:on_confirmation(function(event) + local element = event.element + local text = element.text + event.concept.set_data(element,text) + event.player.print('Player stored text field is now: '..text) +end) +:define_combined_store(Gui.categorize_by_player, function(element,value) + element.text = value or '' +end) + +tests['Text Fields'] = { + ['Basic Text Field'] = basic_text_field, + ['Better Text Field'] = better_text_field, + ['Decimal Text Field'] = decimal_text_field, + ['Password Text Field'] = password_text_field, + ['Player Stored Text Field'] = player_text_field } --[[ - 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 +Text Boxs +> Basic Text Box -- A text box that can not be edited +> Editible Text Box -- A text box that can be edited ]] -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) +Gui.require_concept('text_box') + +local basic_text_box = +Gui.new_concept('text_box') +:debug('basic_text_box') +:set_tooltip('Basic text box') +:set_default('I am the text that will show in the text box') +:define_draw(function(properties,parent,element) + element.style.height = 75 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) +local editible_text_box = +Gui.new_concept('text_box') +:debug('editible_text_box') +:set_tooltip('Editible text box') +:set_is_read_only(false) +:set_default('I am the text that will show in the text box') +:on_text_changed(function(event) + event.player.print('Editible text box is now: '..event.element.text) +end) +:define_draw(function(properties,parent,element) + element.style.height = 75 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_children(progressbar_two.store) - 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 +tests['Text Boxs'] = { + ['Basic Text Box'] = basic_text_box, + ['Editible Text Box'] = editible_text_box } \ No newline at end of file diff --git a/expcore/store.lua b/expcore/store.lua index 83d2ed26..5d3f80ce 100644 --- a/expcore/store.lua +++ b/expcore/store.lua @@ -4,121 +4,87 @@ @alias Store @usage ----- Basic Use - -- At the most basic level this allows for the naming of locations to store in the global table, the second feature is that you are - -- able to listen for updates of this value, which means that when ever the set function is called it will trigger the update callback. +-- The data store module is designed to be an alterative way to store data in the global table +-- each piece of data is stored at a location and optional key of that location +-- it is recomented that you use a local varible to store the location +local scenario_difficuly = Store.uid_location() +local team_scores = 'team-scores' - -- This may be useful when storing config values and when they get set you want to make sure it is taken care of, or maybe you want - -- to have a value that you can trigger an update of from different places. +-- Setting and getting data is then as simple as +-- note that when storing a table you must use Store.update +Store.set(scenario_difficuly,'Hard') +Store.set(team_scores,game.player.force.name,20) - -- This will register a new location called 'scenario.difficulty' - -- note that setting a start value is optional and we could take nil to mean normal - Store.register('scenario.difficulty',function(value) - game.print('The scenario difficulty has be set to: '..value) - end) +Store.get(scenario_difficuly) -- returns 'Hard' +Store.get(team_scores,game.player.force.name) -- returns 20 - -- This will set the value in the store to 'hard' and will trigger the update callback which will print a message to the game - Store.set('scenario.difficulty','hard') +Store.update(team_scores,game.player.force.name,function(value,key) + return value + 10 -- add 10 to the score +end) - -- This will return 'hard' - Store.get('scenario.difficulty') +-- The reason for using stores over global is the abilty to watch for updates +-- for stores to work you must register them, often at the end of the file +Store.register(scenario_difficuly,function(value) + game.print('Scenario difficulty has been set to: '..value) +end) - @usage ----- Using Children - -- One limitation of store is that all locations must be registered to avoid desyncs, to get round this issue "children" can be used. - -- When you set the value of a child it does not have its own update callback so rather the "parent" location which has been registered - -- will have its update value called with a second param of the name of that child. +Store.register(team_scores,function(value,key) + game.print('Team '..key..' now has a score of '..value) +end) - -- This may be useful when you want a value of each player or force and since you cant register every player at the start you must use - -- the players name as the child name. +-- This can be very powerful when working with data that can be changed for a number of locations +-- with this module you can enable any location to output its changes to a file +-- say we wanted team scores to be synced across servers or between saves +-- although you will need to set up a method of storing the data outside the game +Store.register(team_scores,true,function(value,key) + game.print('Team '..key..' now has a score of '..value) +end) - -- This will register the location 'scenario.score' where we plan to use force names as the child - Store.register('scenario.score',function(value,child) - game.print(child..' now has a score of '..value) - end) - - -- This will return nil, but will not error as children don't need to be registered - Store.get('scenario.score','player') - - -- This will set 'player' to have a value of 10 for 'scenario.score' and trigger the game message print - Store.set('scenario.score','player',10) - - -- This would be the similar to Store.get however this will return the names of all the children - Store.get_children('scenario.score') - - @usage ----- Using Sync - -- There is the option to use synced values which is the same as a normal value however you can combine this with an external script - -- which can read the output from 'script-output/log/store.log' and have it send rcon commands back to the game allowing for cross instance - -- syncing of values. - - -- This may be useful when you want to have a value change effect multiple instances or even if you just want a database to store values so - -- you can sync data between map resets. - - -- This example will register the location 'statistics.total-play-time' where we plan to use plan names as the child - -- note that the location must be the same across instances - Store.register('statistics.total-play-time',true,function(value,child) - game.print(child..' now has now played for '..value) - end) - - -- Use of set and are all the same as non synced but you should include from_sync as true - - @usage ----- Alternative method - -- Some people may prefer to use a variable rather than a string for formating reasons here is an example. Also for any times when - -- there will be little external input Store.uid_location() can be used to generate non conflicting locations, uid_location will also - -- be used if you give a nil location. - - local store_game_speed = - Store.register(function(value) - game.print('The game speed has been set to: '..value) - end) +-- If you want multiple handlers on one store location then you can register to the raw event +Event.add(Store.events.on_value_changed,function(event) + game.print('Store '..event.location..'/'..event.key..' was updated to: '..event.value) +end) ]] local Global = require 'utils.global' --- @dep utils.global local Event = require 'utils.event' --- @dep utils.event -local table_keys,write_json = ext_require('expcore.common','table_keys','write_json') --- @dep expcore.common +local table_keys,write_json,get_file_path = ext_require('expcore.common','table_keys','write_json','get_file_path') --- @dep expcore.common local Token = require 'utils.token' --- @dep utils.token local Store = { - data={}, registered={}, synced={}, callbacks={}, events = { - on_value_update=script.generate_event_name() + on_value_changed=script.generate_event_name() } } +local store_data = {} Global.register(Store.data,function(tbl) - Store.data = tbl + store_data = tbl end) local function error_not_table(value) if type(value) ~= 'table' then - error('Location is not a table can not use child locations',3) + error('Location is not a table can not use key locations',3) end end ---- Check for if a location is registered --- @tparam string location the location to test for --- @treturn boolean true if registered -function Store.is_registered(location) - return Store.registered[location] -end - ---- Returns a unique name that can be used for a store --- @treturn string a unique name -function Store.uid_location() - return tostring(Token.uid()) -end - ---- Registers a new location with an update callback which is triggered when the value updates --- @tparam[opt] string location string a unique that points to the data, string used rather than token to allow migration --- @tparam[opt] boolean synced when true will output changes to a file so it can be synced --- @tparam[opt] function callback when given the callback will be automatically registered to the update of the value --- @treturn string the location that is being used +--[[-- Registers a new location with an update callback which is triggered when the value updates +@tparam[opt] string location string a unique that points to the data, string used rather than token to allow migration +@tparam[opt=false] boolean synced when true will output changes to a file so it can be synced +@tparam[opt] function callback when given the callback will be automatically registered to the update of the value +@treturn string the location that is being used +@usage-- Registering a new store location +local store_id = Store.register() +@usage-- Registering a new store location, with custom update callback +local store_id = Store.uid_location() +Store.register(store_id,function(value,key) + game.print('Store '..store_id..'/'..key..' was updated to: '..value) +end) +]] function Store.register(location,synced,callback) if _LIFECYCLE ~= _STAGE.control then return error('Can only be called during the control stage', 2) @@ -136,125 +102,247 @@ function Store.register(location,synced,callback) location = type(location) == 'string' and location or Store.uid_location() if Store.registered[location] then - return error('Location is already registered', 2) + return error('Location '..location..' is already registered by '..Store.registered[location], 2) end - Store.registered[location] = true + Store.registered[location] = get_file_path(1) Store.synced[location] = synced and true or nil Store.callbacks[location] = callback or nil return location end ---- Gets the value stored at a location, this location must be registered --- @tparam string location the location to get the data from --- @tparam[opt] string child the child location if required --- @tparam[opt=false] boolean allow_unregistered when true no error is returned if the location is not registered --- @treturn any the data which was stored at the location -function Store.get(location,child,allow_unregistered) - if not Store.callbacks[location] and not allow_unregistered then +--[[-- Gets the value stored at a location, this location must be registered +@tparam string location the location to get the data from +@tparam[opt] string key the key location if used +@treturn any the data which was stored at the location +@usage-- Getting the data at a store location +local data = Store.get(store_id_no_keys) +local data = Store.get(store_id_with_keys,'key_one') +]] +function Store.get(location,key) + if not Store.registered[location] then return error('Location is not registered', 2) end - local data = Store.data[location] - if child and data then + local data = store_data[location] + if key and data then error_not_table(data) - return data[child] + return data[key] end return data end ---- Sets the value at a location, this location must be registered --- @tparam string location the location to set the data to --- @tparam[opt] string child the child location if required --- @tparam any value the new value to set at the location, value may be reverted if there is a watch callback, cant be nil --- @tparam[opt] boolean from_sync set this true to avoid an output to the sync file --- @treturn boolean true if it was successful -function Store.set(location,child,value,from_sync) - if not Store.callbacks[location] then - return error('Location is not registered', 2) +--[[-- Sets the value at a location, this location must be registered +@tparam string location the location to set the data to +@tparam[opt] string key the key location if used +@tparam any value the new value to set at the location, value may be reverted if there is a watch callback, cant be nil +@tparam[opt=false] boolean from_sync set this true to avoid an output to the sync file +@tparam[opt=false] boolean from_internal set this true to add one to the error stack offset +@treturn boolean true if it was successful +@usage-- Setting the data at a store location +Store.set(store_id_no_keys,'Hello, World!') +Store.set(store_id_with_keys,'key_one','Hello, World!') +]] +function Store.set(location,key,value,from_sync,from_internal) + if not Store.registered[location] then + return error('Location is not registered', from_internal and 3 or 2) end - if child == nil or value == nil then - value = child or value - child = nil + if value == nil then + value = key + key = nil end - local data = Store.data - if child then - data = data[location] + if key then + local data = store_data[location] if not data then data = {} - Store.data[location] = data + store_data[location] = data end error_not_table(data) - data[child] = value + data[key] = value else - data[location] = value + store_data[location] = value end - script.raise_event(Store.events.on_value_update,{ + script.raise_event(Store.events.on_value_changed,{ tick=game.tick, location=location, - child=child, + key=key, value=value, - from_sync=from_sync + from_sync=from_sync or false }) return true end ---- Sets the value at a location to nil, this location must be registered --- @tparam string location the location to set the data to --- @tparam[opt] string child the child location if required --- @tparam[opt] boolean from_sync set this true to avoid an output to the sync file --- @treturn boolean true if it was successful -function Store.clear(location,child,from_sync) +--[[-- Allows for updating a value based on the current value; only valid way to change tables in a store +@tparam string location the location to set the data to +@tparam[opt] string key the key location if required +@tparam[opt] function update_callback the function called to update the value stored, rtn value to set new value +@usage-- Updating a value stored at a location +Store.update(store_id_no_keys,function(value) + return value + 1 +end) +Store.update(store_id_with_keys,'key_one',function(value) + return value + 1 +end) +@usage-- Updating a table stored at a location +Store.update(store_id_no_keys,function(value) + value.ctn = value.ctn + 1 +end) +Store.update(store_id_with_keys,'key_one',function(value) + value.ctn = value.ctn + 1 +end) +]] +function Store.update(location,key,update_callback,...) + local value = Store.get(location,key) + + local args + if type(key) == 'function' then + args = {update_callback,...} + update_callback = key + key = nil + end + + local rtn + if update_callback and type(update_callback) == 'function' then + if args then + rtn = update_callback(value,key,unpack(args)) + else + rtn = update_callback(value,key,...) + end + end + + if rtn then + Store.set(location,key,rtn,nil,true) + else + script.raise_event(Store.events.on_value_changed,{ + tick=game.tick, + location=location, + key=key, + value=value, + from_sync=false + }) + end + +end + +--[[-- Allows for updating all values at a location based on the current value; only valid way to change tables in a store +@tparam string location the location to set the data to +@tparam[opt] function update_callback the function called to update the value stored +@usage-- Updating all values at a location +Store.update(store_id_with_keys,function(value) + return value + 1 +end) +@usage-- Updating all tables at a location +Store.update(store_id_with_keys,function(value) + value.ctn = value.ctn + 1 +end) +]] +function Store.update_all(location,update_callback,...) + local data = Store.get(location) + + error_not_table(data) + + for key,value in pairs(data) do + local rtn + if update_callback and type(update_callback) == 'function' then + rtn = update_callback(value,key,...) + end + + if rtn then + Store.set(location,key,rtn,nil,true) + else + script.raise_event(Store.events.on_value_changed,{ + tick=game.tick, + location=location, + key=key, + value=value, + from_sync=false + }) + end + end + +end + +--[[-- Sets the value at a location to nil, this location must be registered +@tparam string location the location to set the data to +@tparam[opt] string key the key location if used +@tparam[opt=false] boolean from_sync set this true to avoid an output to the sync file +@treturn boolean true if it was successful +@usage-- Clear the data at a location +Store.clear(store_id_no_keys) +Store.clear(store_id_with_keys,'key_one') +]] +function Store.clear(location,key,from_sync) if not Store.callbacks[location] then return error('Location is not registered', 2) end - local data = Store.data - if child then - data = data[location] + if key then + local data = store_data[location] if not data then return end error_not_table(data) - data[child] = nil + data[key] = nil else - data[location] = nil + store_data[location] = nil end - script.raise_event(Store.events.on_value_update,{ + script.raise_event(Store.events.on_value_changed,{ tick=game.tick, location=location, - child=child, - from_sync=from_sync + key=key, + from_sync=from_sync or false }) return true end ---- Gets all non nil children at a location, children can be added and removed during runtime --- this is similar to Store.get but will always return a table even if it is empty --- @tparam string location the location to get the children of --- @treturn table a table containing all the children names -function Store.get_children(location) +--[[-- Gets all non nil keys at a location, keys can be added and removed during runtime +this is similar to Store.get but will always return a table even if it is empty +@tparam string location the location to get the keys of +@treturn table a table containing all the keys names +@usage-- Get all keys at a store location +local keys = Store.get_keys(store_id_with_keys) +]] +function Store.get_keys(location) local data = Store.get(location) return type(data) == 'table' and table_keys(data) or {} end +--[[-- Check for if a location is registered +@tparam string location the location to test for +@treturn boolean true if registered +@usage-- Check that a store is registered +local registerd = Store.is_registered(store_id) +]] +function Store.is_registered(location) + return Store.registered[location] +end + +--[[-- Returns a unique name that can be used for a store +@treturn string a unique name +@usage-- Get a new unique store id +local store_id = Store.uid_location() +]] +function Store.uid_location() + return tostring(Token.uid()) +end + -- Handles syncing -Event.add(Store.events.on_value_update,function(event) +Event.add(Store.events.on_value_changed,function(event) if Store.callbacks[event.location] then - Store.callbacks[event.location](event.value,event.child) + Store.callbacks[event.location](event.value,event.key) end if not event.from_sync and Store.synced[event.location] then write_json('log/store.log',{ tick=event.tick, location=event.location, - child=event.child, + key=event.key, value=event.value, }) end diff --git a/expcore/toolbar.lua b/expcore/toolbar.lua new file mode 100644 index 00000000..da1b5d16 --- /dev/null +++ b/expcore/toolbar.lua @@ -0,0 +1,495 @@ +--[[-- Core Module - Toolbar + @core Toolbar + @alias Toolbar +]] + +local Gui = require 'expcore.gui' --- @dep expcore.gui +local Roles = require 'expcore.roles' --- @dep expcore.roles +local Event = require 'utils.event' --- @dep utils.event +local Game = require 'utils.game' --- @dep utils.game +local mod_gui = require 'mod-gui' --- @dep mod-gui + +Gui.require_concept('button') --- @dep Gui.concept.button + +local toolbar_toggle_concept +local toolbar_hide_concept +local toolbar_concept +local Toolbar = { + button_concepts = {}, + frame_concepts = {}, + permissions = {} +} + +Gui.Toolbar = Toolbar + +--- Permissions. +-- Functions to do with deciding which player can do what +-- @section permissions + +--[[-- Used to test if a player is allowed to use a button on the toolbar, if you are not using expcore.roles then change this function +@tparam LuaPlayer player the player you want ot test is allowed to use this button +@tparam string concept_name the name of the button concept that you want to see if the player is allowed to use +@treturn boolean true if the player is allowed to use it +@usage-- Test if a player can use 'test-player-list' +local allowed = Toolbar.allowed(game.player,'test-player-list') +]] +function Toolbar.allowed(player,concept_name) + local permission = Toolbar.permissions[concept_name] or concept_name + return Roles.player_allowed(player,permission) +end + +--[[-- Use to add an alias for the allowed test, alias is what is tested for rather than the concept name +@tparam string concept_name the name of the concept that will point to this alias +@tparam string alias the permission string that will be tested when this concept is used with Toolbar.allowed +@usage-- Adding an alias for the 'test-player-list' concept +Toolbar.set_permission_alias('test-player-list','gui/player-list') +]] +function Toolbar.set_permission_alias(concept_name,alias) + Toolbar.permissions[concept_name] = alias +end + +--- Buttons. +-- All function to do with the toolbar buttons +-- @section buttons + +--[[-- Adds a concept to be drawn to the button area and allows it to be toggled with the toggle toolbar button +@tparam table concept the gui concept that you want to add to the button area +@usage-- Adding a basic button to the toolbar +local new_button = +Gui.new_concept('button') +:set_caption('Click Me') +:on_click(function(event) + event.player.print('You Clicked Me!!') +end) + +Toolbar.add_button_concept(new_button) +]] +function Toolbar.add_button_concept(concept) + local concepts = Toolbar.button_concepts + concepts[#concepts+1] = concept +end + +--[[-- Updates all the buttons for a player, this means hide and show buttons based on permissions +@tparam LuaPlayer player the player to update the toolbar buttons for +@usage-- Updating your toolbar +Toolbar.update_buttons(player) +]] +function Toolbar.update_buttons(player) + toolbar_concept:raise_event('on_button_update',{ + player_index = player.index + }) +end + +--[[-- Returns an array of buttons names that the given player is able to see, returns none if toolbar hidden +@tparam LuaPlayer player the player you want to get the visible buttons of +@treturn table an array of names of the visible buttons +@usage-- Get a list of all your visible buttons +Toolbar.get_visible_buttons(game.player) +]] +function Toolbar.get_visible_buttons(player) + local rtn = {} + local top_flow = mod_gui.get_button_flow(player) + + for _,concept in pairs(Toolbar.button_concepts) do + local element = top_flow[concept.name] + if element.visible then + rtn[#rtn+1] = element.name + end + end + + return rtn +end + +--[[-- The base element to be used with the toolbar, others can be used but this is recomented +@element toolbar-button + +@tparam string permission_alias the alias used with Toolbar.allowed + +@usage-- Adding a basic button to the toolbar, note no need to call Toolbar.add_button_concept +Gui.new_concept('toolbar-button') +:set_caption('Click Me') +:on_click(function(event) + event.player.print('You Clicked Me!!') +end) + +]] +Toolbar.button = +Gui.new_concept('button') +:save_as('toolbar-button') + +:new_property('permission_alias',nil,function(properties,value) + Toolbar.set_permission_alias(properties.name,value) +end) + +:define_clone(Toolbar.add_button_concept) +:define_draw(function(properties,parent,element) + element.style = mod_gui.button_style +end) + +--- Frames. +-- Functions to do with the toolbar frames +-- @section frames + +--[[-- Adds a frame concept to the toolbar frame area, this will not add a button to the toolbar +@tparam table concept the gui concept that you want to add to the toolbar frame area +@usage-- Adding a basic frame to the frame area +local new_frame = +Gui.new_concept('frame') +:set_title('Test') + +Toolbar.add_frame_concept(new_frame) +]] +function Toolbar.add_frame_concept(concept) + local concepts = Toolbar.frame_concepts + concepts[#concepts+1] = concept +end + +--[[-- Hides all the frames for a player +@tparam LuaPlayer player the player to hide the frames for +@usage-- Hiding all your frames +Toolbar.hide_frames(game.player) +]] +function Toolbar.hide_frames(player) + toolbar_concept:raise_event('on_hide_frames',{ + player_index = player.index + }) +end + +--[[-- Gets an array of the names of all the visible frames for a player +@tparam LuaPlayer player the player that you want to get the visible frames of +@treturn table an array of names of the visible frames for the given player +@usage-- Get all your visible frames +Toolbar.get_visible_frames(game.player) +]] +function Toolbar.get_visible_frames(player) + local rtn = {} + local left_flow = mod_gui.get_frame_flow(player) + + for _,concept in pairs(Toolbar.frame_concepts) do + local element = left_flow[concept.name..'-frame'] + if element.visible then + rtn[#rtn+1] = element.name + end + end + + left_flow[toolbar_hide_concept.name].visible = #rtn > 0 + + return rtn +end + +--[[-- The base toolbar frame, others can be used but this is recomented +@element toolbar-frame + +@param on_update fired when the frame is to have its content updated + +@tparam boolean open_by_default weather the frame should be open when a player first joins +@tparam boolean use_container true by default and will place a container inside the frame for content +@tparam string direction the direction that the items in the frame are added + +@usage-- Adding a basic player list +local player_list = +Gui.new_concept('toolbar-frame') +:set_permission_alias('player_list') +:set_caption('Player List') +:toggle_with_click() + +:define_draw(function(properties,parent,element) + local list_area = + element.add{ + name = 'scroll', + type = 'scroll-pane', + direction = 'vertical', + horizontal_scroll_policy = 'never', + vertical_scroll_policy = 'auto-and-reserve-space' + } + Gui.set_padding(list_area,1,1,2,2) + list_area.style.horizontally_stretchable = true + list_area.style.maximal_height = 200 + + for _,player in pairs(game.connected_players) do + list_area.add{ + type='label', + caption=player.name + } + end +end) + +:on_update(function(event) + local list_area = event.element.scroll + list_area.clear() + + for _,player in pairs(game.connected_players) do + list_area.add{ + type='label', + caption=player.name + } + end +end) + +]] +Toolbar.frame = +Gui.new_concept('toolbar-button') +:save_as('toolbar-frame') + +-- Properties +:new_property('open_by_default',false) +:new_property('use_container',true) +:new_property('direction','horizontal') +:new_event('on_update') + +-- Clone +:define_clone(function(concept) + Toolbar.add_frame_concept(concept) + concept:on_click(function(event) + event.concept:toggle_visible_state(event.player) + end) +end) + +-- Draw +:define_draw(function(properties,parent,element) + -- Add the base frame element, the button is already drawn to parent + local player = Gui.get_player_from_element(element) + local left_flow = mod_gui.get_frame_flow(player) + local frame = left_flow.add{ + name = properties.name..'-frame', + type = 'frame', + direction = properties.direction + } + + frame.style.padding = 2 + + -- Add and return the container if a container is used + if properties.use_container then + local container = + frame.add{ + name = 'container', + type = 'frame', + direction = properties.direction, + style = 'window_content_frame_packed' + } + Gui.set_padding(container) + + return container + + end + + return frame +end) + +--[[-- Gets the content area of the frame concept for this player, each player only has one area +@tparam LuaPlayer player the player that you want to get the frame content for +@treturn LuaGuiElement the content area of this concept for this player +@usage-- Get the content area of a concept +local frame = player_list:get_content(game.player) +]] +function Toolbar.frame:get_content(player) + local left_flow = mod_gui.get_frame_flow(player) + local frame = left_flow[self.name..'-frame'] + return frame.container or frame +end + +--[[-- Toggles the visibilty of this concept for the given player +@tparam LuaPlayer player the player that you want to toggle the frame for +@treturn boolean the new state of the visibilty of this concept for the player +@usage-- Toggle the frame for your self +player_list:toggle_visible_state(game.player) +]] +function Toolbar.frame:toggle_visible_state(player) + local left_flow = mod_gui.get_frame_flow(player) + local frame = left_flow[self.name..'-frame'] + if frame.visible then + frame.visible = false + Toolbar.get_visible_frames(player) + return false + else + frame.visible = true + Toolbar.get_visible_frames(player) + return true + end +end + +--[[-- Gets the current visibilty state of this conept for this player +@tparam LuaPlayer player the player that you want the visibilty state for +@treturn boolean the current visiblity state of this concept to the player +@usage-- Getting the current visiblity state +player_list:get_visible_state(player)]] +function Toolbar.frame:get_visible_state(player) + local left_flow = mod_gui.get_frame_flow(player) + return left_flow[self.name..'-frame'].visible +end + +--[[-- Triggers an update of the content within the concept for this player, uses on_update handlers +@tparam LuaPlayer player the player to update the concept content for +@tparam[opt] table event the event data that you want to pass to the update handlers +@usage-- Updating the frame for your player +player_list:update(game.player) +]] +function Toolbar.frame:update(player,event) + event = event or {} + event.player_index = player.index + event.element = self:get_content(player) + self:raise_event('on_update',event) +end + +--[[-- Triggers an update of the content with in this frame for all players +@tparam[opt] table event the event data that you want to pass to the update handlers +@usage-- Update the grame for all players +player_list:update_all() +]] +function Toolbar.frame:update_all(event) + local players = event.update_offline == true and game.players or game.connected_players + for _,player in pairs(players) do + self:update(player) + end +end + +--- Other Elements. +-- All the other elements that are used to make this work +-- @section elements + +--[[-- The main toolbar element, draws, updates, and controls the other concepts +@element toolbar +@param on_button_update fired when the buttons are updated for a player +@param on_hide_frames fired when the frames are hidden for a player +]] +toolbar_concept = +Gui.new_concept() +:debug('toolbar') +:define_draw(function(properties,player) + -- Get the main flows + local top_flow = mod_gui.get_button_flow(player) + if not top_flow then return end + local left_flow = mod_gui.get_frame_flow(player) + if not left_flow then return end + + -- Draw toggle buttons first + toolbar_toggle_concept:draw(top_flow) + toolbar_hide_concept:draw(left_flow) + + -- Draw all the buttons and frames + local done = {} + for _,concept in pairs(Toolbar.button_concepts) do + done[concept.name] = true + concept:draw(top_flow) + top_flow[concept.name].visible = Toolbar.allowed(player,concept.name) + + local frame = left_flow[concept.name..'-frame'] + if frame then + frame.visible = Gui.resolve_property(concept.properties.open_by_default,frame) + end + end + + -- Draws frames that did not have buttons + for _,concept in pairs(Toolbar.frame_concepts) do + if not done[concept.name] then + concept:draw(left_flow) + local frame = left_flow[concept.name..'-frame'] + if frame then + frame.visible = Gui.resolve_property(concept.properties.open_by_default,frame) + end + end + end + + -- Toggle the clear toobar if needed + Toolbar.get_visible_frames(player) + +end) + +-- When the buttons are updated +:new_event('on_button_update') +:on_button_update(function(event) + -- Get the top flow + local player = event.player + local top_flow = mod_gui.get_button_flow(player) + if not top_flow then return end + + -- Set the visiblity of the elements + local visible = top_flow[toolbar_toggle_concept.name].caption == '<' + for _,concept in pairs(Toolbar.button_concepts) do + local element = top_flow[concept.name] + if Gui.valid(element) then + element.visible = visible and Toolbar.allowed(player,concept.name) + end + end + +end) + +-- When frames are hidden +:new_event('on_hide_frames') +:on_hide_frames(function(event) + -- Get the left flow + local player = event.player + local left_flow = mod_gui.get_frame_flow(player) + if not left_flow then return end + + -- Set the visiblity of the elements + left_flow[toolbar_hide_concept.name].visible = false + for _,concept in pairs(Toolbar.frame_concepts) do + local element = left_flow[concept.name..'-frame'] + if Gui.valid(element) then element.visible = false end + end +end) + +--- Used so toggle and hide can have the same look as each other +local function toolbar_button_draw(properties,parent,element) + element.style = mod_gui.button_style + local style = element.style + style.width = 18 + style.height = 36 + style.padding = 0 + style.left_padding = 1 + style.font = 'default-small-bold' +end + +--[[-- Button which toggles the the visible state of all toolbar buttons, triggers on_button_update +@element toolbar-toggle +]] +toolbar_toggle_concept = +Gui.new_concept('button') +:set_caption('<') +:set_tooltip{'gui_util.button_tooltip'} +:define_draw(toolbar_button_draw) +:on_click(function(event) + local element = event.element + element.caption = element.caption == '<' and '>' or '<' + toolbar_concept:raise_event('on_button_update',{ + player_index = event.player_index + }) +end) + +--[[-- Button which hides all visible toolbar frames, triggers on_hide_frames +@element toolbar-clear +]] +toolbar_hide_concept = +Gui.new_concept('button') +:set_caption('<') +:set_tooltip{'expcore-gui.left-button-tooltip'} +:define_draw(toolbar_button_draw) +:on_click(function(event) + event.element.visible = false + toolbar_concept:raise_event('on_hide_frames',{ + player_index = event.player_index + }) +end) + +--- When there is a new player they will have the toolbar update +Event.add(defines.events.on_player_created,function(event) + local player = Game.get_player_by_index(event.player_index) + toolbar_concept:draw(player) +end) + +--- When a player gets a new role they will have the toolbar updated +Event.add(Roles.events.on_role_assigned,function(event) + toolbar_concept:raise_event('on_button_update',{ + player_index = event.player_index + }) +end) + +--- When a player loses a role they will have the toolbar updated +Event.add(Roles.events.on_role_unassigned,function(event) + toolbar_concept:raise_event('on_button_update',{ + player_index = event.player_index + }) +end) + +return Toolbar \ No newline at end of file diff --git a/modules/gui/warp-list.lua b/modules/gui/warp-list.lua index 4e06b335..9fb9e390 100644 --- a/modules/gui/warp-list.lua +++ b/modules/gui/warp-list.lua @@ -478,7 +478,7 @@ end) 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_children(warp_timer.store) + local categories = Store.get_keys(warp_timer.store) for _,category in pairs(categories) do warp_timer:increment(1,category) end diff --git a/utils/debug.lua b/utils/debug.lua index 1c1a3633..98f85a28 100644 --- a/utils/debug.lua +++ b/utils/debug.lua @@ -31,7 +31,7 @@ end ---Shows the given message if debug is enabled. Uses serpent to print non scalars. -- @param message --- @param stack_traceback levels of stack trace to give, defaults to 1 level if nil +-- @param trace_levels levels of stack trace to give, defaults to 1 level if nil function Debug.print(message, trace_levels) if not _DEBUG then return diff --git a/utils/event_core.lua b/utils/event_core.lua index 364e3134..b34715e1 100644 --- a/utils/event_core.lua +++ b/utils/event_core.lua @@ -27,7 +27,7 @@ local function call_handlers(handlers, event) local handler = handlers[i] local success, error = pcall(handler, event) if not success then - log(error) + log('\n\t'..error) end end end diff --git a/utils/math.lua b/utils/math.lua index 6876f1c5..179005c9 100644 --- a/utils/math.lua +++ b/utils/math.lua @@ -39,7 +39,8 @@ math.calculate_slope = function(x1, y1, x2, y2) end --- Calculates the y-intercept of a line --- @param x, y numbers - coordinates of point on line +-- @param x number - coordinates of point on line +-- @param y number - coordinates of point on line -- @param slope number - the slope of a line -- @return number - the y-intercept of a line math.calculate_y_intercept = function(x, y, slope) diff --git a/utils/state_machine.lua b/utils/state_machine.lua index 7db455ab..9d298a52 100644 --- a/utils/state_machine.lua +++ b/utils/state_machine.lua @@ -87,8 +87,8 @@ end -- You may register multiple handlers for the same transition -- NOTICE: This function will invoke an error if called after init. Dynamic machine changes are currently unsupported -- @param self StateMachine the machine --- @param state number/string exiting state --- @param state number/string entering state +-- @param old number/string exiting state +-- @param new number/string entering state -- @param callback function function Module.register_transition_callback(self, old, new, callback) if _LIFECYCLE ~= control_stage then diff --git a/utils/table.lua b/utils/table.lua index ea69bbd7..4b1973e2 100644 --- a/utils/table.lua +++ b/utils/table.lua @@ -49,7 +49,7 @@ end --- Checks if a table contains an element -- @param t -- @param e table element --- @returns the index of the element or nil +-- @return the index of the element or nil function table.index_of(t, e) for k, v in pairs(t) do if v == e then @@ -62,7 +62,7 @@ end --- Checks if the arrayed portion of a table contains an element -- @param t
    -- @param e table element --- @returns the index of the element or nil +-- @return the index of the element or nil function table.index_of_in_array(t, e) for i = 1, #t do if t[i] == e then @@ -76,7 +76,7 @@ local index_of = table.index_of --- Checks if a table contains an element -- @param t
    -- @param e table element --- @returns indicating success +-- @return indicating success function table.contains(t, e) return index_of(t, e) and true or false end @@ -85,7 +85,7 @@ local index_of_in_array = table.index_of_in_array --- Checks if the arrayed portion of a table contains an element -- @param t
    -- @param e table element --- @returns indicating success +-- @return indicating success function table.array_contains(t, e) return index_of_in_array(t, e) and true or false end @@ -128,11 +128,10 @@ end --- Chooses a random entry from a weighted table -- because this uses math.random, it cannot be used outside of events --- @param weight_table
    of tables with items and their weights +-- @param weighted_table
    of tables with items and their weights -- @param item_index of the index of items, defaults to 1 -- @param weight_index of the index of the weights, defaults to 2 -- @return table element --- @see features.chat_triggers::hodor function table.get_random_weighted(weighted_table, item_index, weight_index) local total_weight = 0 item_index = item_index or 1 @@ -156,6 +155,7 @@ end -- because this uses math.random, it cannot be used outside of events if no rng is supplied -- from: http://www.sdknews.com/cross-platform/corona/tutorial-how-to-shuffle-table-items -- @param t
    to shuffle +-- @param rng to provide random numbers function table.shuffle_table(t, rng) local rand = rng or math.random local iterations = #t