Merge branch 'feature/gui-structure' into dev

This commit is contained in:
Cooldude2606
2019-05-24 20:02:43 +01:00
16 changed files with 1658 additions and 146 deletions

View File

@@ -14,10 +14,9 @@
Other functions present from expcore.gui.core
]]
local mod_gui = require 'mod-gui'
local Gui = require './core'
local Gui = require 'expcore.gui.core'
local Button = {
config={},
_prototype=Gui._prototype_factory{
on_click = Gui._event_factory('on_click'),
on_left_click = Gui._event_factory('on_left_click'),

191
expcore/Gui/center.lua Normal file
View File

@@ -0,0 +1,191 @@
--- Gui structure define for center gui frames
--[[
>>>> Functions
CenterFrames.get_flow(player) --- Gets the center flow for a player
CenterFrames.clear_flow(player) --- Clears the center flow for a player
CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing
CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destroy it and redraw
CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open
CenterFrames.new_frame(permision_name) --- Sets the frame to be the current active gui when opened and closes all other frames
CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame
CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames
CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it
CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
]]
local Gui = require 'expcore.gui.core'
local Toolbar = require 'expcore.gui.toolbar'
local Game = require 'utils.game'
local CenterFrames = {
_prototype = Gui._prototype_factory{
on_draw = Gui._event_factory('on_draw')
}
}
--- Gets the center flow for a player
-- @tparam player LuapPlayer the player to get the flow for
-- @treturn LuaGuiElement the center flow
function CenterFrames.get_flow(player)
player = Game.get_player_from_any(player)
return player.gui.center
end
--- Clears the center flow for a player
-- @tparam player LuapPlayer the player to clear the flow for
function CenterFrames.clear_flow(player)
local flow = CenterFrames.get_flow(player)
flow.clear()
end
--- Draws the center frame for a player, if already open then will do nothing
-- @tparam player LuapPlayer the player that will have the frame drawn
-- @tparam name string the name of the hui that will drawn
-- @treturn LuaGuiElement the new frame that was made
function CenterFrames.draw_frame(player,name)
local define = Gui.get_define(name,true)
if define then
return define:draw_frame(player)
end
end
--- Draws the center frame for a player, if already open then will destroy it and redraw
-- @tparam player LuapPlayer the player that will have the frame drawn
-- @tparam name string the name of the hui that will drawn
-- @treturn LuaGuiElement the new frame that was made
function CenterFrames.redraw_frame(player,name)
local define = Gui.get_define(name,true)
if define then
return define:draw_frame(player)
end
end
--- Toggles if the frame is currently open or not, will open if closed and close if open
-- @tparam player LuapPlayer the player that will have the frame toggled
-- @tparam name string the name of the hui that will be toggled
-- @tparam[opt] state boolean when set will force a state for the frame
-- @treturn boolean if the frame if no open or closed
function CenterFrames.toggle_frame(player,name,state)
local define = Gui.get_define(name,true)
if define then
if state == true then
define:draw_frame(player)
return true
elseif state == false then
local flow = CenterFrames.get_flow(player)
if flow[define.name] then
flow[define.name].destroy()
end
return false
else
return define:toggle_frame(player)
end
end
end
--- Creates a new center frame define
-- @tparam permision_name string the name that can be used with the permision system
-- @treturn table the new center frame define
function CenterFrames.new_frame(permision_name)
local self = Toolbar.new_button(permision_name)
self:on_click(function(player,element)
self:toggle_frame(player)
end)
local mt = getmetatable(self)
mt.__index = CenterFrames._prototype
mt.__call = self.event_handler
Gui.on_custom_close(self.name,function(event)
local element = event.element
if element and element.valid then element.destroy() end
end)
return self
end
--- Sets the frame to be the current active gui when opened and closes all other frames
-- @tparam[opt=true] state boolean when true will auto close other frames and set this frame as player.opened
function CenterFrames._prototype:set_auto_focus(state)
if state == false then
self.auto_focus = false
else
self.auto_focus = true
end
end
--- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
-- @tparam player LuaPlayer the player to draw the frame for
-- @treturn LuaGuiElement the new frame that was drawn
function CenterFrames._prototype:draw_frame(player)
player = Game.get_player_from_any(player)
local flow = CenterFrames.get_flow(player)
if flow[self.name] then
return flow[self.name]
end
if self.auto_focus then
flow.clear()
end
local frame = flow.add{
type='frame',
name=self.name
}
if self.auto_focus then
player.opened = frame
end
if self.events.on_draw then
self.events.on_draw(player,frame)
end
return frame
end
--- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
-- @tparam player LuaPlayer the player to draw the frame for
-- @treturn LuaGuiElement the new frame that was drawn
function CenterFrames._prototype:redraw_frame(player)
player = Game.get_player_from_any(player)
local flow = CenterFrames.get_flow(player)
if flow[self.name] then
flow[self.name].destroy()
end
return self:draw_frame(player)
end
--- Toggles if the frame is open, if open it will close it and if closed it will open it
-- @tparam player LuaPlayer the player to draw the frame for
-- @treturn boolean with the gui frame is now open
function CenterFrames._prototype:toggle_frame(player)
player = Game.get_player_from_any(player)
local flow = CenterFrames.get_flow(player)
if flow[self.name] then
flow[self.name].destroy()
return false
else
self:draw_frame(player)
return true
end
end
--- Creates an event handler that will trigger one of its functions, use with Event.add
-- @tparam[opt=update] action string the action to take on this event
function CenterFrames._prototype:event_handler(action)
action = action or 'update'
return function(event)
local player = Game.get_player_by_index(event.player_index)
self[action](self,player)
end
end
return CenterFrames

View File

@@ -45,7 +45,7 @@
Other functions present from expcore.gui.core
]]
local Gui = require './core'
local Gui = require 'expcore.gui.core'
local Store = require 'expcore.store'
local Game = require 'utils.game'

View File

@@ -152,17 +152,13 @@
]]
local Gui = require 'utils.gui'
local Game = require 'utils.game'
local Global = require 'utils.global'
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
Gui.instances = {} -- Stores runtime data of all active instances of an element define
Global.register(Gui.instances,function(tbl)
Gui.instances = tbl
end)
--- Used internally to create new prototypes for element defines
-- @tparam tbl table a table that will have functions added to it
@@ -211,24 +207,18 @@ function Gui._store_factory(callback)
self.store = Store.uid_location()
self.categorize = categorize
Gui.instances[self.name]={}
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
local instances = Gui.get_instances(self,category)
if instances then
for k,element in pairs(instances) do
if element and element.valid then
callback(self,element,value)
else
instances[k] = nil
end
end
if Instances.is_registered(self.name) then
Instances.apply_to_elements(self.name,category,function(element)
callback(self,element,value)
end)
end
end)
@@ -256,24 +246,18 @@ function Gui._sync_store_factory(callback)
self.store = location
self.categorize = categorize
Gui.instances[self.name]={}
Instances.register(self.name,self.categorize)
Store.register_synced(self.store,function(value,category)
if self.events.on_store_update then
self.events.on_store_update(value,category)
end
local instances = Gui.get_instances(self,category)
if instances then
for k,element in pairs(instances) do
if element and element.valid then
callback(self,element,value)
else
instances[k] = nil
end
end
if Instances.is_registered(self.name) then
Instances.apply_to_elements(self,category,function(element)
callback(self,element,value)
end)
end
end)
@@ -294,8 +278,8 @@ function Gui._define_factory(prototype)
}
},{
__index=prototype,
__call=function(self,element)
return self:draw_to(element)
__call=function(self,element,...)
return self:draw_to(element,...)
end
})
Gui.defines[define.name] = define
@@ -366,7 +350,7 @@ end
-- the data with in the draw_data is set up through the use of all the other functions
-- @tparam element LuaGuiElement the element that the define will draw a copy of its self onto
-- @treturn LuaGuiElement the new element that was drawn so styles can be applied
function Gui._prototype:draw_to(element)
function Gui._prototype:draw_to(element,...)
if element[self.name] then return end
local player = Game.get_player_by_index(element.player_index)
@@ -380,15 +364,11 @@ function Gui._prototype:draw_to(element)
new_element.enabled = self.post_authenticator(player,self.name)
end
if self.store then
local category = self.categorize and self.categorize(element) or nil
local instances = Gui.get_instances(self,category)
if instances then
table.insert(instances,new_element)
end
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
if self.post_draw then self.post_draw(new_element,...) end
return new_element
end
@@ -435,31 +415,13 @@ function Gui.get_define(name,internal)
return Gui.defines[Gui.names[name]]
elseif not define then
return error('Invalid name for checkbox, name not found.',internal and 3 or 2) or nil
return error('Invalid name for element define, name not found.',internal and 3 or 2) or nil
end
return define
end
--- Gets all instances of the element define, mostly internal use and note invalid elements may be present in the return
-- @tparam name string the uid or debug name for the define to get the instances for
-- @tparam[opt] category string the category to get the instances for
-- @treturn table a table of LuaGuiElements that might be invalid which belong to this define
function Gui.get_instances(name,category)
local define = Gui.get_define(name,true)
if not Gui.instances[define.name] then return end
local instances = Gui.instances[define.name]
if define.categorize then
if not instances[category] then instances[category] = {} end
return instances[category]
end
return instances
end
--- Gets the value that is stored for a given element define, category needed if categorize function used
-- @tparam name ?string|table the uid, debug name or define for the element define to get
-- @tparam[opt] category string the category to get the value for
@@ -507,9 +469,9 @@ end
-- @tparam name ?string|table the uid, debug name or define for the element define to draw
-- @tparam element LuaGuiEelement the parent element that it the define will be drawn to
-- @treturn LuaGuiElement the new element that was created
function Gui.draw(name,element)
function Gui.draw(name,element,...)
local define = Gui.get_define(name,true)
return define:draw_to(element)
return define:draw_to(element,...)
end
--- Will toggle the enabled state of an element
@@ -534,4 +496,18 @@ function Gui.toggle_visible(element)
end
end
--- Sets the padding for a gui element
-- @tparam element LuaGuiElement the element to set the padding for
-- @tparam[opt=0] up number the amount of padding on the top
-- @tparam[opt=0] down number the amount of padding on the bottom
-- @tparam[opt=0] left number the amount of padding on the left
-- @tparam[opt=0] right number the amount of padding on the right
function Gui.set_padding(element,up,down,left,right)
local style = element.style
style.top_padding = up or 0
style.bottom_padding = down or 0
style.left_padding = left or 0
style.right_padding = right or 0
end
return Gui

View File

@@ -16,7 +16,7 @@
Other functions present from expcore.gui.core
]]
local Gui = require './core'
local Gui = require 'expcore.gui.core'
local Game = require 'utils.game'
--- Event call for on_selection_state_changed and store update

View File

@@ -11,7 +11,7 @@
Other functions present from expcore.gui.core
]]
local Gui = require './core'
local Gui = require 'expcore.gui.core'
local Game = require 'utils.game'
--- Event call for on_elem_changed and store update

227
expcore/Gui/instances.lua Normal file
View File

@@ -0,0 +1,227 @@
--- This file is a breakout from core which forcues on instance management of defines
--[[
>>>> Using registered instance groups
The main use of this module is to register a group of elements refered here as "instances of an element define" in which
is meant that you define the name of a group of drawn elements that are really just multiple versions of a single element.
For example this might be that you have one label in multiple places (either for one player or many) and you want to update
the caption of all of them at once; this is where this module comes it.
First you must register the way that the intances are stored and under what name, using Instances.register you will give the
name of the collective group of instances followed by an optional categorise function which allows varients to be stored under one
name (like one for each force or player)
-- categorise works in the same way as store categorise
-- so the function will worl here but no value is stored only gui elements
Instances.register('score',Gui.force_store)
Then when you draw the new element to a gui you will want to add the element to the group:
Instances.add_element('score',new_element)
Then when you want to get the instances you have two options; Instances.get_elements or Instances.apply_to_elements when you want loop
over the elements it is more efficient to use apply_to_elements:
Instances.get_elements('score','player') -- returns all elements that were added with the 'player' category
Instances.apply_to_elements('score','player',function(element) -- runs the function on every valid element
element.caption = 0
end)
Note that if you dont give a categorise function then you dont need to give a category when getting the elements.
>>>> Using unregistered instance groups
When using a registered group and the functions that go with them it is much simpler to use and more importantly includes error checking
for valid instance group names; the down side is that the group must be registered which can only be done during startup and not during runtime.
To counter this there are two functions simlair to those above in order to add and get instances but may lead to errors not being noticed due to
the error interal error checking being skiped to allow it to work.
The main difference between the two groups of functions is that the category must always be present even if is nil; example below shows how a
instance group would work when registered vs unregistered:
-- Registered with category
Instances.register('score',Gui.force_store) -- force_store will return the force name of an element
Instances.add_element('score',new_element) -- the new element is added to the category based on in force
Instances.apply_to_elements('score','player',function(element)
element.caption = '0'
end) -- gets all instances from the player force and sets the caption to 0
-- Unregistered with category
Instances.unregistered_add_element('score','player',new_element) -- adds the new element to the player category
Instances.unregistered_apply_to_elements('score','player',function(element)
element.caption = '0'
end) -- gets all instances from the player force and sets the caption to 0
-- Registered without category; note that category can just be igroned
Instances.register('score') -- all instances will be under one group with no categories
Instances.add_element('score',new_element) -- adds the new element to the instance list
Instances.apply_to_elements('score',function(element)
element.caption = '0'
end) -- gets all instances and sets the element caption to 0
-- Unregistered without category; note that category must be given as nil
Instances.unregistered_add_element('score',nil,new_element) -- adds the new element to a single group with no categories
Instances.unregistered_apply_to_elements('score',nil,function(element)
element.caption = '0'
end) -- gets all instances and sets the element caption to 0
>>>> Functions
Instances.has_categories(name) --- Returns if a 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
Instances.add_element(name,element) --- Adds an element to the instance group under the correct category; must be registered
Instances.get_elements_raw(name,category) --- Gets all element instances without first removing any invalid ones; used internally and must be registered
Instances.get_valid_elements(name,category,callback) --- Gets all valid element instances and has the option of running a callback on those that are valid
Instances.unregistered_add_element(name,category,element) --- A version of add_element that does not require the group to be registered
Instances.unregistered_get_elements(name,category,callback) --- A version of get_elements that does not require the group to be registered
]]
local Global = require 'utils.global'
local Instances = {
categorise={},
data={}
}
Global.register(Instances.data,function(tbl)
Instances.data = tbl
end)
--- Returns if a instnace group has a categorise function; must be registerd
-- @tparam name string the name of the instance group
-- @treturn boolean true if there is a categorise function
function Instances.has_categories(name)
return type(Instances.categorise[name]) == 'function'
end
--- Returns if the given name is a registered instance group
-- @tparam name string the name of the instance group you are testing
-- @treturn boolean true if the name is registered
function Instances.is_registered(name)
return Instances.categorise[name] ~= nil
end
--- Registers the name of an instance group to allow for storing element instances
-- @tparam name string the name of the instance group; must to unique
-- @tparam[opt] categorise function function used to turn the element into a string
-- categorise param - element LuaGuiElement - the gui element to be turned into a string
-- categorise return - string - the category that the element will be added to like the player's name or force's name
-- @treturn string the name that was added so it can be used as a varible
function Instances.register(name,categorise)
if _LIFECYCLE ~= _STAGE.control then
return error('Can only be called during the control stage', 2)
end
if Instances.categorise[name] then
return error('Instances for '..name..' already exist.',2)
end
categorise = type(categorise) == 'function' and categorise or true
Instances.data[name] = {}
Instances.categorise[name] = categorise
return name
end
--- Adds an element to the instance group under the correct category; must be registered
-- @tparam name string the name of the instance group to add the element to
-- @tparam element LuaGuiElement the element to add the the instance group
function Instances.add_element(name,element)
if not Instances.categorise[name] then
return error('Inavlid name for instance group: '..name,2)
end
if Instances.has_categories(name) then
local category = Instances.categorise[name](element)
if not Instances.data[name][category] then Instances.data[name][category] = {} end
table.insert(Instances.data[name][category],element)
else
table.insert(Instances.data[name],element)
end
end
--- Gets all element instances without first removing any invalid ones; used internally and must be registered
-- @tparam name string the name of the instance group to get the instances of
-- @tparam[opt] category string the category to get the instance from, not needed when no categorise function
-- @treturn table the table of element instances of which some may be invalid
function Instances.get_elements_raw(name,category)
if not Instances.categorise[name] then
return error('Inavlid name for instance group: '..name,2)
end
if Instances.has_categories(name) then
return Instances.data[name][category] or {}
else
return Instances.data[name]
end
end
--- Gets all valid element instances and has the option of running a callback on those that are valid
-- @tparam name string the name of the instance group to get the instances of
-- @tparam[opt] category string the category to get the instances of, not needed when no categorise function
-- @tparan[opt] callback function when given the callback will be ran on all valid elements
-- callback param - element LuaGuiElement - the current valid element
-- @treturn table the table of element instances with all invalid ones removed
function Instances.get_valid_elements(name,category,callback)
if not Instances.categorise[name] then
return error('Inavlid name for instance group: '..name,2)
end
category = category or callback
local elements = Instances.get_elements_raw(name,category)
local categorise = Instances.has_categories(name)
for key,element in pairs(elements) do
if not element or not element.valid then
elements[key] = nil
else
if categorise and callback then callback(element)
elseif category then category(element) end
end
end
return elements
end
Instances.get_elements = Instances.get_valid_elements
Instances.apply_to_elements = Instances.get_valid_elements
--- A version of add_element that does not require the group to be registered
-- @tparam name string the name of the instance group to add the element to
-- @tparam category ?string|nil the category to add the element to, can be nil but must still be given
-- @tparam element LuaGuiElement the element to add to the instance group
function Instances.unregistered_add_element(name,category,element)
if not Instances.data[name] then Instances.data[name] = {} end
if category then
if not Instances.data[name][category] then Instances.data[name][category] = {} end
table.insert(Instances.data[name][category],element)
else
table.insert(Instances.data[name],element)
end
end
--- A version of get_elements that does not require the group to be registered
-- @tparam name string the name of the instance group to get the instances of
-- @tparam category ?string|nil the category to get the instances of, can be nil but must still be given
-- @tparam[opt] callback function when given will be called on all valid instances
-- callback param - element LuaGuiElement - the current valid element
-- @treturn table the table of element instances with all invalid ones removed
function Instances.unregistered_get_elements(name,category,callback)
local elements = Instances.data[name]
if elements and category then
elements = elements[category]
end
if not elements then return {} end
for key,element in pairs(elements) do
if not element or not element.valid then
elements[key] = nil
else
if callback then callback(element) end
end
end
return elements
end
Instances.unregistered_apply_to_elements = Instances.runtime_get_elements
return Instances

290
expcore/Gui/left.lua Normal file
View File

@@ -0,0 +1,290 @@
--- Gui structure define for left frames
--[[
>>>> Example formating
-- first we add config that relates to the button on the toolbar, all normal button functions are present
local left_frame =
Gui.new_left_frame('test-left-frame')
:set_caption('Test Left Gui')
:set_post_authenticator(function(player,button_name)
return global.show_test_gui
end)
-- then we add the config for the left frame, on_draw should draw the gui from an empty frame, on_update should take a frame from on_draw on edit it
:set_open_by_default()
:on_draw(function(_player,frame)
for _,player in pairs(game.connected_players) do
frame.add{
type='label',
caption=player.name
}
end
end)
-- now we can use the action factory to call events on the gui, actions are: 'update', 'update_all', 'redraw', 'redraw_all'
Event.add(defines.events.on_player_joined_game,left_frame 'update_all')
Event.add(defines.events.on_player_left_game,left_frame 'update_all')
>>>> Functions
LeftFrames.get_flow(player) --- Gets the left frame flow for a player
LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name
LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button
LeftFrames.toggle_frame(name,player,state) --- Toggles the visiblty of a left frame, or sets its visiblty state
LeftFrames.new_frame(permision_name) --- Creates a new left frame define
LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean
LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow
LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible
LeftFrames._prototype:toggle(player) --- Toggles the visiblty of the left frame
LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, oter wise will clear and redraw
LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update
LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame
LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw
LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame
LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it
LeftFrames._prototype: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 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')
}
}
setmetatable(LeftFrames._prototype, {
__index = Buttons._prototype
})
--- Gets the left frame flow for a player
-- @tparam player LuaPlayer the player to get the flow of
-- @treturn LuaGuiElement the left frame flow for the player
function LeftFrames.get_flow(player)
player = Game.get_player_from_any(player)
return mod_gui.get_frame_flow(player)
end
--- Gets one frame from the left flow by its name
-- @tparam name string the name of the gui frame to get
-- @tparam player LuaPlayer the player to get the frame of
-- @treturn LuaGuiElement the frame in the left frame flow with that name
function LeftFrames.get_frame(name,player)
local define = LeftFrames.frames[name]
if not define then
return error('Left Frame '..name..' is not defined.',2)
end
return define:get_frame(player)
end
--- Gets all open frames for a player, if non are open it will remove the close all button
-- @tparam player LuaPlayer the player to get the flow of
-- @treturn table contains all the open (and registered) frames for the player
function LeftFrames.get_open(player)
local open = {}
local flow = LeftFrames.get_flow(player)
for _,define in pairs(LeftFrames.frames) do
if define:is_open(player) then
table.insert(open,define)
end
end
flow[LeftFrames.toggle_button.name].visible = #open ~= 0
return open
end
--- Toggles the visiblty of a left frame, or sets its visiblty state
-- @tparam name string the name of the gui frame to toggle
-- @tparam player LuaPlayer the player to get the frame of
-- @tparam[opt] state boolean when given will be the state that the visiblty is set to
-- @treturn boolean the new state of the visiblity
function LeftFrames.toggle_frame(name,player,state)
local define = LeftFrames.frames[name]
if not define then
return error('Left Frame '..name..' is not defined.',2)
end
local frame = LeftFrames.get_frame(name,player)
if state ~= nil then
frame.visible = state
else
Gui.toggle_visible(frame)
end
LeftFrames.get_open(player)
return frame.visible
end
--- Creates a new left frame define
-- @tparam permision_name string 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)
mt.__index = LeftFrames._prototype
mt.__call = self.event_handler
self:on_click(function(player,_element)
self:toggle(player)
end)
LeftFrames.frames[self.name] = self
return self
end
--- Sets if the frame is visible when a player joins, can also be a function to return a boolean
-- @tparam[opt=true] state ?boolean|function the default state of the visiblty, can be a function
-- state param - player LuaPlayer - the player that has joined the game
-- state param - define_name string - the define name for the frame
-- state return - boolean - false will hide the frame
function LeftFrames._prototype:set_open_by_default(state)
if state == false then
self.open_by_default = false
else
self.open_by_default = state
end
return self
end
--- Gets the frame for this define from the left frame flow
-- @tparam player LuaPlayer the player to get the frame of
-- @treturn LuaGuiElement the frame in the left frame flow for this define
function LeftFrames._prototype:get_frame(player)
local flow = LeftFrames.get_flow(player)
if flow[self.name] and flow[self.name].valid then
return flow[self.name]
end
end
--- Returns if the player currently has this define visible
-- @tparam player LuaPlayer the player to get the frame of
-- @treturn boolean true if it is open/visible
function LeftFrames._prototype:is_open(player)
local frame = self:get_frame(player)
return frame and frame.visible or false
end
--- Toggles the visiblty of the left frame
-- @tparam player LuaPlayer the player to toggle the frame of
-- @treturn boolean the new state of the visiblity
function LeftFrames._prototype:toggle(player)
local frame = self:get_frame(player)
Gui.toggle_visible(frame)
LeftFrames.get_open(player)
return frame.visible
end
--- Updates the contents of the left frame, first tries update callback, oter wise will clear and redraw
-- @tparam player LuaPlayer 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
frame.clear()
self.events.on_draw(player,frame)
end
end
--- Updates the frame for all players, see update
-- @tparam[opt=false] update_offline boolean when true will update the frame for offline players
function LeftFrames._prototype:update_all(update_offline)
local players = update_offline == true and game.players or game.connected_players
for _,player in pairs(players) do
self:update(player)
end
end
--- Redraws the frame by calling on_draw, will always clear the frame
-- @tparam player LuaPlayer the player to update the frame of
function LeftFrames._prototype:redraw(player)
local frame = self:get_frame(player)
frame.claer()
if self.events.on_draw then
self.events.on_draw(player,frame)
end
end
--- Redraws the frame for all players, see redraw
-- @tparam[opt=false] update_offline boolean when true will update the frame for offline players
function LeftFrames._prototype:redraw_all(update_offline)
local players = update_offline == true and game.players or game.connected_players
for _,player in pairs(players) do
self:redraw(player)
end
end
--- Creates an event handler that will trigger one of its functions, use with Event.add
-- @tparam[opt=update] action string the action to take on this event
function LeftFrames._prototype:event_handler(action)
action = action or 'update'
return function(event)
local player = Game.get_player_by_index(event.player_index)
self[action](self,player)
end
end
LeftFrames.toggle_button =
Buttons.new_button()
:set_tooltip('Close Windows')
:set_caption('<')
:on_click(function(player,element)
for _,define in pairs(LeftFrames.frames) do
local frame = LeftFrames.get_frame(define.name,player)
frame.visible = false
end
element.visible = false
end)
Event.add(defines.events.on_player_created,function(event)
local player = Game.get_player_by_index(event.player_index)
local flow = LeftFrames.get_flow(player)
local close_button = LeftFrames.toggle_button(flow)
Gui.set_padding(close_button)
local style = close_button.style
style.width = 18
style.height = 36
style.font = 'default-small-bold'
for _,define in pairs(LeftFrames.frames) do
local frame = flow.add{
type='frame',
name=define.name
}
if define.events.on_draw then
define.events.on_draw(player,frame)
end
if define.open_by_default == false then
frame.visible = false
elseif type(define.open_by_default) == 'function' then
if not define.open_by_default(player,define.name) then
frame.visible = false
end
end
if not Toolbar.allowed(player,define.name) then
frame.visible = false
end
end
LeftFrames.get_open(player)
end)
return LeftFrames

228
expcore/Gui/popups.lua Normal file
View File

@@ -0,0 +1,228 @@
--- Gui structure define for popup gui
--[[
>>>> Functions
PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames
PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
PopupFrames.close_progress --- Progress bar which when depleaded will close the popup frame
PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out
PopupFrames.new_popup(name) --- Creates a new popup frame define
PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open
PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function
]]
local Gui = require 'expcore.gui.core'
local Game = require 'utils.game'
local Event = require 'utils.event'
local ProgressBar = require 'expcore.gui.progress-bar'
local Button = require 'expcore.gui.buttons'
local mod_gui = require 'mod-gui'
local Color = require 'resources.color_presets'
local Global = require 'utils.global'
local PopupFrames = {
paused_popups={},
popup_flow_name = Gui.uid_name(),
main_frame_name = Gui.uid_name(),
close_frame_name = Gui.uid_name(),
_prototype = Gui._prototype_factory{
on_draw = Gui._event_factory('on_draw')
}
}
Global.register(PopupFrames.paused_popups,function(tbl)
PopupFrames.paused_popups = tbl
end)
--- Sets the state of the element in the pasued list, nil or true
-- @tparam element LuaGuiElement the element to set the state of
-- @tparam[opt] state boolean the state to set it to, true will pause the the progress bar
local function set_pasued_state(element,state)
local name = element.player_index..':'..element.index
PopupFrames.paused_popups[name] = state
end
--- Gets the state of the element in the pasued list, nil or true
-- @tparam element LuaGuiElement the element to get the state of
local function get_pasued_state(element)
local name = element.player_index..':'..element.index
return PopupFrames.paused_popups[name]
end
--- Gets the left flow that contains the popup frames
-- @tparam player LuaPlayer the player to get the flow for
-- @treturn LuaGuiElement the left flow that contains the popup frames
function PopupFrames.get_flow(player)
player = Game.get_player_from_any(player)
local flow = mod_gui.get_frame_flow(player)
return flow[PopupFrames.popup_flow_name]
end
--- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
-- @tparam define_name string the name of the define that you want to open for the player
-- @tparam player LuaPlayer the player to open the popup for
-- @tparam[opt] open_time number the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default
-- @tparam ... any the other params that you want to pass to your on_draw event
-- @treturn LuaGuiElement the frame that was drawn, the inner gui flow which contains the content
function PopupFrames.open(define_name,player,open_time,...)
local define = Gui.get_define(define_name,true)
player = Game.get_player_from_any(player)
return define:open(player,open_time,...)
end
--- Closes the popup, is called by progress bar and close button
-- @tparam element LuaGuiElement either the progress bar or the close button
local function close_popup(element)
local frame = element.parent.parent.parent
if not frame or not frame.valid then return end
set_pasued_state(element.parent[PopupFrames.close_progress:uid()])
frame.destroy()
end
--- Progress bar which when depleaded will close the popup frame
PopupFrames.close_progress =
ProgressBar.new_progressbar()
:use_count_down()
:set_tooltip('Pause/Resume Auto-close')
:on_complete(function(player,element)
close_popup(element)
end)
--- A button which can be used to close the gui before the timer runs out
PopupFrames.close_button =
Button.new_button()
:set_sprites('utility/close_white')
:set_tooltip('Close Popup')
:on_click(function(player,element)
close_popup(element)
end)
--- When the progress bar is clicked it will pause its progress, or resume if previously paused
Gui.on_click(PopupFrames.close_progress:uid(),function(event)
local element = event.element
if get_pasued_state(element) then
set_pasued_state(element)
else
set_pasued_state(element,true)
end
end)
--- When the parent flow of the progress bar is clicked it will pause its progress, or resume if previously paused
Gui.on_click(PopupFrames.close_frame_name,function(event)
local element = event.element[PopupFrames.close_progress:uid()]
if get_pasued_state(element) then
set_pasued_state(element)
else
set_pasued_state(element,true)
end
end)
--- Creates a new popup frame define
-- @tparam[opt] name string 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)
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,...)
-- main content frame
local frame = element.add{
type='flow',
name=PopupFrames.main_frame_name
}
frame.style.horizontally_stretchable = true
-- flow for progress bar and close button
local close_flow = element.add{
type='flow',
name=PopupFrames.close_frame_name
}
close_flow.style.horizontally_stretchable = true
-- progress bar, when 0 then a static full one is drawn
local progress_style
if maximum == 0 then
progress_style = close_flow.add{
type='progressbar',
tooltip='No Auto-close',
value=1
}.style
else
progress_style = PopupFrames.close_progress(close_flow,maximum).style
end
progress_style.top_padding = 6
progress_style.bottom_padding = 3
progress_style.height = 11
progress_style.color = Color.grey
-- close button, will close the popup when clicked
local close_button = PopupFrames.close_button(close_flow)
Gui.set_padding(close_button)
local close_button_style = close_button.style
close_button_style.width = 20
close_button_style.height = 20
-- event trigger to draw the gui content
if self.events.on_draw then
local player = Game.get_player_by_index(element.player_index)
self.events.on_draw(player,frame,...)
end
end
return self
end
--- Sets the default open time for the popup, will be used if non is provided with open
-- @tparam amount number the number of ticks, by default, the popup will be open for
-- @treturn table the define to allow for chaining
function PopupFrames._prototype:set_default_open_time(amount)
self.default_open_time = amount
return self
end
--- Opens this define for a player, can be given open time and any other params for the draw function
-- @tparam player LuaPlayer the player to open the popup for
-- @tparam[opt] open_time number the minimum number of ticks you want the popup open for, 0 means no limit, nil will take default
-- @tparam ... any the other params that you want to pass to your on_draw event
-- @treturn LuaGuiElement the frame that was drawn, the inner gui flow which contains the content
function PopupFrames._prototype:open(player,open_time,...)
open_time = open_time or self.default_open_time or 0
player = Game.get_player_from_any(player)
local flow = PopupFrames.get_flow(player)
local frame = flow.add{
type='frame',
style='blurry_frame'
}
Gui.set_padding(frame,3,3,4,4)
return self:draw_to(frame,open_time,...)[PopupFrames.main_frame_name]
end
--- When player is first created the popup flow is added to they left flow
Event.add(defines.events.on_player_created,function(event)
local player = Game.get_player_by_index(event.player_index)
local flow = mod_gui.get_frame_flow(player)
flow.add{
type='flow',
direction='vertical',
name=PopupFrames.popup_flow_name
}
end)
--- Every tick any, not pasued, progress bars will go down by one tick
Event.add(defines.events.on_tick,PopupFrames.close_progress:event_countdown(function(element)
return not get_pasued_state(element)
end))
return PopupFrames

View File

@@ -0,0 +1,390 @@
--- Gui element define for progess bars
--[[
>>>> Functions
ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented
ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decresed
ProgressBar.new_progressbar(name) --- Creates a new progressbar element define
ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0
ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar
ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store
ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar
ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store
ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store
ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0
ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element compeltes (hits 0 or 1)
ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1)
ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggeres, can filter which elements are incremented
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 Global = require 'utils.global'
local Game = require 'utils.game'
--- Event call for when the value is outside the range 0-1
-- @tparam define table the define that this is acting on
-- @tparam element LuaGuiElement 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
end
--- Store call for store update
-- @tparam define table the define that this is acting on
-- @tparam element LuaGuiElement the element that triggered the event
local function store_call(define,element,value)
if value then
element.value = value
if define.count_down and value <= 0
or not define.count_down and value >= 1 then
event_call(define,element)
end
end
end
local ProgressBar = {
unregistered={}, -- elements with no callbacks
independent={}, -- elements with a link to a 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)
}
}
Global.register({
ProgressBar.unregistered,
ProgressBar.independent
},function(tbl)
ProgressBar.unregistered = tbl[1]
ProgressBar.independent = tbl[2]
end)
--- Gets the define data, cant use Gui.get_define as it would error
-- @tparam define ?table|string the define to get
-- @treturn table the define or nil
local function get_define(define)
if type(define) == 'table' then
if define.name and Gui.defines[define.name] then
return Gui.defines[define.name]
end
end
return Gui.defines[define]
end
--- Gets the element data, used when there is no define
-- @tparam element LuaGuiElement
-- @treturn table the element data simialr to define
local function get_element(element)
if not element.valid then return end
local name = element.player_index..':'..element.index
if ProgressBar.unregistered[name] then
return ProgressBar.unregistered[name]
end
end
--- Sets the maximum value that represents the end value of the progress bar
-- @tparam element ?LuaGuiElement|string either a gui element or a registered define
-- @tparam amount number the amount to have set as the maximum
function ProgressBar.set_maximum(element,amount)
amount = amount > 0 and amount or error('amount must be greater than 0')
local define = get_define(element)
if define then
define:set_deafult_maximum(amount)
else
local element_data = get_element(element)
if element_data then
element_data.maximum = amount
else
local name = element.player_index..':'..element.index
ProgressBar.unregistered[name] = {
element=element,
maximum=amount or 1
}
end
end
end
--- Increases the value of the progressbar, if a define is given all of its instances are incremented
-- @tapram element ?LuaGuiElement|string either a gui element or a registered define
-- @tparam[opt=1] amount number the amount to increase the progressbar by
function ProgressBar.increment(element,amount)
amount = type(amount) == 'number' and amount or 1
local define = get_define(element)
if define then
define:increment(amount)
else
local element_data = get_element(element)
if element_data then
local real_amount = amount/element_data.maximum
element.value = element.value + real_amount
if element.value >= 1 then
local name = element.player_index..':'..element.index
ProgressBar.unregistered[name] = nil
return true
end
end
end
end
--- Decreases the value of the progressbar, if a define is given all of its instances are decresed
-- @tapram element ?LuaGuiElement|string either a gui element or a registered define
-- @tparam[opt=1] amount number the amount to decrease the progressbar by
function ProgressBar.decrement(element,amount)
amount = type(amount) == 'number' and amount or 1
local define = get_define(element)
if define then
define:decrement(amount)
else
local element_data = get_element(element)
if element_data then
local real_amount = amount/element_data.maximum
element.value = element.value - real_amount
if element.value <= 0 then
local name = element.player_index..':'..element.index
ProgressBar.unregistered[name] = nil
return true
end
end
end
end
--- Creates a new progressbar element define
-- @tparam[opt] name string 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)
self.draw_data.type = 'progressbar'
if name then
self:debug_name(name)
end
self.post_draw = function(element,maximum)
if self.store then
local category = self.categorize and self.categorize(element) or nil
local value = self:get_store(category)
if not value then
value = self.count_down and 1 or 0
self:set_store(category,value)
end
element.value = value
else
if self.count_down then
element.value = 1
end
if not ProgressBar.independent[self.name] then
ProgressBar.independent[self.name] = {}
end
table.insert(ProgressBar.independent[self.name],{
element = element,
maximum = maximum
})
end
end
return self
end
--- Sets the maximum value that represents the end value of the progress bar
-- @tparam amount number the amount to have set as the maximum
-- @treturn table the define to allow chaining
function ProgressBar._prototype:set_default_maximum(amount)
amount = amount > 0 and amount or error('amount must be greater than 0')
self.default_maximum = amount
return self
end
--- Will set the progress bar to start at 1 and trigger when it hits 0
-- @tparam[opt=true] state boolean when true the bar will start filled, to be used with decrease
-- @treturn table the define to allow chaining
function ProgressBar._prototype:use_count_down(state)
if state == false then
self.count_down = false
else
self.count_down = true
end
return self
end
--- Main logic for changing the value of a progress bar, this only applies when its a registered define
-- @tparam self table the define that is being changed
-- @tparam amount number the amount which it is being changed by, may be negative
-- @tparam[opt] category string the category to use with store
local function change_value_prototype(self,amount,category,filter)
local function reset_store()
local value = self.count_down and 1 or 0
local _category = category or value
self:set_store(_category,value)
end
if self.store then
local value = self:get_store(category) or self.count_down and 1 or 0
local maximum = self.default_maximum or 1
local new_value = value + (amount/maximum)
if self.count_down and new_value <= 0
or not self.count_down and new_value >= 1 then
self:set_store(category)
if self.events.on_store_complete then
category = category or reset_store
self.events.on_store_complete(category,reset_store)
end
end
category = category or new_value
self:set_store(category,new_value)
return
end
if ProgressBar.independent[self.name] then
for key,element_data in pairs(ProgressBar.independent[self.name]) do
local element = element_data.element
if not element or not element.valid then
ProgressBar.independent[self.name][key] = nil
else
if not filter or filter(element) then
local maximum = element_data.maximum or self.default_maximum or 1
element.value = element.value + (amount/maximum)
if self.count_down and element.value <= 0
or not self.count_down and element.value >= 1 then
ProgressBar.independent[self.name][key] = nil
event_call(self,element)
end
end
end
end
end
end
--- Increases the value of the progressbar
-- @tparam[opt=1] amount number the amount to increase the progressbar by
-- @tparam[opt] category string the category that is used with a store
function ProgressBar._prototype:increment(amount,category)
amount = type(amount) == 'number' and amount or 1
change_value_prototype(self,amount,category)
end
--- Increases the value of the progressbar, if the filter condition is met, does not work with store
-- @tparam[opt=1] amount number the amount to increase the progressbar by
-- @tparam[opt] category string the category that is used with a store
function ProgressBar._prototype:increment_filtered(amount,filter)
amount = type(amount) == 'number' and amount or 1
change_value_prototype(self,amount,nil,filter)
end
--- Decreases the value of the progressbar
-- @tparam[opt=1] amount number the amount to decrease the progressbar by
-- @tparam[opt] category string the category that is used with a store
function ProgressBar._prototype:decrement(amount,category)
amount = type(amount) == 'number' and amount or 1
change_value_prototype(self,-amount,category)
end
--- Decreases the value of the progressbar, if the filter condition is met, does not work with store
-- @tparam[opt=1] amount number the amount to decrease the progressbar by
-- @tparam[opt] category string the category that is used with a store
function ProgressBar._prototype:decrement_filtered(amount,filter)
amount = type(amount) == 'number' and amount or 1
change_value_prototype(self,-amount,nil,filter)
end
--- Adds an element into the list of instances that will are waiting to complete, does not work with store
-- note use store if you want persistent data, this only stores the elements not the values which they have
-- @tparam element LuaGuiElement the element that you want to add into the waiting to complete list
-- @tparam[opt] maximum number the maximum for this element if not given the default for this define is used
function ProgressBar._prototype:add_element(element,maximum)
if self.store then return end
if not ProgressBar.independent[self.name] then
ProgressBar.independent[self.name] = {}
end
table.insert(ProgressBar.independent[self.name],{
element = element,
maximum = maximum
})
end
--- Resets an element, or its store, to be back at the start, either 1 or 0
-- @tparam element LuaGuiElement the element that you want to reset the progress of
function ProgressBar._prototype:reset_element(element)
if not element or not element.valid then return end
local value = self.count_down and 1 or 0
if self.store then
local category = self.categorize and self.categorize(element) or value
self:set_store(category,value)
else
element.value = value
end
end
--- Event handler factory that counts up by 1 every time the event triggeres, can filter which elements are incremented
-- @tparam[opt] filter function when given will use filtered incerement
-- @treturn function the event handler
function ProgressBar._prototype:event_counter(filter)
if type(filter) == 'function' then
return function()
self:increment_filtered(1,filter)
end
else
return function()
self:increment()
end
end
end
--- Event handler factory that counts down by 1 every time the event triggeres, can filter which elements are decremented
-- @tparam[opt] filter function when given will use filtered decerement
-- @treturn function the event handler
function ProgressBar._prototype:event_countdown(filter)
if type(filter) == 'function' then
return function()
self:decrement_filtered(1,filter)
end
else
return function()
self:decrement()
end
end
end
return ProgressBar

View File

@@ -6,54 +6,17 @@
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
Other functions present from expcore.gui.core
]]
local Gui = require './core'
local Gui = require 'expcore.gui.core'
local Instances = require 'expcore.gui.instances'
local Game = require 'utils.game'
--- Gets the active lables for a define
-- @tparam define table the define to get the labels for
-- @tparam element LuaGuiElement the element that will be used to get the category
-- @treturn table the table of active instances for the slider lables
local function get_labels(define,element)
local function cat(e)
return e.player_index
end
local name = define.name..'-label'
if not Gui.instances[name] then return end
local categorize = define.categorize or not define.store and cat
local category = categorize and categorize(element) or nil
local instances = Gui.get_instances({
name=name,
categorize=categorize
},category)
return instances
end
--- Gets and updates the label values
-- @tparam define table the define to get the labels for
-- @tparam element LuaGuiElement the element that will be used to get the category
local function update_lables(define,element)
local instances = get_labels(define,element)
local value = element.slider_value
if instances then
for k,instance in pairs(instances) do
if instance and instance.valid then
instance.caption = tostring(math.round(value,2))
else
instances[k]=nil
end
end
end
end
--- Event call for on_value_changed and store update
-- @tparam define table the define that this is acting on
-- @tparam element LuaGuiElement the element that triggered the event
@@ -69,7 +32,14 @@ local function event_call(define,element,value)
define.events.on_element_update(player,element,value,percent)
end
update_lables(define,element)
local category = player.name
if define.categorize then
category = define.categorize(element)
end
Instances.unregistered_get_elements(define.name..'-label',category,function(label)
label.caption = tostring(math.round(value,2))
end)
end
--- Store call for store update
@@ -145,6 +115,17 @@ function Slider.new_slider(name)
return self
end
--- Adds notches to the slider
-- @tparam[opt] state boolean 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] min number the minimum value that the slider can take
-- @tparam[opt] max number the maximum value that the slider can take
@@ -183,10 +164,10 @@ function Slider._prototype:draw_label(element)
caption=tostring(math.round(value,2))
}
if not Gui.instances[name] then Gui.instances[name] = {} end
local categorise = self.categorise or Gui.player_store
local category = categorise(new_element)
local labels = get_labels(self,element)
table.insert(labels,new_element)
Instances.unregistered_add_element(name,category,new_element)
return new_element
end

View File

@@ -4,7 +4,8 @@
local Gui = require 'expcore.gui'
local format_chat_colour,table_keys = ext_require('expcore.common','format_chat_colour','table_keys')
local Colors = require 'resources.color_presets'
local Game = require 'utils.game'
local Event = require 'utils.event'
local Store = require 'expcore.store'
local tests = {}
@@ -13,7 +14,6 @@ local tests = {}
> No display - Toolbar button with no display
> With caption - Toolbar button with a caption display
> With icons - Toolbar button with an icon
> Main test gui - Main test gui triggers all other tests
]]
Gui.new_toolbar_button('click-1')
@@ -42,20 +42,19 @@ end)
player.print('CLICK 3')
end)
Gui.new_toolbar_button('gui-test-open')
--[[
Center Frame Tests
> Main test gui - Main test gui triggers all other tests
]]
local test_gui =
Gui.new_center_frame('gui-test-open')
:set_caption('Open Test Gui')
:set_post_authenticator(function(player,button_name)
return global.show_test_gui
end)
:on_click(function(player,_element)
if player.gui.center.TestGui then player.gui.center.TestGui.destroy() return end
local frame = player.gui.center.add{
type='frame',
caption='Gui Test',
name='TestGui'
}
:on_draw(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))
@@ -92,6 +91,58 @@ end)
end
end)
--[[
Left Frame Test
> Left frame which holds all online player names, updates when player leaves or joins
]]
local left_frame =
Gui.new_left_frame('test-left-frame')
:set_caption('Test Left Gui')
:set_post_authenticator(function(player,button_name)
return global.show_test_gui
end)
:set_open_by_default()
:on_draw(function(_player,frame)
for _,player in pairs(game.connected_players) do
frame.add{
type='label',
caption=player.name
}
end
end)
Event.add(defines.events.on_player_joined_game,left_frame 'update_all')
Event.add(defines.events.on_player_left_game,left_frame 'update_all')
--[[
Popup Test
> Allows opening a popup which contains the players name and tick it was opened
]]
local test_popup =
Gui.new_popup('test-popup')
:on_draw(function(player,frame)
frame.add{
type='label',
caption=player.name
}
frame.add{
type='label',
caption=game.tick
}
end)
Gui.new_toolbar_button('test-popup-open')
:set_caption('Test Popup')
:set_post_authenticator(function(player,button_name)
return global.show_test_gui
end)
:on_click(function(player,element)
test_popup(player,300)
end)
--[[
Button Tests
> No display - Simple button which has no display
@@ -379,6 +430,7 @@ 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
@@ -393,6 +445,14 @@ 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')
@@ -440,6 +500,7 @@ 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,
@@ -549,4 +610,52 @@ tests["Elem Buttons"] = {
['Default']=elem_default,
['Function']=elem_function,
['Store']=elem_store
}
--[[
Progress bar tests
> Simple -- Progress bar that fills every 2 seconds
> Store -- Progress bar that fills every 5 seconds with synced value
> Reverce -- Progress bar that decreases every 2 seconds
]]
local progressbar_one =
Gui.new_progressbar('test-prog-one')
:set_default_maximum(120)
:on_complete(function(player,element,reset_element)
reset_element()
end)
local progressbar_two =
Gui.new_progressbar('test-prog-one')
:set_default_maximum(300)
:add_store(Gui.force_store)
:on_complete(function(player,element,reset_element)
reset_element()
end)
:on_store_complete(function(category,reset_store)
reset_store()
end)
local progressbar_three =
Gui.new_progressbar('test-prog-one')
:set_default_maximum(120)
:use_count_down()
:on_complete(function(player,element,reset_element)
reset_element()
end)
Event.add(defines.events.on_tick,function()
progressbar_one:increment()
progressbar_three:decrement()
local categories = Store.get_children(progressbar_two.store)
for category,_ in pairs(categories) do
progressbar_two:increment(1,category)
end
end)
tests["Progress Bars"] = {
['Simple']=progressbar_one,
['Store']=progressbar_two,
['Reverce']=progressbar_three
}

View File

@@ -14,7 +14,7 @@
Other functions present from expcore.gui.core
]]
local Gui = require './core'
local Gui = require 'expcore.gui.core'
local Game = require 'utils.game'
--- Event call for on_text_changed and store update

View File

@@ -1,28 +1,47 @@
--- Gui structure for the toolbar (top left)
--[[
>>>> Example format
-- this is the same as any other button define, this just automatically draws it
-- you can use add_button if you already defined the button
local toolbar_button =
Toolbar.new_button('print-click')
:on_click(function(player,_element)
player.print('You clicked a button!')
end)
>>>> Functions
Toolbar.new_button(name) --- Adds a new button to the toolbar
Toolbar.add_button(button) --- Adds an existing buttton to the toolbar
Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return
]]
local Buttons = require './buttons'
local Gui = require './core'
local Buttons = require 'expcore.gui.buttons'
local Gui = require 'expcore.gui.core'
local Roles = require 'expcore.roles'
local Event = require 'utils.event'
local Game = require 'utils.game'
local Toolbar = {
permisison_names = {},
buttons = {}
}
function Toolbar.allowed(player,define_name)
local permisison_name = Toolbar.permisison_names[define_name] or define_name
return Roles.player_allowed(player,permisison_name)
end
function Toolbar.permission_alias(define_name,permisison_name)
Toolbar.permisison_names[define_name] = permisison_name
end
--- Adds a new button to the toolbar
-- @tparam[opt] name string the name of the button to be added
-- @tparam[opt] name string when given allows an alias to the button for the permission system
-- @treturn table the button define
function Toolbar.new_button(name)
name = name or #Toolbar.buttons+1
local button = Buttons.new_button('toolbar/'..name)
button:set_post_authenticator(Roles.player_allowed)
local button = Buttons.new_button()
button:set_post_authenticator(Toolbar.allowed)
Toolbar.add_button(button)
Toolbar.permission_alias(button.name,name)
return button
end

View File

@@ -1,7 +1,7 @@
--- This file is used to require all the different elements of the gui module
-- each module has an outline here but for more details see their seperate files in ./gui
local Gui = require('./gui/core')
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
@@ -36,7 +36,14 @@ local Gui = require('./gui/core')
Gui.toggle_visible(element) --- Will toggle the visiblity of an element
]]
local Button = require('./gui/buttons')
local Instances = require 'expcore.gui.instances'
Gui.new_instance_group = Instances.registers
Gui.get_instances = Instances.get_elements
Gui.add_instance = Instances.get_elements
Gui.update_instances = Instances.apply_to_elements
Gui.classes.instances = Instances
local Button = require 'expcore.gui.buttons'
Gui.new_button = Button.new_button
Gui.classes.button = Button
--[[
@@ -51,18 +58,7 @@ Gui.classes.button = Button
Button._prototype:set_key_filter(filter,...) --- Adds a control key filter to the button
]]
local Toolbar = require('./gui/toolbar')
Gui.new_toolbar_button = Toolbar.new_button
Gui.add_button_to_toolbar = Toolbar.add_button
Gui.update_toolbar = Toolbar.update
Gui.classes.toolbar = Toolbar
--[[
Toolbar.new_button(name) --- Adds a new button to the toolbar
Toolbar.add_button(button) --- Adds an existing buttton to the toolbar
Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return
]]
local Checkbox = require('./gui/checkboxs')
local Checkbox = require 'expcore.gui.checkboxs'
Gui.new_checkbox = Checkbox.new_checkbox
Gui.new_radiobutton = Checkbox.new_radiobutton
Gui.new_radiobutton_option_set = Checkbox.new_option_set
@@ -84,7 +80,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('./gui/dropdown')
local Dropdown = require 'expcore.gui.dropdown'
Gui.new_dropdown = Dropdown.new_dropdown
Gui.new_list_box = Dropdown.new_list_box
Gui.classes.dropdown = Dropdown
@@ -103,7 +99,7 @@ Gui.classes.dropdown = Dropdown
Dropdown.get_selected_value(element) --- Returns the currently selected value rather than index
]]
local Slider = require('./gui/slider')
local Slider = require 'expcore.gui.slider'
Gui.new_slider = Slider.new_slider
Gui.classes.slider = Slider
--[[
@@ -112,12 +108,13 @@ 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('./gui/text')
local Text = require 'expcore.gui.text'
Gui.new_text_filed = Text.new_text_field
Gui.new_text_box = Text.new_text_box
Gui.classes.text = Text
@@ -134,7 +131,7 @@ Gui.classes.text = Text
Text._prototype_box:set_read_only(state) --- Sets the text box to be read only
]]
local ElemButton = require('./gui/elem-button')
local ElemButton = require 'expcore.gui.elem-button'
Gui.new_elem_button = ElemButton.new_elem_button
Gui.classes.elem_button = ElemButton
--[[
@@ -147,4 +144,109 @@ 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'
Gui.new_progressbar = ProgressBar.new_progressbar
Gui.set_progressbar_maximum = ProgressBar.set_maximum
Gui.increment_progressbar = ProgressBar.increment
Gui.decrement_progressbar = ProgressBar.decrement
Gui.classes.progressbar = ProgressBar
--[[
ProgressBar.set_maximum(element,amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
ProgressBar.increment(element,amount) --- Increases the value of the progressbar, if a define is given all of its instances are incremented
ProgressBar.decrement(element,amount) --- Decreases the value of the progressbar, if a define is given all of its instances are decresed
ProgressBar.new_progressbar(name) --- Creates a new progressbar element define
ProgressBar._prototype:set_maximum(amount,count_down) --- Sets the maximum value that represents the end value of the progress bar
ProgressBar._prototype:use_count_down(state) --- Will set the progress bar to start at 1 and trigger when it hits 0
ProgressBar._prototype:increment(amount,category) --- Increases the value of the progressbar
ProgressBar._prototype:increment_filtered(amount,filter) --- Increases the value of the progressbar, if the filter condition is met, does not work with store
ProgressBar._prototype:decrement(amount,category) --- Decreases the value of the progressbar
ProgressBar._prototype:decrement_filtered(amount,filter) --- Decreases the value of the progressbar, if the filter condition is met, does not work with store
ProgressBar._prototype:add_element(element,maximum) --- Adds an element into the list of instances that will are waiting to complete, does not work with store
ProgressBar._prototype:reset_element(element) --- Resets an element, or its store, to be back at the start, either 1 or 0
ProgressBar._prototype:on_complete(callback) --- Triggers when a progress bar element compeltes (hits 0 or 1)
ProgressBar._prototype:on_complete(callback) --- Triggers when a store value completes (hits 0 or 1)
ProgressBar._prototype:event_counter(filter) --- Event handler factory that counts up by 1 every time the event triggeres, can filter which elements are incremented
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'
Gui.new_toolbar_button = Toolbar.new_button
Gui.add_button_to_toolbar = Toolbar.add_button
Gui.update_toolbar = Toolbar.update
Gui.classes.toolbar = Toolbar
--[[
Toolbar.new_button(name) --- Adds a new button to the toolbar
Toolbar.add_button(button) --- Adds an existing buttton to the toolbar
Toolbar.update(player) --- Updates the player's toolbar with an new buttons or expected change in auth return
]]
local LeftFrames = require 'expcore.gui.left'
Gui.get_left_frame_flow = LeftFrames.get_flow
Gui.toggle_left_frame = LeftFrames.toggle_frame
Gui.new_left_frame = LeftFrames.new_frame
Gui.classes.left_frames = LeftFrames
--[[
LeftFrames.get_flow(player) --- Gets the left frame flow for a player
LeftFrames.get_frame(name,player) --- Gets one frame from the left flow by its name
LeftFrames.get_open(player) --- Gets all open frames for a player, if non are open it will remove the close all button
LeftFrames.toggle_frame(name,player,state) --- Toggles the visiblty of a left frame, or sets its visiblty state
LeftFrames.new_frame(permision_name) --- Creates a new left frame define
LeftFrames._prototype:set_open_by_default(state) --- Sets if the frame is visible when a player joins, can also be a function to return a boolean
LeftFrames._prototype:get_frame(player) --- Gets the frame for this define from the left frame flow
LeftFrames._prototype:is_open(player) --- Returns if the player currently has this define visible
LeftFrames._prototype:toggle(player) --- Toggles the visiblty of the left frame
LeftFrames._prototype:update(player) --- Updates the contents of the left frame, first tries update callback, oter wise will clear and redraw
LeftFrames._prototype:update_all(update_offline) --- Updates the frame for all players, see update
LeftFrames._prototype:redraw(player) --- Redraws the frame by calling on_draw, will always clear the frame
LeftFrames._prototype:redraw_all(update_offline) --- Redraws the frame for all players, see redraw
LeftFrames._prototype:on_draw(player,frame) --- Use to draw your elements to the new frame
LeftFrames._prototype:on_update(player,frame) --- Use to edit your frame when there is no need to redraw it
LeftFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
]]
local CenterFrames = require 'expcore.gui.center'
Gui.get_center_flow = CenterFrames.get_flow
Gui.toggle_left_frame = CenterFrames.toggle_frame
Gui.draw_center_frame = CenterFrames.draw_frame
Gui.redraw_center_frame = CenterFrames.redraw_frames
Gui.new_center_frame = CenterFrames.new_frame
Gui.classes.center_frames = CenterFrames
--[[
CenterFrames.get_flow(player) --- Gets the center flow for a player
CenterFrames.clear_flow(player) --- Clears the center flow for a player
CenterFrames.draw_frame(player,name) --- Draws the center frame for a player, if already open then will do nothing
CenterFrames.redraw_frame(player,name) --- Draws the center frame for a player, if already open then will destory it and redraw
CenterFrames.toggle_frame(player,name,state) --- Toggles if the frame is currently open or not, will open if closed and close if open
CenterFrames.new_frame(permision_name) --- Sets the frame to be the current active gui when opened and closes all other frames
CenterFrames._prototype:on_draw(player,frame) --- Use to draw your elements onto the new frame
CenterFrames._prototype:set_auto_focus(state) --- Sets the frame to be the current active gui when opened and closes all other frames
CenterFrames._prototype:draw_frame(player) --- Draws this frame to the player, if already open does nothing (will call on_draw to draw to the frame)
CenterFrames._prototype:redraw_frame(player) --- Draws this frame to the player, if already open it will remove it and redraw it (will call on_draw to draw to the frame)
CenterFrames._prototype:toggle_frame(player) --- Toggles if the frame is open, if open it will close it and if closed it will open it
CenterFrames._prototype:event_handler(action) --- Creates an event handler that will trigger one of its functions, use with Event.add
]]
local PopupFrames = require 'expcore.gui.popups'
Gui.get_popup_flow = PopupFrames.get_flow
Gui.open_popup = PopupFrames.open
Gui.new_popup = PopupFrames.new_popup
Gui.classes.popup_frames = PopupFrames
--[[
PopupFrames.get_flow(player) --- Gets the left flow that contains the popup frames
PopupFrames.open(define_name,player,open_time,...) --- Opens a popup for the player, can give the amount of time it is open as well as params for the draw function
PopupFrames.close_progress --- Progress bar which when depleaded will close the popup frame
PopupFrames.close_button --- A button which can be used to close the gui before the timer runs out
PopupFrames.new_popup(name) --- Creates a new popup frame define
PopupFrames._prototype:set_default_open_time(amount) --- Sets the default open time for the popup, will be used if non is provided with open
PopupFrames._prototype:open(player,open_time,...) --- Opens this define for a player, can be given open time and any other params for the draw function
]]
return Gui

View File

@@ -17,7 +17,7 @@ local interface_modules = {
-- loads all the modules given in the above table
for key,value in pairs(interface_modules) do
if type(value) == 'string' then
interface_modules[key] = require(value)
interface_modules[key] = Common.opt_require(value)
end
end