From ccd14da8230c0951fabbbce7d552787c928ede57 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Fri, 14 Jun 2019 20:00:16 +0100 Subject: [PATCH] Cleaned up gui --- expcore/gui.lua | 97 ++--- expcore/gui/{ => concepts}/center.lua | 11 +- expcore/gui/{ => concepts}/left.lua | 40 +- expcore/gui/{ => concepts}/popups.lua | 24 +- expcore/gui/{ => concepts}/toolbar.lua | 2 +- expcore/gui/core.lua | 383 +++----------------- expcore/gui/{ => elements}/buttons.lua | 29 +- expcore/gui/{ => elements}/checkboxs.lua | 52 +-- expcore/gui/{ => elements}/dropdown.lua | 52 ++- expcore/gui/{ => elements}/elem-button.lua | 48 +-- expcore/gui/{ => elements}/progress-bar.lua | 43 +-- expcore/gui/{ => elements}/slider.lua | 42 +-- expcore/gui/{ => elements}/text.lua | 51 +-- expcore/gui/instances.lua | 4 +- expcore/gui/prototype.lua | 303 ++++++++++++++++ expcore/gui/test.lua | 41 +-- modules/gui/player-list.lua | 4 +- modules/gui/rocket-info.lua | 8 +- modules/gui/science-info.lua | 6 +- modules/gui/task-list.lua | 6 +- modules/gui/warp-list.lua | 29 +- 21 files changed, 598 insertions(+), 677 deletions(-) rename expcore/gui/{ => concepts}/center.lua (96%) rename expcore/gui/{ => concepts}/left.lua (92%) rename expcore/gui/{ => concepts}/popups.lua (94%) rename expcore/gui/{ => concepts}/toolbar.lua (98%) rename expcore/gui/{ => elements}/buttons.lua (85%) rename expcore/gui/{ => elements}/checkboxs.lua (87%) rename expcore/gui/{ => elements}/dropdown.lua (85%) rename expcore/gui/{ => elements}/elem-button.lua (70%) rename expcore/gui/{ => elements}/progress-bar.lua (93%) rename expcore/gui/{ => elements}/slider.lua (82%) rename expcore/gui/{ => elements}/text.lua (75%) create mode 100644 expcore/gui/prototype.lua diff --git a/expcore/gui.lua b/expcore/gui.lua index 9bfe8171..a2da7e41 100644 --- a/expcore/gui.lua +++ b/expcore/gui.lua @@ -3,43 +3,47 @@ local Gui = require 'expcore.gui.core' --[[ - Gui._prototype_factory(tbl) --- Used internally to create new prototypes for element defines - Gui._event_factory(name) --- Used internally to create event handler adders for element defines - Gui._store_factory(callback) --- Used internally to create store adders for element defines - Gui._sync_store_factory(callback) --- Used internally to create synced store adders for element defines - Gui._define_factory(prototype) --- Used internally to create new element defines from a class prototype + Core - Gui._prototype:uid() --- Gets the uid for the element define - Gui._prototype:debug_name(name) --- Sets a debug alias for the define - Gui._prototype:set_caption(caption) --- Sets the caption for the element define - Gui._prototype:set_tooltip(tooltip) --- Sets the tooltip for the element define - Gui._prototype:set_style(style,callback) --- Sets the style for the element define - Gui._prototype:set_embeded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function - Gui._prototype:on_element_update(callback) --- Add a hander to run on the general value update event, different classes will handle this event differently - - Gui._prototype:set_pre_authenticator(callback) --- Sets an authenticator that blocks the draw function if check fails - Gui._prototype:set_post_authenticator(callback) --- Sets an authenticator that disables the element if check fails - Gui._prototype:draw_to(element) --- Draws the element using what is in the draw_data table, allows use of authenticator if present, registers new instances if store present + Gui.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._prototype:add_store(categorize) --- Adds a store location for the define that will save the state of the element, categorize is a function that returns a string - Gui._prototype:add_sync_store(location,categorize) --- Adds a store location for the define that will sync between games, categorize is a function that returns a string - Gui._prototype:on_store_update(callback) --- Adds a event callback for when the store changes are other events are not gauenteted to be raised - Gui.player_store(element) --- A categorize function to be used with add_store, each player has their own value - Gui.force_store(element) --- A categorize function to be used with add_store, each force has its own value - Gui.surface_store(element) --- A categorize function to be used with add_store, each surface has its own value + Gui.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._prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used - Gui._prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used - Gui.get_store(name,category) --- Gets the value that is stored for a given element define, category needed if categorize function used - Gui.set_store(name,category,value) --- Sets the value stored for a given element define, category needed if categorize function used - - Gui.toggle_enable(element) --- Will toggle the enabled state of an element + Gui.toggle_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_right_align(element,flow_name) --- Allows the creation of a right align flow to place elements into + Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into Gui.destory_if_valid(element) --- Destroies an element but tests for it being present and valid first + + 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_embeded_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' @@ -48,8 +52,20 @@ 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 instnace group has a categorise function; must be registerd + 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 -local Button = require 'expcore.gui.buttons' + 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' Gui.new_button = Button.new_button Gui.classes.button = Button --[[ @@ -64,7 +80,7 @@ Gui.classes.button = Button Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button ]] -local Checkbox = require 'expcore.gui.checkboxs' +local Checkbox = require 'expcore.gui.elements.checkboxs' Gui.new_checkbox = Checkbox.new_checkbox Gui.new_radiobutton = Checkbox.new_radiobutton Gui.new_radiobutton_option_set = Checkbox.new_option_set @@ -86,7 +102,7 @@ Gui.classes.checkbox = Checkbox Checkbox.reset_radiobutton(element,exclude,recursive) --- Sets all radiobutotn in a element to false (unless excluded) and can act recursivly ]] -local Dropdown = require 'expcore.gui.dropdown' +local Dropdown = require 'expcore.gui.elements.dropdown' Gui.new_dropdown = Dropdown.new_dropdown Gui.new_list_box = Dropdown.new_list_box Gui.classes.dropdown = Dropdown @@ -105,7 +121,7 @@ Gui.classes.dropdown = Dropdown Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index ]] -local Slider = require 'expcore.gui.slider' +local Slider = require 'expcore.gui.elements.slider' Gui.new_slider = Slider.new_slider Gui.classes.slider = Slider --[[ @@ -114,13 +130,12 @@ Gui.classes.slider = Slider 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:use_notches(state) --- Adds notches to the slider 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.text' +local Text = require 'expcore.gui.elements.text' Gui.new_text_filed = Text.new_text_field Gui.new_text_box = Text.new_text_box Gui.classes.text = Text @@ -137,7 +152,7 @@ Gui.classes.text = Text Text._prototype_box:set_read_only(state) --- Sets the text box to be read only ]] -local ElemButton = require 'expcore.gui.elem-button' +local ElemButton = require 'expcore.gui.elements.elem-button' Gui.new_elem_button = ElemButton.new_elem_button Gui.classes.elem_button = ElemButton --[[ @@ -150,7 +165,7 @@ Gui.classes.elem_button = ElemButton 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.progress-bar' +local ProgressBar = require 'expcore.gui.elements.progress-bar' Gui.new_progressbar = ProgressBar.new_progressbar Gui.set_progressbar_maximum = ProgressBar.set_maximum Gui.increment_progressbar = ProgressBar.increment @@ -177,7 +192,7 @@ Gui.classes.progressbar = ProgressBar ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggeres, can filter which elements are decremented ]] -local Toolbar = require 'expcore.gui.toolbar' +local Toolbar = require 'expcore.gui.concepts.toolbar' Gui.new_toolbar_button = Toolbar.new_button Gui.add_button_to_toolbar = Toolbar.add_button Gui.update_toolbar = Toolbar.update @@ -188,7 +203,7 @@ Gui.classes.toolbar = Toolbar Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return ]] -local LeftFrames = require 'expcore.gui.left' +local LeftFrames = require '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 @@ -217,7 +232,7 @@ Gui.classes.left_frames = LeftFrames 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.center' +local CenterFrames = require '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 @@ -240,7 +255,7 @@ Gui.classes.center_frames = CenterFrames 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.popups' +local PopupFrames = require 'expcore.gui.concepts.popups' Gui.get_popup_flow = PopupFrames.get_flow Gui.open_popup = PopupFrames.open Gui.new_popup = PopupFrames.new_popup diff --git a/expcore/gui/center.lua b/expcore/gui/concepts/center.lua similarity index 96% rename from expcore/gui/center.lua rename to expcore/gui/concepts/center.lua index 2788e804..c7eb5e34 100644 --- a/expcore/gui/center.lua +++ b/expcore/gui/concepts/center.lua @@ -16,12 +16,13 @@ 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' -local Toolbar = require 'expcore.gui.toolbar' +local Prototype = require 'expcore.gui.prototype' +local Toolbar = require 'expcore.gui.concepts.toolbar' local Game = require 'utils.game' local CenterFrames = { - _prototype = Gui._prototype_factory{ - on_draw = Gui._event_factory('on_draw') + _prototype = Prototype.extend{ + on_creation = Prototype.event } } @@ -141,9 +142,7 @@ function CenterFrames._prototype:draw_frame(player) player.opened = frame end - if self.events.on_draw then - self.events.on_draw(player,frame) - end + self:raise_event('on_creation',player,frame) return frame end diff --git a/expcore/gui/left.lua b/expcore/gui/concepts/left.lua similarity index 92% rename from expcore/gui/left.lua rename to expcore/gui/concepts/left.lua index eeb054d8..d7c25263 100644 --- a/expcore/gui/left.lua +++ b/expcore/gui/concepts/left.lua @@ -49,18 +49,19 @@ 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' -local Toolbar = require 'expcore.gui.toolbar' -local Buttons = require 'expcore.gui.buttons' +local Prototype = require 'expcore.gui.prototype' +local Toolbar = require 'expcore.gui.concepts.toolbar' +local Buttons = require 'expcore.gui.elements.buttons' local mod_gui = require 'mod-gui' local Game = require 'utils.game' local Event = require 'utils.event' local LeftFrames = { frames={}, - _prototype=Gui._prototype_factory{ - on_draw = Gui._event_factory('on_draw'), - on_update = Gui._event_factory('on_update'), - on_player_toggle = Gui._event_factory('on_player_toggle') + _prototype=Prototype.extend{ + on_creation = Prototype.event, + on_update = Prototype.event, + on_player_toggle = Prototype.event } } setmetatable(LeftFrames._prototype, { @@ -132,7 +133,6 @@ end -- @tparam string permision_name the name that can be used with the permision system -- @treturn table the new left frame define function LeftFrames.new_frame(permision_name) - local self = Toolbar.new_button(permision_name) local mt = getmetatable(self) @@ -141,11 +141,8 @@ function LeftFrames.new_frame(permision_name) self:on_click(function(player,_element) local visible = self:toggle(player) - - if self.events.on_player_toggle then - local frame = self:get_frame(player) - self.events.on_player_toggle(player,frame,visible) - end + local frame = self:get_frame(player) + self:raise_event('on_player_toggle',player,frame,visible) end) LeftFrames.frames[self.name] = self @@ -187,9 +184,7 @@ function LeftFrames._prototype:_internal_draw(player) direction=self.direction } - if self.events.on_draw then - self.events.on_draw(player,frame) - end + self:raise_event('on_creation',player,frame) if not self.open_by_default then frame.visible = false @@ -240,11 +235,9 @@ end -- @tparam LuaPlayer player the player to update the frame of function LeftFrames._prototype:update(player) local frame = self:get_frame(player) - if self.events.on_update then - self.events.on_update(player,frame) - elseif self.events.on_draw then + if self:raise_event('on_update',player,frame) == 0 then frame.clear() - self.events.on_draw(player,frame) + self:raise_event('on_creation',player,frame) end end @@ -262,9 +255,7 @@ end function LeftFrames._prototype:redraw(player) local frame = self:get_frame(player) frame.clear() - if self.events.on_draw then - self.events.on_draw(player,frame) - end + self:raise_event('on_creation',player,frame) end --- Redraws the frame for all players, see redraw @@ -297,10 +288,7 @@ Buttons.new_button() for _,define in pairs(LeftFrames.frames) do local frame = LeftFrames.get_frame(define.name,player) frame.visible = false - - if define.events.on_player_toggle then - define.events.on_player_toggle(player,frame,false) - end + define:raise_event('on_player_toggle',player,frame,false) end element.visible = false end) diff --git a/expcore/gui/popups.lua b/expcore/gui/concepts/popups.lua similarity index 94% rename from expcore/gui/popups.lua rename to expcore/gui/concepts/popups.lua index b324f0c0..91da73ed 100644 --- a/expcore/gui/popups.lua +++ b/expcore/gui/concepts/popups.lua @@ -12,10 +12,11 @@ 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' +local Prototype = require 'expcore.gui.prototype' local Game = require 'utils.game' local Event = require 'utils.event' -local ProgressBar = require 'expcore.gui.progress-bar' -local Button = require 'expcore.gui.buttons' +local ProgressBar = require 'expcore.gui.elements.progress-bar' +local Button = require 'expcore.gui.elements.buttons' local mod_gui = require 'mod-gui' local Color = require 'resources.color_presets' local Global = require 'utils.global' @@ -25,8 +26,8 @@ local PopupFrames = { popup_flow_name = Gui.uid_name(), main_frame_name = Gui.uid_name(), close_frame_name = Gui.uid_name(), - _prototype = Gui._prototype_factory{ - on_draw = Gui._event_factory('on_draw') + _prototype = Prototype.extend{ + on_creation = Prototype.event } } Global.register(PopupFrames.paused_popups,function(tbl) @@ -120,20 +121,16 @@ end) -- @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._define_factory(PopupFrames._prototype) + local self = Gui.new_define(PopupFrames._prototype,name) self.draw_data.type = 'flow' self.draw_data.direction = 'vertical' - if name then - self:debug_name(name) - end - local mt = getmetatable(self) mt.__call = function(tbl,player,open_time,...) return tbl:open(player,open_time,...) end - self.post_draw = function(element,maximum,...) + self:on_draw(function(player,element,maximum,...) -- main content frame local frame = element.add{ type='flow', @@ -172,11 +169,8 @@ function PopupFrames.new_popup(name) close_button_style.height = 20 -- event trigger to draw the gui content - if self.events.on_draw then - local player = Game.get_player_by_index(element.player_index) - self.events.on_draw(player,frame,...) - end - end + self:raise_event('on_creation',player,frame,...) + end) return self end diff --git a/expcore/gui/toolbar.lua b/expcore/gui/concepts/toolbar.lua similarity index 98% rename from expcore/gui/toolbar.lua rename to expcore/gui/concepts/toolbar.lua index b9fc98ad..ff1e0f06 100644 --- a/expcore/gui/toolbar.lua +++ b/expcore/gui/concepts/toolbar.lua @@ -14,8 +14,8 @@ Toolbar.add_button(button) --- Adds an existing buttton to the toolbar Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return ]] -local Buttons = require 'expcore.gui.buttons' local Gui = require 'expcore.gui.core' +local Buttons = require 'expcore.gui.elements.buttons' local Roles = require 'expcore.roles' local Event = require 'utils.event' local Game = require 'utils.game' diff --git a/expcore/gui/core.lua b/expcore/gui/core.lua index a3456e15..6a91ad3d 100644 --- a/expcore/gui/core.lua +++ b/expcore/gui/core.lua @@ -16,12 +16,7 @@ Note that all event handlers will include event.player as a valid player and that if the player or the element is not valid then the callback will not be run. ->>>> Interal factory functions - There are a few factory function that are used by the class definations the use of these function are important to - know about but should only be used when making a new class deination rather than an element defination. See one of - the existing class definations for an example of when to use these. - ->>>> Basic prototype functions +>>>> 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() @@ -74,14 +69,14 @@ return global.checkbox_example_allow_post_auth end) ->>>> Using store +>>>> 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.player_store) + -- 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 @@ -89,7 +84,7 @@ Of course this tool is not limited to only player interactions; the current satate of a define can be gotten using a number of methods and the value can even be updated by the script and have all instances of the element define be updated. When you use a category then we must give a category to the get - and set functions; in our case we used Gui.player_store which uses the player's name as the category which is why 'Cooldude2606' is given as a argument, + 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') @@ -112,333 +107,55 @@ Gui.new_checkbox() :set_caption('Example Checkbox') :set_tooltip('Example checkbox') - :add_store(Gui.player_store) + :add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value) player.print('Example checkbox is now: '..tostring(value)) end) >>>> Functions - Gui._prototype_factory(tbl) --- Used internally to create new prototypes for element defines - Gui._event_factory(name) --- Used internally to create event handler adders for element defines - Gui._store_factory(callback) --- Used internally to create store adders for element defines - Gui._sync_store_factory(callback) --- Used internally to create synced store adders for element defines - Gui._define_factory(prototype) --- Used internally to create new element defines from a class prototype - - Gui._prototype:uid() --- Gets the uid for the element define - Gui._prototype:debug_name(name) --- Sets a debug alias for the define - Gui._prototype:set_caption(caption) --- Sets the caption for the element define - Gui._prototype:set_tooltip(tooltip) --- Sets the tooltip for the element define - Gui._prototype:set_style(style,callback) --- Sets the style for the element define - Gui._prototype:set_embeded_flow(state) --- Sets the element to be drawn inside a nameless flow, can be given a name using a function - Gui._prototype:on_element_update(callback) --- Add a hander to run on the general value update event, different classes will handle this event differently - - Gui._prototype:set_pre_authenticator(callback) --- Sets an authenticator that blocks the draw function if check fails - Gui._prototype:set_post_authenticator(callback) --- Sets an authenticator that disables the element if check fails - Gui._prototype:draw_to(element) --- Draws the element using what is in the draw_data table, allows use of authenticator if present, registers new instances if store present + Gui.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._prototype:add_store(categorize) --- Adds a store location for the define that will save the state of the element, categorize is a function that returns a string - Gui._prototype:add_sync_store(location,categorize) --- Adds a store location for the define that will sync between games, categorize is a function that returns a string - Gui._prototype:on_store_update(callback) --- Adds a event callback for when the store changes are other events are not gauenteted to be raised - Gui.player_store(element) --- A categorize function to be used with add_store, each player has their own value - Gui.force_store(element) --- A categorize function to be used with add_store, each force has its own value - Gui.surface_store(element) --- A categorize function to be used with add_store, each surface has its own value + Gui.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._prototype:get_store(category) --- Gets the value in this elements store, category needed if categorize function used - Gui._prototype:set_store(category,value) --- Sets the value in this elements store, category needed if categorize function used - Gui.get_store(name,category) --- Gets the value that is stored for a given element define, category needed if categorize function used - Gui.set_store(name,category,value) --- Sets the value stored for a given element define, category needed if categorize function used - - Gui.toggle_enable(element) --- Will toggle the enabled state of an element + Gui.toggle_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_right_align(element,flow_name) --- Allows the creation of a right align flow to place elements into + Gui.create_alignment(element,flow_name) --- Allows the creation of a right align flow to place elements into Gui.destory_if_valid(element) --- Destroies an element but tests for it being present and valid first ]] local Gui = require 'utils.gui' local Game = require 'utils.game' -local Store = require 'expcore.store' -local Instances = require 'expcore.gui.instances' -Gui._prototype = {} -- Stores the base prototype of all element defines Gui.classes = {} -- Stores the class definations used to create element defines Gui.defines = {} -- Stores the indivdual element definations Gui.names = {} -- Stores debug names to link to gui uids ---- Used internally to create new prototypes for element defines --- @tparam table tbl table a that will have functions added to it --- @treturn table the new table with the keys added to it -function Gui._prototype_factory(tbl) - for k,v in pairs(Gui._prototype) do - if not tbl[k] then tbl[k] = v end - end - return tbl -end - ---- Used internally to create event handler adders for element defines --- @tparam string name the key that the event will be stored under, should be the same as the event name --- @treturn function the function that can be used to add an event handler -function Gui._event_factory(name) - --- Gui._prototype:on_event(callback) - --- Add a hander to run on this event, replace event with the event, different classes have different events - -- @tparam function callback the function that will be called on the event - -- callback param - player LuaPlayer - the player who owns the gui element - -- callback param - element LuaGuiElement - the element that caused the event - -- callback param - value any - (not always present) the updated value for the element - -- callback param - ... any - other class defines may add more params - -- @treturn self the element define to allow chaining - return function(self,callback) - if type(callback) ~= 'function' then - return error('Event callback must be a function',2) - end - - self.events[name] = callback - return self - end -end - ---- Used internally to create store adders for element defines --- @tparam callback a callback is called when there is an update to the stored value and stould set the state of the element --- @treturn function the function that can be used to add a store the the define -function Gui._store_factory(callback) - --- Gui._prototype:add_store(categorize) - --- Adds a store location for the define that will save the state of the element, categorize is a function that returns a string - -- @tparam[opt] function categorize if present will be called to convert an element into a category string - -- categorize param - element LuaGuiElement - the element that needs to be converted - -- categorize return - string - a determistic string that referses to a category such as player name or force name - -- @treturn self the element define to allow chaining - return function(self,categorize) - if self.store then return end - - self.store = Store.uid_location() - self.categorize = categorize - - Instances.register(self.name,self.categorize) - - Store.register(self.store,function(value,category) - if self.events.on_store_update then - self.events.on_store_update(value,category) - end - - if Instances.is_registered(self.name) then - Instances.apply_to_elements(self.name,category,function(element) - callback(self,element,value) - end) - end - end) - - return self - end -end - ---- Used internally to create synced store adders for element defines --- @tparam callback a callback is called when there is an update to the stored value and stould set the state of the element --- @treturn function the function that can be used to add a sync store the the define -function Gui._sync_store_factory(callback) - --- Gui._prototype:add_sync_store(location,categorize) - --- Adds a store location for the define that will sync between games, categorize is a function that returns a string - -- @tparam string location string a unique location, unlike add_store a uid location should not be used to avoid migration problems - -- @tparam[opt] function categorize if present will be called to convert an element into a category string - -- categorize param - element LuaGuiElement - the element that needs to be converted - -- categorize return - string - a determistic string that referses to a category such as player name or force name - -- @treturn self the element define to allow chaining - return function(self,location,categorize) - if self.store then return end - - if Store.is_registered(location) then - return error('Location for store is already registered: '..location,2) - end - - self.store = location - self.categorize = categorize - - Instances.register(self.name,self.categorize) - - Store.register(self.store,true,function(value,category) - if self.events.on_store_update then - self.events.on_store_update(value,category) - end - - if Instances.is_registered(self.name) then - Instances.apply_to_elements(self,category,function(element) - callback(self,element,value) - end) - end - end) - - return self - end -end - ---- Used internally to create new element defines from a class prototype +--- 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 -- @treturn table the new element define with all functions accessed via __index metamethod -function Gui._define_factory(prototype) - local uid = Gui.uid_name() +function Gui.new_define(prototype,debug_name) + local name = Gui.uid_name() local define = setmetatable({ - name=uid, - events={}, - draw_data={ - name=uid + debug_name = debug_name, + name = name, + events = {}, + draw_data = { + name = name } },{ - __index=prototype, - __call=function(self,element,...) - return self:draw_to(element,...) + __index = prototype, + __call = function(self,...) + return self:draw_to(...) end }) Gui.defines[define.name] = define return define end ---- Gets the uid for the element define --- @treturn string the uid of this element define -function Gui._prototype:uid() - return self.name -end - ---- Sets a debug alias for the define --- @tparam 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 -function Gui._prototype:debug_name(name) - self.debug_name = name - return self -end - ---- 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 -function Gui._prototype:set_caption(caption) - self.draw_data.caption = caption - return self -end - ---- 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 -function Gui._prototype:set_tooltip(tooltip) - self.draw_data.tooltip = tooltip - return self -end - ---- Sets the style for the element define --- @tparam string style the style that will be used for this element when drawn --- @tparam[opt] callback function function is called when element is drawn to alter its style --- @treturn self the element define to allow chaining -function Gui._prototype:set_style(style,callback) - self.draw_data.style = style - self.events.on_style = callback - return self -end - ---- Sets the element to be drawn inside a nameless flow, can be given a name using a function --- @tparam state ?boolean|function when true a padless flow is created to contain the element --- @treturn self the element define to allow chaining -function Gui._prototype:set_embeded_flow(state) - if state == false or type(state) == 'function' then - self.embeded_flow = state - else - self.embeded_flow = true - end - return self -end - ---- 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 - player LuaPlayer - the player that the element is being drawn to --- callback param - define_name string - the name of the define that is being drawn --- callback return - boolean - false will stop the element from being drawn --- @treturn self the element define to allow chaining -function Gui._prototype:set_pre_authenticator(callback) - if type(callback) ~= 'function' then - return error('Pre authenticator callback must be a function') - end - - self.pre_authenticator = callback - return self -end - ---- Sets an authenticator that disables the element if check fails --- @tparam function callback the function that will be ran to test if the element should be enabled or not --- callback param - player LuaPlayer - the player that the element is being drawn to --- callback param - define_name string - the name of the define that is being drawn --- callback return - boolean - false will disable the element --- @treturn self the element define to allow chaining -function Gui._prototype:set_post_authenticator(callback) - if type(callback) ~= 'function' then - return error('Authenicater callback must be a function') - end - - self.post_authenticator = callback - return self -end - ---- Draws the element using what is in the draw_data table, allows use of authenticator if present, registers new instances if store present --- the data with in the draw_data is set up through the use of all the other functions --- @tparam LuaGuiElement element the element that the define will draw a copy of its self onto --- @treturn LuaGuiElement the new element that was drawn so styles can be applied -function Gui._prototype:draw_to(element,...) - if element[self.name] then return end - local player = Game.get_player_by_index(element.player_index) - - if self.pre_authenticator then - if not self.pre_authenticator(player,self.name) then return end - end - - if self.embeded_flow then - local embeded_name - if type(self.embeded_flow) == 'function' then - embeded_name = self.embeded_flow(element,...) - end - element = element.add{type='flow',name=embeded_name} - Gui.set_padding(element) - end - - local new_element = element.add(self.draw_data) - - if self.events.on_style then - self.events.on_style(new_element.style) - end - - 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 - - if self.post_draw then self.post_draw(new_element,...) end - - return new_element -end - ---- Gets the value in this elements store, category needed if categorize function used --- @tparam 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 Gui._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 Gui._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 Gui._prototype:clear_store(category) - if not self.store then return end - return Store.clear(self.store,category) -end - --- Gets an element define give the uid, debug name or a copy of the element define -- @tparam name ?string|table the uid, debug name or define for the element define to get -- @tparam[opt] boolean internal when true the error trace is one level higher (used internally) @@ -463,29 +180,10 @@ function Gui.get_define(name,internal) return define end ---- Gets the value that is stored for a given element define, category needed if categorize function used --- @tparam name ?string|table the uid, debug name or define for the element define to get --- @tparam[opt] string category the category to get the value for --- @treturn any the value that is stored for this define -function Gui.get_store(name,category) - local define = Gui.get_define(name,true) - return define:get_store(category) -end - ---- Sets the value stored for a given element define, category needed if categorize function used --- @tparam name ?string|table the uid, debug name or define for the element define to set --- @tparam[opt] string category the category to set the value for --- @tparam boolean any value the value to set for the define, must be valid for its type ie for a checkbox --- @treturn boolean true if the value was set -function Gui.set_store(name,category,value) - local define = Gui.get_define(name,true) - return define:get_store(category,value) -end - --- A categorize function to be used with add_store, each player has their own value -- @tparam LuaGuiElement element the element that will be converted to a string -- @treturn string the player's name who owns this element -function Gui.player_store(element) +function Gui.categorize_by_player(element) local player = Game.get_player_by_index(element.player_index) return player.name end @@ -493,7 +191,7 @@ end --- A categorize function to be used with add_store, each force has its own value -- @tparam LuaGuiElement element the element that will be converted to a string -- @treturn string the player's force name who owns this element -function Gui.force_store(element) +function Gui.categorize_by_force(element) local player = Game.get_player_by_index(element.player_index) return player.force.name end @@ -501,7 +199,7 @@ end --- A categorize function to be used with add_store, each surface has its own value -- @tparam LuaGuiElement element the element that will be converted to a string -- @treturn string the player's surface name who owns this element -function Gui.surface_store(element) +function Gui.categorize_by_surface(element) local player = Game.get_player_by_index(element.player_index) return player.surface.name end @@ -518,7 +216,7 @@ 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_enable(element) +function Gui.toggle_enabled(element) if not element or not element.valid then return end if not element.enabled then element.enabled = true @@ -568,20 +266,21 @@ function Gui.set_padding_style(style,up,down,left,right) style.right_padding = right or 0 end ---- Allows the creation of a right align flow to place elements into --- @tparam LuaGuiElement element the element to add this flow to, --- @tparam[opt] string flow_name the name of the flow can be nil --- @treturn LuaGuiElement the flow that was created -function Gui.create_right_align(element,flow_name) - local right_flow = - element.add{ - name=flow_name, - type='flow' - } - Gui.set_padding(right_flow,1,1,2,2) - right_flow.style.horizontal_align = 'right' - right_flow.style.horizontally_stretchable = true - return right_flow +--- 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 diff --git a/expcore/gui/buttons.lua b/expcore/gui/elements/buttons.lua similarity index 85% rename from expcore/gui/buttons.lua rename to expcore/gui/elements/buttons.lua index 9a5d794b..66aa957e 100644 --- a/expcore/gui/buttons.lua +++ b/expcore/gui/elements/buttons.lua @@ -15,12 +15,14 @@ ]] local mod_gui = require 'mod-gui' local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Button = { - _prototype=Gui._prototype_factory{ - on_click = Gui._event_factory('on_click'), - on_left_click = Gui._event_factory('on_left_click'), - on_right_click = Gui._event_factory('on_right_click'), + _prototype=Prototype.extend{ + on_raw_click = Prototype.event, + on_click = Prototype.event, + on_left_click = Prototype.event, + on_right_click = Prototype.event, } } @@ -29,27 +31,26 @@ local Button = { -- @treturn table the new button element define function Button.new_button(name) - local self = Gui._define_factory(Button._prototype) + local self = Gui.new_define(Button._prototype,name) self.draw_data.type = 'button' self.draw_data.style = mod_gui.button_style - if name then - self:debug_name(name) - end - Gui.on_click(self.name,function(event) local mouse_button = event.button local keys = {alt=event.alt,control=event.control,shift=event.shift} + 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 and self.events.on_left_click then - self.events.on_left_click(event.player,event.element) + 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.events.on_right_click(event.player,event.element) + 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 @@ -59,9 +60,7 @@ function Button.new_button(name) end end - if self.events.on_click then - self.events.on_click(event.player,event.element,event) - end + self:raise_event('on_click',player,element) end) return self diff --git a/expcore/gui/checkboxs.lua b/expcore/gui/elements/checkboxs.lua similarity index 87% rename from expcore/gui/checkboxs.lua rename to expcore/gui/elements/checkboxs.lua index 02769360..0b68952a 100644 --- a/expcore/gui/checkboxs.lua +++ b/expcore/gui/elements/checkboxs.lua @@ -10,7 +10,7 @@ local example_option_set = Gui.new_option_set('example-option-set',function(value,category) game.print('Example options set '..category..' is now: '..tostring(value)) - end,Gui.player_store) + end,Gui.categorize_by_player) Then you must register some radiobutton defines and include them in the option set: @@ -46,43 +46,34 @@ Other functions present from expcore.gui.core ]] local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Store = require 'expcore.store' local Game = require 'utils.game' ---- Event call for on_checked_state_changed and 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 event_call(define,element,value) - if define.events.on_element_update then - local player = Game.get_player_by_index(element.player_index) - define.events.on_element_update(player,element,value) - end -end - --- Store call for store update -- @tparam 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_call(define,element,value) +local function store_update(define,element,value) element.state = value - event_call(define,element,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=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _prototype_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=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _prototype_radiobutton=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) } } @@ -91,21 +82,17 @@ local Checkbox = { -- @treturn table the new checkbox element define function Checkbox.new_checkbox(name) - local self = Gui._define_factory(Checkbox._prototype_checkbox) + local self = Gui.new_define(Checkbox._prototype_checkbox,name) self.draw_data.type = 'checkbox' self.draw_data.state = false - if name then - self:debug_name(name) - end - - self.post_draw = function(element) + 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 + end) Gui.on_checked_state_changed(self.name,function(event) local element = event.element @@ -121,8 +108,7 @@ function Checkbox.new_checkbox(name) self:set_store(category,value) else - local value = element.state - event_call(self,element,value) + self:raise_event('on_element_update',event.player,element,element.state) end end) diff --git a/expcore/gui/dropdown.lua b/expcore/gui/elements/dropdown.lua similarity index 85% rename from expcore/gui/dropdown.lua rename to expcore/gui/elements/dropdown.lua index 8d976162..847492f5 100644 --- a/expcore/gui/dropdown.lua +++ b/expcore/gui/elements/dropdown.lua @@ -17,40 +17,30 @@ Other functions present from expcore.gui.core ]] local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Game = require 'utils.game' ---- Event call for on_selection_state_changed and store update +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 event_call(define,element,value) +local function store_update(define,element,value) + select_value(element,value) local player = Game.get_player_by_index(element.player_index) - - if define.events.on_element_update then - define.events.on_element_update(player,element,value) - end + 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 _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_call(define,element,value) - _select_value(element,value) - event_call(define,element,value) -end - local Dropdown = { - _prototype=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _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) } } @@ -59,16 +49,11 @@ local Dropdown = { -- @treturn table the new dropdown element define function Dropdown.new_dropdown(name) - local self = Gui._define_factory(Dropdown._prototype) + local self = Gui.new_define(Dropdown._prototype,name) self.draw_data.type = 'drop-down' - if name then - self:debug_name(name) - end - - self.post_draw = function(element) + self:on_draw(function(player,element) if self.dynamic_options then - local player = Game.get_player_by_index(element.player_index) local dynamic_options = self.dynamic_options(player,element) local items = element.items for _,v in pairs(dynamic_options) do @@ -82,7 +67,7 @@ function Dropdown.new_dropdown(name) local value = self:get_store(category) if value then Dropdown.select_value(element,value) end end - end + end) Gui.on_selection_state_changed(self.name,function(event) local element = event.element @@ -93,7 +78,12 @@ function Dropdown.new_dropdown(name) self:set_store(category,value) else - event_call(self,element,value) + 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 @@ -176,7 +166,7 @@ function Dropdown.select_value(element,value) end end end -_select_value = Dropdown.select_value +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 diff --git a/expcore/gui/elem-button.lua b/expcore/gui/elements/elem-button.lua similarity index 70% rename from expcore/gui/elem-button.lua rename to expcore/gui/elements/elem-button.lua index b20cae59..c70c1aa6 100644 --- a/expcore/gui/elem-button.lua +++ b/expcore/gui/elements/elem-button.lua @@ -12,36 +12,25 @@ Other functions present from expcore.gui.core ]] local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Game = require 'utils.game' ---- Event call for on_elem_changed and 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 event_call(define,element,value) - local player = Game.get_player_by_index(element.player_index) - - if define.events.on_element_update then - define.events.on_element_update(player,element,value) - end - -end - --- Store call for store update -- @tparam 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_call(define,element,value) +local function store_update(define,element,value) element.elem_value = value - event_call(define,element,value) + local player = Game.get_player_by_index(element.player_index) + define:raise_event('on_element_update',player,element,value) end local ElemButton = { - _prototype=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _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) } } @@ -50,16 +39,10 @@ local ElemButton = { -- @treturn table the new elem button element define function ElemButton.new_elem_button(name) - local self = Gui._define_factory(ElemButton._prototype) + local self = Gui.new_define(ElemButton._prototype,name) self.draw_data.type = 'choose-elem-button' - if name then - self:debug_name(name) - end - - self.post_draw = function(element) - local player = Game.get_player_by_index(element.player_index) - + self:on_draw(function(player,element) if type(self.default) == 'function' then element.elem_value = self.default(player,element) end @@ -69,7 +52,7 @@ function ElemButton.new_elem_button(name) local value = self:get_store(category) if value then element.elem_value = value end end - end + end) Gui.on_elem_changed(self.name,function(event) local element = event.element @@ -80,7 +63,7 @@ function ElemButton.new_elem_button(name) self:set_store(category,value) else - event_call(self,element,value) + self:raise_event('on_element_update',event.player,element,value) end @@ -92,10 +75,7 @@ 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 -function ElemButton._prototype:set_type(type) - self.draw_data.elem_type = type - return self -end +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 diff --git a/expcore/gui/progress-bar.lua b/expcore/gui/elements/progress-bar.lua similarity index 93% rename from expcore/gui/progress-bar.lua rename to expcore/gui/elements/progress-bar.lua index 2200019d..020ab2a3 100644 --- a/expcore/gui/progress-bar.lua +++ b/expcore/gui/elements/progress-bar.lua @@ -21,6 +21,7 @@ ProgressBar._prototype:event_countdown(filter) --- Event handler factory that counts down by 1 every time the event triggeres, can filter which elements are decremented ]] local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Global = require 'utils.global' local Game = require 'utils.game' @@ -29,20 +30,17 @@ local Game = require 'utils.game' -- @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) - - if define.events.on_complete then - define.events.on_complete(player,element,function() - define:add_element(element) - define:reset_element(element) - end) - end + 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_call(define,element,value) +local function store_update(define,element,value) if value then element.value = value if define.count_down and value <= 0 @@ -55,14 +53,14 @@ end local ProgressBar = { unregistered={}, -- elements with no callbacks independent={}, -- elements with a link to a deinfe - _prototype=Gui._prototype_factory{ - -- note both events will recive a reset function that can be used to reset the progress of the element/store - on_complete = Gui._event_factory('on_complete'), - on_store_complete = Gui._event_factory('on_store_complete'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _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 @@ -182,14 +180,11 @@ end -- @tparam[opt] string name the optional debug name that can be added -- @treturn table the new progressbar elemente define function ProgressBar.new_progressbar(name) - local self = Gui._define_factory(ProgressBar._prototype) + + local self = Gui.new_define(ProgressBar._prototype,name) self.draw_data.type = 'progressbar' - if name then - self:debug_name(name) - end - - self.post_draw = function(element,maximum) + 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) @@ -215,7 +210,7 @@ function ProgressBar.new_progressbar(name) end - end + end) return self end @@ -263,11 +258,7 @@ local function change_value_prototype(self,amount,category,filter) if self.count_down and new_value <= 0 or not self.count_down and new_value >= 1 then self:clear_store(category) - - if self.events.on_store_complete then - self.events.on_store_complete(category,reset_store) - end - + self:raise_event('on_store_complete',category,reset_store) return end diff --git a/expcore/gui/slider.lua b/expcore/gui/elements/slider.lua similarity index 82% rename from expcore/gui/slider.lua rename to expcore/gui/elements/slider.lua index f8bdef5e..abd34f29 100644 --- a/expcore/gui/slider.lua +++ b/expcore/gui/elements/slider.lua @@ -6,7 +6,6 @@ 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:use_notches(state) --- Adds notches to the slider 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 @@ -14,6 +13,7 @@ Other functions present from expcore.gui.core ]] local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Instances = require 'expcore.gui.instances' local Game = require 'utils.game' @@ -28,9 +28,7 @@ local function event_call(define,element,value) local delta = max-min local percent = delta == 0 and 0 or (value-min)/delta - if define.events.on_element_update then - define.events.on_element_update(player,element,value,percent) - end + define:raise_event('on_element_update',player,element,value,percent) local category = player.name if define.categorize then @@ -46,17 +44,17 @@ end -- @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_call(define,element,value) +local function store_update(define,element,value) element.slider_value = value event_call(define,element,value) end local Slider = { - _prototype=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _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) } } @@ -65,15 +63,10 @@ local Slider = { -- @treturn table the new slider element define function Slider.new_slider(name) - local self = Gui._define_factory(Slider._prototype) + local self = Gui.new_define(Slider._prototype,name) self.draw_data.type = 'slider' - if name then - self:debug_name(name) - end - - self.post_draw = function(element) - local player = Game.get_player_by_index(element.player_index) + self:on_draw(function(player,element) local min,max = element.get_slider_minimum(),element.get_slider_maximum() if type(self.min) == 'function' then @@ -95,7 +88,7 @@ function Slider.new_slider(name) if self.auto_label then self:draw_label(element.parent) end - end + end) Gui.on_value_changed(self.name,function(event) local element = event.element @@ -115,17 +108,6 @@ function Slider.new_slider(name) return self end ---- Adds notches to the slider --- @tparam[opt] boolean state when true will draw notches onto the slider -function Slider._prototype:use_notches(state) - if state == false then - self.draw_data.style = nil - else - self.draw_data.style = 'notched_slider' - 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 @@ -164,7 +146,7 @@ function Slider._prototype:draw_label(element) caption=tostring(math.round(value,2)) } - local categorise = self.categorise or Gui.player_store + local categorise = self.categorise or Gui.categorize_by_player local category = categorise(new_element) Instances.unregistered_add_element(name,category,new_element) diff --git a/expcore/gui/text.lua b/expcore/gui/elements/text.lua similarity index 75% rename from expcore/gui/text.lua rename to expcore/gui/elements/text.lua index 4fb5b43f..0c38895a 100644 --- a/expcore/gui/text.lua +++ b/expcore/gui/elements/text.lua @@ -15,42 +15,31 @@ Other functions present from expcore.gui.core ]] local Gui = require 'expcore.gui.core' +local Prototype = require 'expcore.gui.prototype' local Game = require 'utils.game' ---- Event call for on_text_changed and 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 event_call(define,element,value) - local player = Game.get_player_by_index(element.player_index) - - if define.events.on_element_update then - define.events.on_element_update(player,element,value) - end - -end - --- Store call for store update -- @tparam 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_call(define,element,value) +local function store_update(define,element,value) element.text = value - event_call(define,element,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=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _prototype_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=Gui._prototype_factory{ - on_element_update = Gui._event_factory('on_element_update'), - on_store_update = Gui._event_factory('on_store_update'), - add_store = Gui._store_factory(store_call), - add_sync_store = Gui._sync_store_factory(store_call) + _prototype_box=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) } } @@ -59,14 +48,10 @@ local Text = { -- @treturn table the new text field element define function Text.new_text_field(name) - local self = Gui._define_factory(Text._prototype_field) + local self = Gui.new_define(Text._prototype_field,name) self.draw_data.type = 'textfield' - if name then - self:debug_name(name) - end - - self.post_draw = function(element) + self:on_draw(function(player,element) if self.selectable then element.selectable = true end @@ -84,7 +69,7 @@ function Text.new_text_field(name) local value = self:get_store(category) if value then element.text = value end end - end + end) Gui.on_text_changed(self.name,function(event) local element = event.element @@ -95,7 +80,7 @@ function Text.new_text_field(name) self:set_store(category,value) else - event_call(self,element,value) + self:raise_event('on_element_update',event.player,element,value) end diff --git a/expcore/gui/instances.lua b/expcore/gui/instances.lua index 1bb502b9..cd3616d8 100644 --- a/expcore/gui/instances.lua +++ b/expcore/gui/instances.lua @@ -12,7 +12,7 @@ -- categorise works in the same way as store categorise -- so the function will worl here but no value is stored only gui elements - Instances.register('score',Gui.force_store) + 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: @@ -38,7 +38,7 @@ instance group would work when registered vs unregistered: -- Registered with category - Instances.register('score',Gui.force_store) -- force_store will return the force name of an element + 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' diff --git a/expcore/gui/prototype.lua b/expcore/gui/prototype.lua new file mode 100644 index 00000000..bec61e8d --- /dev/null +++ b/expcore/gui/prototype.lua @@ -0,0 +1,303 @@ +--- Used to create new gui prototypes see elements and concepts +--[[ + >>>> 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 + + 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_embeded_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 Game = require 'utils.game' +local Store = require 'expcore.store' +local Instances = require 'expcore.gui.instances' + +local Constructor = {} +local Prototype = {} + +--- Creates a new function to add functions to an event handler +-- @tparam string event_name the name of the event that callbacks will be added to +-- @treturn function the function used to register handlers +function Constructor.event(event_name) + --- Adds a callback as a handler for an event + -- @tparam table self the gui define being acted on + -- @tparam function callback the function that will be added as a handler for the event + -- @treturn table self returned to allowing chaining of functions + return function(self,callback) + if type(callback) ~= 'function' then + return error('Event callback for '..event_name..' must be a function',2) + end + + local handlers = self.events[event_name] + if not handlers then + handlers = {} + self.events[event_name] = handlers + end + + handlers[#handlers+1] = callback + return self + end +end + +--- Extents a prototype with the base functions of all gui prototypes, no metatables +-- @tparam table new_prototype the prototype that you want to add the functions to +-- @treturn table the same prototype but with the new functions added +function Constructor.extend(new_prototype) + for key,value in pairs(Prototype) do + if type(value) == 'table' then + new_prototype[key] = table.deepcopy(value) + else + new_prototype[key] = value + end + end + for key,value in pairs(new_prototype) do + if value == Constructor.event then + new_prototype[key] = Constructor.event(key) + end + end + return new_prototype +end + +--- Creates a new function which adds a store to a gui define +-- @tparam 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 omited 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 omited all share one single category + -- categorize param - LuaGuiElement element - the element that needs to be converted + -- categorize return - string - a determistic string that referses to a category such as player name or force name + -- @treturn self the element define to allow chaining + return function(self,location,categorize) + if self.store then return end + + if not sync then + categorize = location + location = Store.uid_location() + end + + if Store.is_registered(location) then + return error('Location for store is already registered: '..location,2) + end + + self.store = location + self.categorize = categorize + + Instances.register(self.name,self.categorize) + + Store.register(self.store,sync,function(value,category) + self:raise_event('on_store_update',value,category) + + if Instances.is_registered(self.name) then + Instances.apply_to_elements(self.name,category,function(element) + callback(self,element,value) + end) + end + end) + + return self + end +end + +--- Creates a setter function that checks the type when a value is set +-- @tparam string value_type the type that the value should be when it is set +-- @tparam string key the key of the define that will be set +-- @tparam[opt] string second_key allows for setting of a key in a sub table +-- @treturn function the function that will check the type and set the value +function Constructor.setter(value_type,key,second_key) + local display_message = 'Gui define '..key..' must be of type '..value_type + if second_key then + display_message = 'Gui define '..second_key..' must be of type '..value_type + end + + local locale = false + if value_type == 'locale-string' then + locale = true + value_type = 'table' + end + + return function(self,value) + local vtype = type(value) + if vtype ~= value_type and (not locale or vtype ~= 'string') then + error(display_message,2) + end + + if second_key then + self[key][second_key] = value + else + self[key] = value + end + + return self + end +end + +--- Gets the uid for the element define +-- @treturn string the uid of this element define +function Prototype:uid() + return self.name +end + +--- Sets a debug alias for the define +-- @tparam string name the debug name for the element define that can be used to get this element define +-- @treturn self the element define to allow chaining +Prototype.debug_name = Constructor.setter('string','debug_name') + +--- Sets the caption for the element define +-- @tparam string caption the caption that will be drawn with the element +-- @treturn self the element define to allow chaining +Prototype.set_caption = Constructor.setter('locale-string','draw_data','caption') + +--- Sets the tooltip for the element define +-- @tparam string tooltip the tooltip that will be displayed for this element when drawn +-- @treturn self the element define to allow chaining +Prototype.set_tooltip = Constructor.setter('locale-string','draw_data','tooltip') + +--- Sets an authenticator that blocks the draw function if check fails +-- @tparam function callback the function that will be ran to test if the element should be drawn or not +-- callback param - LuaPlayer player - the player that the element is being drawn to +-- callback param - string define_name - the name of the define that is being drawn +-- callback return - boolean - false will stop the element from being drawn +-- @treturn self the element define to allow chaining +Prototype.set_pre_authenticator = Constructor.setter('function','pre_authenticator') + +--- Sets an authenticator that disables the element if check fails +-- @tparam function callback the function that will be ran to test if the element should be enabled or not +-- callback param - LuaPlayer player - the player that the element is being drawn to +-- callback param - string define_name - the name of the define that is being drawn +-- callback return - boolean - false will disable the element +-- @treturn self the element define to allow chaining +Prototype.set_post_authenticator = Constructor.setter('function','post_authenticator') + +--- Registers a callback to the on_draw event +-- @tparam function callback +-- callback param - LuaPlayer player - the player that the element was drawn to +-- callback param - LuaGuiElement element - the element that was drawn +-- callback param - any ... - any other params passed by the draw_to function +Prototype.on_draw = Constructor.event('on_draw') + +--- Registers a callback to the on_style_update event +-- @tparam function callback +-- callback param - LuaStyle style - the style that was changed and/or needs changing +Prototype.on_style_update = Constructor.event('on_style_update') + +--- Sets the style for the element define +-- @tparam string style the style that will be used for this element when drawn +-- @tparam[opt] callback function function is called when element is drawn to alter its style +-- @treturn self the element define to allow chaining +function Prototype:set_style(style,callback) + self.draw_data.style = style + if callback then + self:on_style_update(callback) + end + return self +end + +--- Sets the element to be drawn inside a nameless flow, can be given a name using a function +-- @tparam state ?boolean|function when true a padless flow is created to contain the element +-- @treturn self the element define to allow chaining +function Prototype:set_embeded_flow(state) + if state == false or type(state) == 'function' then + self.embeded_flow = state + else + self.embeded_flow = true + end + return self +end + +--- Raises a custom event for this define, any number of params can be given +-- @tparam string event_name the name of the event that you want to raise +-- @tparam any ... any params that you want to pass to the event +-- @treturn number the number of handlers that were registered +function Prototype:raise_event(event_name,...) + local handlers = self.events[event_name] + if handlers then + for _,handler in pairs(handlers) do + handler(...) + end + end + 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.embeded_flow then + local embeded_name + if type(self.embeded_flow) == 'function' then + embeded_name = self.embeded_flow(element,...) + end + element = element.add{type='flow',name=embeded_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 diff --git a/expcore/gui/test.lua b/expcore/gui/test.lua index ec4a77a2..ed6545dd 100644 --- a/expcore/gui/test.lua +++ b/expcore/gui/test.lua @@ -55,7 +55,7 @@ Gui.new_center_frame('gui-test-open') return global.show_test_gui end) -:on_draw(function(player,frame) +: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)) @@ -106,7 +106,7 @@ Gui.new_left_frame('test-left-frame') end) :set_open_by_default() -:on_draw(function(_player,frame) +:on_creation(function(_player,frame) for _,player in pairs(game.connected_players) do frame.add{ type='label', @@ -125,7 +125,7 @@ Event.add(defines.events.on_player_left_game,left_frame 'update_all') local test_popup = Gui.new_popup('test-popup') -:on_draw(function(player,frame) +:on_creation(function(player,frame) frame.add{ type='label', caption=player.name @@ -225,7 +225,7 @@ local checkbox_force = Gui.new_checkbox('test-checkbox-store-force') :set_tooltip('Checkboc store force') :set_caption('Checkbox Store Force') -:add_store(Gui.force_store) +:add_store(Gui.categorize_by_force) :on_element_update(function(player,element,state) player.print('Checkbox store force: '..tostring(state)) end) @@ -234,7 +234,7 @@ local checkbox_player = Gui.new_checkbox('test-checkbox-store-player') :set_tooltip('Checkbox store player') :set_caption('Checkbox Store Player') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,state) player.print('Checkbox store player: '..tostring(state)) end) @@ -265,7 +265,7 @@ local radiobutton_player = Gui.new_radiobutton('test-radiobutton-store') :set_tooltip('Radiobutton store') :set_caption('Radiobutton Store') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,state) player.print('Radiobutton store: '..tostring(state)) end) @@ -273,7 +273,7 @@ end) local radiobutton_option_set = Gui.new_radiobutton_option_set('gui.test.share',function(value,category) game.print('Radiobutton option set for: '..category..' is now: '..tostring(value)) -end,Gui.player_store) +end,Gui.categorize_by_player) local radiobutton_option_one = Gui.new_radiobutton('test-radiobutton-option-one') @@ -332,7 +332,7 @@ local dropdown_player_static_general = Gui.new_dropdown('test-dropdown-store-static-general') :set_tooltip('Dropdown store static general') :add_options('One','Two','Three','Four') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value) player.print('Dropdown store static general: '..tostring(value)) end) @@ -360,7 +360,7 @@ end local dropdown_player_static_case = Gui.new_dropdown('test-dropdown-store-static-case') :set_tooltip('Dropdown store static case') -:add_store(Gui.player_store) +:add_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) @@ -388,7 +388,7 @@ Gui.new_dropdown('test-dropdown-store-dynamic') :add_dynamic(function(player,element) return table_keys(Colors) end) -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value) player.print('Dropdown store dynamic: '..tostring(value)) end) @@ -420,7 +420,7 @@ local list_box_player = Gui.new_list_box('test-list-box-store') :set_tooltip('List box store') :add_options('One','Two','Three','Four') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value) player.print('Dropdown store: '..tostring(value)) end) @@ -433,7 +433,6 @@ tests["List Boxs"] = { --[[ Slider Tests > Local default -- Simple slider with default range - > Local notched -- Simple slider with notches > 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 @@ -448,18 +447,11 @@ Gui.new_slider('test-slider-local-default') player.print('Slider local default: '..tostring(math.round(value))..' '..tostring(math.round(percent,1))) end) -local slider_notched_default = -Gui.new_slider('test-slider-notched-default') -:set_tooltip('Silder notched default') -:use_notches() -:on_element_update(function(player,element,value,percent) - player.print('Slider notched default: '..tostring(math.round(value))..' '..tostring(math.round(percent,1))) -end) local slider_player_default = Gui.new_slider('test-slider-store-default') :set_tooltip('Silder store default') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value,percent) player.print('Slider store default: '..tostring(math.round(value))..' '..tostring(math.round(percent,1))) end) @@ -496,14 +488,13 @@ local label_slider_player = Gui.new_slider('test-slider-store-label') :set_tooltip('Silder store label') :enable_auto_draw_label() -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value,percent) player.print('Slider store label: '..tostring(math.round(value))..' '..tostring(math.round(percent,1))) end) tests.Sliders = { ['Local default']=slider_local_default, - ['Local notched']=slider_notched_default, ['Player default']=slider_player_default, ['Static range']=slider_static, ['Dynamic range']=slider_dynamic, @@ -535,7 +526,7 @@ end) local text_filed_store = Gui.new_text_filed('test-text-field-store') :set_tooltip('Text field store') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value) player.print('Text field store: '..value) end) @@ -603,7 +594,7 @@ local elem_store = Gui.new_elem_button('test-elem-store') :set_tooltip('Elem store') :set_type('item') -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :on_element_update(function(player,element,value) player.print('Elem store: '..value) end) @@ -632,7 +623,7 @@ end) local progressbar_two = Gui.new_progressbar('test-prog-one') :set_default_maximum(300) -:add_store(Gui.force_store) +:add_store(Gui.categorize_by_force) :on_complete(function(player,element,reset_element) reset_element() end) diff --git a/modules/gui/player-list.lua b/modules/gui/player-list.lua index 3add331d..92cbbabd 100644 --- a/modules/gui/player-list.lua +++ b/modules/gui/player-list.lua @@ -258,7 +258,7 @@ local function add_player(list_table,player,role_name) player_name.style.font_color = player.chat_color -- flow which allows right align for the play time - local time_flow = Gui.create_right_align(list_table,'player-time-'..player.index) + local time_flow = Gui.create_alignment(list_table,'player-time-'..player.index) -- time given in Xh Ym and is right aligned local tick = game.tick > 0 and game.tick or 1 @@ -295,7 +295,7 @@ Gui.new_left_frame('gui/player-list') :set_tooltip{'player-list.main-tooltip'} :set_open_by_default() :set_direction('vertical') -:on_draw(function(player,element) +:on_creation(function(player,element) local list_table,action_bar = generate_container(player,element) generate_action_bar(player,action_bar) diff --git a/modules/gui/rocket-info.lua b/modules/gui/rocket-info.lua index e2725717..f4ad5c19 100644 --- a/modules/gui/rocket-info.lua +++ b/modules/gui/rocket-info.lua @@ -163,7 +163,7 @@ local function create_section(container,section_name,table_size) } --- Right aligned button to toggle the section - local expand_flow = Gui.create_right_align(header,section_name) + local expand_flow = Gui.create_alignment(header,section_name) toggle_section(expand_flow) --- The area which contains the section content @@ -272,7 +272,7 @@ local function create_label_value_pair(element,data_name,value,tooltip,extra) tooltip={'rocket-info.data-tooltip-'..data_name,extra} } --- Right aligned label to store the data - local right_flow = Gui.create_right_align(element,data_name_extra) + local right_flow = Gui.create_alignment(element,data_name_extra) right_flow.add{ type='label', name='label', @@ -470,7 +470,7 @@ local function generate_progress(player,frame) } --- Creates the progress value which is right aligned - local right_flow = Gui.create_right_align(element,silo_name) + local right_flow = Gui.create_alignment(element,silo_name) right_flow.add{ type='label', name='label', @@ -517,7 +517,7 @@ end) return player.force.rockets_launched > 0 end) :set_direction('vertical') -:on_draw(function(player,element) +:on_creation(function(player,element) generate_container(player,element) generate_stats(player,element) generate_milestones(player,element) diff --git a/modules/gui/science-info.lua b/modules/gui/science-info.lua index 775035aa..09b0be17 100644 --- a/modules/gui/science-info.lua +++ b/modules/gui/science-info.lua @@ -142,7 +142,7 @@ local function generate_container(player,element) } -- data for the footer - local right_align = Gui.create_right_align(footer,'eta') + local right_align = Gui.create_alignment(footer,'eta') eta = right_align.add{ name='label', @@ -191,7 +191,7 @@ local function add_data_label(element,name,value,secondary,tooltip) else -- right aligned number - local right_align = Gui.create_right_align(element,name) + local right_align = Gui.create_alignment(element,name) local data = right_align.add{ name='label', @@ -341,7 +341,7 @@ Gui.new_left_frame('gui/science-info') :set_sprites('entity/lab') :set_direction('vertical') :set_tooltip{'science-info.main-tooltip'} -:on_draw(function(player,element) +:on_creation(function(player,element) local table, eta = generate_container(player,element) for _,science_pack in ipairs(config) do diff --git a/modules/gui/task-list.lua b/modules/gui/task-list.lua index 6e01b853..9cc02f89 100644 --- a/modules/gui/task-list.lua +++ b/modules/gui/task-list.lua @@ -211,7 +211,7 @@ function generate_task(player,element,task_id) Gui.set_padding(task_area) -- if the player can edit then it adds the edit and delete button - local flow = Gui.create_right_align(element,'edit-'..task_id) + local flow = Gui.create_alignment(element,'edit-'..task_id) local sub_flow = flow.add{type='flow',name=task_id} edit_task(sub_flow) @@ -330,7 +330,7 @@ local function generate_container(player,element) --- Right aligned button to toggle the section if player_allowed_edit(player) then - local right_align = Gui.create_right_align(header) + local right_align = Gui.create_alignment(header) add_new_task(right_align) end @@ -381,7 +381,7 @@ Gui.new_left_frame('gui/task-list') :set_direction('vertical') :set_tooltip{'task-list.main-tooltip'} :set_open_by_default() -:on_draw(function(player,element) +:on_creation(function(player,element) local data_table = generate_container(player,element) local force_name = player.force.name diff --git a/modules/gui/warp-list.lua b/modules/gui/warp-list.lua index aabac3d7..767fdfd1 100644 --- a/modules/gui/warp-list.lua +++ b/modules/gui/warp-list.lua @@ -254,7 +254,7 @@ local warp_timer = Gui.new_progressbar() :set_tooltip{'warp-list.timer-tooltip',config.recharge_time} :set_default_maximum(math.floor(config.recharge_time*config.update_smothing)) -:add_store(Gui.player_store) +:add_store(Gui.categorize_by_player) :set_style(nil,function(style) style.horizontally_stretchable = true style.color = Colors.light_blue @@ -449,7 +449,7 @@ function generate_warp(player,element,warp_id) Gui.set_padding(warp_area) -- if the player can edit then it adds the edit and delete button - local flow = Gui.create_right_align(element,'edit-'..warp_id) + local flow = Gui.create_alignment(element,'edit-'..warp_id) local sub_flow = flow.add{type='flow',name=warp_id} edit_warp(sub_flow) @@ -597,7 +597,7 @@ local function generate_container(player,element) --- Right aligned button to toggle the section if player_allowed_edit(player) then - local right_align = Gui.create_right_align(header) + local right_align = Gui.create_alignment(header) add_new_warp(right_align) end @@ -637,7 +637,7 @@ Gui.new_left_frame('gui/warp-list') :set_sprites('item/'..config.default_icon) :set_tooltip{'warp-list.main-tooltip',config.activation_range} :set_direction('vertical') -:on_draw(function(player,element) +:on_creation(function(player,element) local data_table = generate_container(player,element) local force_name = player.force.name @@ -655,7 +655,6 @@ end) local warps = force_warps[force_name] or {} for _,warp_id in pairs(warps) do generate_warp(player,data_table,warp_id) - make_warp_tag(warp_id) end end) :on_player_toggle(function(player,element,visible) @@ -790,4 +789,24 @@ Event.add(defines.events.on_player_created,function(event) end end) +local function maintain_tag(event) + local tag = event.tag + local force = event.force + local warps = force_warps[force.name] + if warps then + for _,warp_id in pairs(warps) do + local warp = warp_details[warp_id] + if not warp.tag or not warp.tag.valid or warp.tag == tag then + if event.name == defines.events.on_chart_tag_removed then + warp.tag = nil + end + make_warp_tag(warp_id) + end + end + end +end + +Event.add(defines.events.on_chart_tag_modified,maintain_tag) +Event.add(defines.events.on_chart_tag_removed,maintain_tag) + return warp_list \ No newline at end of file