Updated ExpGamingCore.Gui

This commit is contained in:
Cooldude2606
2018-12-09 15:47:18 +00:00
parent 874d97cc28
commit 1db000dcf0
22 changed files with 452 additions and 346 deletions

View File

@@ -1,215 +0,0 @@
--- Adds a uniform preset for guis in the center of the screen which allow for different tabs to be opened
-- @module ExpGamingCore.Gui.Center
-- @alias center
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This is a submodule of ExpGamingCore.Gui but for ldoc reasons it is under its own module
-- @function _comment
local Game = require('FactorioStdLib.Game')
local Color = require('FactorioStdLib.Color')
local mod_gui = require("mod-gui")
local Gui = Gui -- this is to force gui to remain in the ENV
local center = {}
center._prototype = {}
--- Adds a new obj to the center gui
-- @usage Gui.center.add{name='foo',caption='Foo',tooltip='Testing',draw=function}
-- @usage return_value(player) -- opens the center gui for that player
-- @param obj contains the new object, needs name, fraw is opt and is function(root_frame)
-- @return the object made, used to add tabs, calling the returned value will open the center for the given player
function center.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.name,'string') then return end
verbose('Created Center Gui: '..obj.name)
setmetatable(obj,{__index=center._prototype,__call=function(self,player) return center.open(player,self.name) end})
obj.tabs = {}
obj._tabs = {}
Gui.data('center',obj.name,obj)
Gui.toolbar(obj.name,obj.caption,obj.tooltip,obj.open)
return obj
end
--- Used to get the center frame of the player, used mainly in script
-- @usage Gui.center.get_flow(player) -- returns gui emelemt
-- @param player a player indifier to get the flow for
-- @treturn table the gui element flow
function center.get_flow(player)
local player = Game.get_player(player)
if not player then error('Invalid player',2) end
return player.gui.center.exp_center or player.gui.center.add{name='exp_center',type='flow'}
end
--- Used to open a center frame for a player
-- @usage Gui.center.open(player,'server-info') -- return true
-- @param player a player indifier to get the flow for
-- @tparam string center the name of the center frame to open
-- @treturn boelon based on if it successed or not
function center.open(player,center)
local player = Game.get_player(player)
if not player then error('Invalid player',2) return false end
Gui.center.clear(player)
if not Gui.data.center[center] then return false end
Gui.data.center[center].open{
element={name=center},
player_index=player.index
}
return true
end
--- Used to open a center frame for a player
-- @usage Gui.center.open_tab(player,'readme','rules') -- return true
-- @param player a player indifier to get the flow for
-- @tparam string center the name of the center frame to open
-- @tparam string tab the name of the tab to open
-- @treturn boelon based on if it successed or not
function center.open_tab(player,center,tab)
local player = Game.get_player(player)
if not player then error('Invalid player',2) end
if not Gui.center.open(player,center) then return false end
local name = center..'_'..tab
if not Gui.data.inputs_button[name] then return false end
Gui.data.inputs_button[name].events[defines.events.on_gui_click]{
element=Gui.center.get_flow(player)[center].tab_bar.tab_bar_scroll.tab_bar_scroll_flow[name],
}
return true
end
--- Used to clear the center frame of the player, used mainly in script
-- @usage Gui.center.clear(player)
-- @param player a player indifier to get the flow for
function center.clear(player)
local player = Game.get_player(player)
center.get_flow(player).clear()
end
-- used on the button press when the toolbar button is press, can be overriden
-- not recomented for direct use see Gui.center.open
function center._prototype.open(event)
local player = Game.get_player(event)
local _center = Gui.data.center[event.element.name]
local center_flow = center.get_flow(player)
if center_flow[_center.name] then Gui.center.clear(player) return end
local center_frame = center_flow.add{
name=_center.name,
type='frame',
caption=_center.caption,
direction='vertical',
style=mod_gui.frame_style
}
if is_type(center_frame.caption,'string') and player.gui.is_valid_sprite_path(center_frame.caption) then center_frame.caption = '' end
if is_type(_center.draw,'function') then
local success, err = pcall(_center.draw,_center,center_frame)
if not success then error(err) end
else error('No Callback on center frame '.._center.name)
end
player.opened=center_frame
end
-- this is the default draw function if one is not provided, can be overriden
-- not recomented for direct use see Gui.center.open
function center._prototype:draw(frame)
Gui.bar(frame,510)
local tab_bar = frame.add{
type='frame',
name='tab_bar',
style='image_frame',
direction='vertical'
}
tab_bar.style.width = 510
tab_bar.style.height = 65
local tab_bar_scroll = tab_bar.add{
type='scroll-pane',
name='tab_bar_scroll',
horizontal_scroll_policy='auto-and-reserve-space',
vertical_scroll_policy='never'
}
tab_bar_scroll.style.vertically_squashable = false
tab_bar_scroll.style.vertically_stretchable = true
tab_bar_scroll.style.width = 500
local tab_bar_scroll_flow = tab_bar_scroll.add{
type='flow',
name='tab_bar_scroll_flow',
direction='horizontal'
}
Gui.bar(frame,510)
local tab = frame.add{
type ='frame',
name='tab',
direction='vertical',
style='image_frame'
}
tab.style.width = 510
tab.style.height = 305
local tab_scroll = tab.add{
type ='scroll-pane',
name='tab_scroll',
horizontal_scroll_policy='never',
vertical_scroll_policy='auto'
}
tab_scroll.style.vertically_squashable = false
tab_scroll.style.vertically_stretchable = true
tab_scroll.style.width = 500
local tab_scroll_flow = tab_scroll.add{
type='flow',
name='tab_scroll_flow',
direction='vertical'
}
tab_scroll_flow.style.width = 480
Gui.bar(frame,510)
local first_tab = nil
for name,button in pairs(self.tabs) do
first_tab = first_tab or name
button(tab_bar_scroll_flow).style.font_color = defines.color.white
end
self._tabs[self.name..'_'..first_tab](tab_scroll_flow)
tab_bar_scroll_flow.children[1].style.font_color = defines.color.orange
frame.parent.add{type='frame',name='temp'}.destroy()--recenter the GUI
end
--- If deafult draw is used then you can add tabs to the gui with this function
-- @usage _center:add_tab('foo','Foo','Just a tab',function)
-- @tparam string name this is the name of the tab
-- @tparam string caption this is the words that appear on the tab button
-- @tparam[opt] string tooltip the tooltip that is on the button
-- @tparam function callback this is called when button is pressed with function(root_frame)
-- @return self to allow chaining of _center:add_tab
function center._prototype:add_tab(name,caption,tooltip,callback)
verbose('Created Tab: '..self.name..'/'..name)
self._tabs[self.name..'_'..name] = callback
self.tabs[name] = Gui.inputs.add{
type='button',
name=self.name..'_'..name,
caption=caption,
tooltip=tooltip
}:on_event('click',function(event)
local tab = event.element.parent.parent.parent.parent.tab.tab_scroll.tab_scroll_flow
tab.clear()
local frame_name = tab.parent.parent.parent.name
local _center = Gui.data.center[frame_name]
local _tab = _center._tabs[event.element.name]
if is_type(_tab,'function') then
for _,button in pairs(event.element.parent.children) do
if button.name == event.element.name then
button.style.font_color = defines.color.orange
else
button.style.font_color = defines.color.white
end
end
local success, err = pcall(_tab,tab)
if not success then error(err) end
end
end)
return self
end
-- used so that when gui close key is pressed this will close the gui
center._events = {[defines.events.on_gui_closed]=function(event)
if event.element and event.element.valid then event.element.destroy() end
end}
center.on_role_change = center.clear
-- calling will attempt to add a new gui
return setmetatable(center,{__call=function(self,...) return self.add(...) end})

View File

@@ -1,385 +0,0 @@
--- Adds a clean way of making new inputs for a gui allowing for sliders and text inputs to be hanndleded with custom events
-- @module ExpGamingCore.Gui.Inputs
-- @alias inputs
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This is a submodule of ExpGamingCore.Gui but for ldoc reasons it is under its own module
-- @function _comment
local Game = require('FactorioStdLib.Game')
local Color = require('FactorioStdLib.Color')
local mod_gui = require("mod-gui")
local Gui = Gui -- this is to force gui to remain in the ENV
local inputs = {}
inputs._prototype = {}
-- these are just so you can have short cuts to this
inputs.events = {
error='error',
state=defines.events.on_gui_checked_state_changed,
click=defines.events.on_gui_click,
elem=defines.events.on_gui_elem_changed,
selection=defines.events.on_gui_selection_state_changed,
text=defines.events.on_gui_text_changed,
slider=defines.events.on_gui_value_changed
}
--- Sets the input to trigger on an certain event
-- @usage button:on_event(defines.events.on_gui_click,player_return)
-- @param event the event to raise callback on | can be number of the event | can be a key of inputs.events
-- @tparam function callback the function you want to run on the event
-- @treturn table returns self so you can chain together
function inputs._prototype:on_event(event,callback)
if not is_type(callback,'function') then return self end
if inputs.events[event] then event = inputs.events[event] end
if event == 'error' then self._error = callback return self end
self.events[event] = callback
return self
end
--- Draw the input into the root element
-- @usage button:draw(frame)
-- @param root the element you want to add the input to
-- @return returns the element that was added
function inputs._prototype:draw(root)
local player = Game.get_player(root.player_index)
if is_type(self.draw_data.caption,'string') and player.gui.is_valid_sprite_path(self.draw_data.caption) then
local data = table.deepcopy(self.draw_data)
data.type = 'sprite-button'
data.sprite = data.caption
data.caption = nil
return root.add(data)
elseif is_type(self.draw_data.sprite,'string') and player.gui.is_valid_sprite_path(self.draw_data.sprite) then
local data = table.deepcopy(self.draw_data)
data.type = 'sprite-button'
return root.add(data)
elseif is_type(self.data._state,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._state,player,root)
if success then data.state = err else error(err) end
return root.add(data)
elseif is_type(self.data._start,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._start,player,root)
if success then data.value = err else error(err) end
return root.add(data)
elseif is_type(self.data._index,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._index,player,root)
if success then data.selected_index = err else error(err) end
if is_type(self.data._items,'function') then
local success, err = pcall(self.data._items,player,root)
if success then data.items = err else error(err) end
end
return root.add(data)
elseif is_type(self.data._items,'function') then
local data = table.deepcopy(self.draw_data)
local success, err = pcall(self.data._items,player,root)
if success then data.items = err else error(err) end
if is_type(self.data._index,'function') then
local success, err = pcall(self.data._index,player,root)
if success then data.selected_index = err else error(err) end
end
return root.add(data)
else
return root.add(self.draw_data)
end
end
--- Add a new input, this is the same as doing frame.add{} but returns a diffrent object
-- @usage Gui.inputs.add{type='button',name='test',caption='Test'}
-- @usage return_value(frame) -- draws the button onto that frame
-- @tparam table obj the new element to add if caption is a sprite path then sprite is used
-- @treturn table the custom input object, calling the returned calue will draw the button
function inputs.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.type,'string') then return end
local type = obj.type
if type == 'button' or
type == 'sprite-button' or
type == 'choose-elem-button' or
type == 'checkbox' or
type == 'radiobutton' or
type == 'textfield' or
type == 'text-box' or
type == 'slider' or
type == 'drop-down'
then else return end
verbose('Created Input: '..obj.name..' ('..obj.type..')')
if obj.type == 'button' or obj.type == 'sprite-button' then obj.style = mod_gui.button_style end
obj.draw_data = table.deepcopy(obj)
obj.data = {}
obj.events = {}
setmetatable(obj,{__index=inputs._prototype,__call=function(self,...) return self:draw(...) end})
Gui.data('inputs_'..type,obj.name,obj)
return obj
end
-- this just runs the events given to inputs
function inputs._event_handler(event)
if not event.element then return end
local elements = Gui.data['inputs_'..event.element.type] or {}
local element = elements[event.element.name]
if not element and event.element.type == 'sprite-button' then
elements = Gui.data.inputs_button or {}
element = elements[event.element.name]
end
if element then
verbose('There was a gui event ('..Event.names[event.name]..') with element: '..event.element.name)
if not is_type(element.events[event.name],'function') then return end
local success, err = Manager.sandbox(element.events[event.name],{},event)
if not success then
if is_type(element._error,'function') then pcall(element._error)
else error(err) end
end
end
end
inputs._events = {
[inputs.events.state]=inputs._event_handler,
[inputs.events.click]=inputs._event_handler,
[inputs.events.elem]=inputs._event_handler,
[inputs.events.state]=inputs._event_handler,
[inputs.events.text]=inputs._event_handler,
[inputs.events.slider]=inputs._event_handler,
[inputs.events.selection]=inputs._event_handler
}
-- the folwing functions are just to make inputs easier but if what you want is not include use inputs.add(obj)
--- Used to define a button, can have many function
-- @usage Gui.inputs.add_button('test','Test','Just for testing',{{condition,callback},...})
-- @tparam string name the name of this button
-- @tparam string the display for this button, either text or sprite path
-- @tparam string tooltip the tooltip to show on the button
-- @param callbacks can either be a single function or a list of function pairs see exaplmes at bottom
-- @treturn table the button object that was made, to allow a custom error event if wanted
function inputs.add_button(name,display,tooltip,callbacks)
local button = inputs.add{
type='button',
name=name,
caption=display,
tooltip=tooltip
}
button.data._callbacks = callbacks
button:on_event('click',function(event)
local elements = Gui.data['inputs_'..event.element.type] or {}
local button = elements[event.element.name]
if not button and event.element.type == 'sprite-button' then
elements = Gui.data.inputs_button or {}
button = elements[event.element.name]
end
local player = Game.get_player(event)
local mouse = event.button
local keys = {alt=event.alt,ctrl=event.control,shift=event.shift}
local element = event.element
local callbacks = button.data._callbacks
if is_type(callbacks,'function') then callbacks = {{function(...) return true end,callbacks}} end
for _,data in pairs(callbacks) do
if is_type(data[1],'function') and is_type(data[2],'function') then
local success, err = pcall(data[1],player,mouse,keys,event)
if success and err == true then
local success, err = pcall(data[2],player,element,event)
if not success then error(err) end
elseif not success then error(err) end
else error('Invalid Callback Condition Format') end
end
end)
return button
end
--- Used to define a choose-elem-button callback only on elem_changed
-- @usage Gui.inputs.add_elem_button('test','Test','Just for testing',function)
-- @tparam string name the name of this button
-- @tparam string elem_type the display for this button, either text or sprite path
-- @tparam string tooltip the tooltip to show on the button
-- @tparam function callback the callback to call on change function(player,element,elem)
-- @treturn table the button object that was made, to allow a custom error event if wanted
function inputs.add_elem_button(name,elem_type,tooltip,callback)
local button = inputs.add{
type='choose-elem-button',
name=name,
elem_type=elem_type,
tooltip=tooltip
}
button.data._callback = callback
button:on_event('elem',function(event)
local button = Gui.data['inputs_'..event.element.type][event.element.name]
local player = Game.get_player(event)
local element = event.element or {elem_type=nil,elem_value=nil}
local elem = {type=element.elem_type,value=element.elem_value}
if is_type(button.data._callback,'function') then
local success, err = pcall(button.data._callback,player,element,elem)
if not success then error(err) end
else error('Invalid Callback') end
end)
return button
end
--- Used to define a checkbox callback only on state_changed
-- @usage Gui.inputs.add_checkbox('test',false,'Just for testing',function,function,funvtion)
-- @tparam string name the name of this button
-- @tparam boolean radio if this is a radio button
-- @tparam string display the display for this button, either text or sprite path
-- @tparam function default the callback which choses the default check state
-- @tparam function callback_true the callback to call when changed to true
-- @tparam function callback_false the callback to call when changed to false
-- @treturn table the button object that was made, to allow a custom error event if wanted
function inputs.add_checkbox(name,radio,display,default,callback_true,callback_false)
local type = 'checkbox'; if radio then type='radiobutton' end
local state = false; if is_type(default,'boolean') then state = default end
local checkbox = inputs.add{
type=type,
name=name,
caption=display,
state=state
}
if is_type(default,'function') then checkbox.data._state = default end
checkbox.data._true = callback_true
checkbox.data._false = callback_false
checkbox:on_event('state',function(event)
local checkbox = Gui.data['inputs_'..event.element.type][event.element.name]
local player = Game.get_player(event)
local state = event.element.state
if state then
if is_type(checkbox.data._true,'function') then
local success, err = pcall(checkbox.data._true,player,event.element)
if not success then error(err) end
else error('Invalid Callback') end
else
if is_type(checkbox.data._false,'function') then
local success, err = pcall(checkbox.data._false,player,event.element)
if not success then error(err) end
else error('Invalid Callback') end
end
end)
return checkbox
end
--- Used to reset the state of radio buttons, recomened to be called on_state_change to reset any radio buttons it is ment to work with.
-- @usage Gui.inputs.reset_radio{radio1,radio2,...}
-- @param elements can be a list of elements or a single element
function inputs.reset_radio(elements)
if #elements > 0 then
for _,element in pairs(elements) do
if element.valid then
local _elements = Gui.data['inputs_'..element.type] or {}
local _element = _elements[element.name]
local player = Game.get_player(element.player_index)
local state = false
local success, err = pcall(_element.data._state,player,element.parent)
if success then state = err else error(err) end
element.state = state
end
end
else
if elements.valid then
local _elements = Gui.data['inputs_'..elements.type] or {}
local _element = _elements[elements.name]
local player = Game.get_player(elements.player_index)
local state = false
local success, err = pcall(_element.data._state,player,elements.parent)
if success then state = err else error(err) end
elements.state = state
end
end
end
--- Used to define a text callback only on text_changed
-- @usage Gui.inputs.add_text('test',false,'Just for testing',function)
-- @tparam string name the name of this button
-- @tparam boolean box is it a text box rather than a text field
-- @tparam string text the starting text
-- @tparam function callback the callback to call on change function(player,text,element)
-- @treturn table the text object that was made, to allow a custom error event if wanted
function inputs.add_text(name,box,text,callback)
local type = 'textfield'; if box then type='text-box' end
local textbox = inputs.add{
type=type,
name=name,
text=text
}
textbox.data._callback = callback
textbox:on_event('text',function(event)
local textbox = Gui.data['inputs_'..event.element.type][event.element.name]
local player = Game.get_player(event)
local element = event.element
local callback = textbox.data._callback
if is_type(callback,'function') then
local success, err = pcall(callback,player,element.text,element)
if not success then error(err) end
else error('Invalid Callback Condition Format') end
end)
return textbox
end
--- Used to define a slider callback only on value_changed
-- @usage Gui.inputs.add_slider('test','horizontal',1,10,5,function)
-- @tparam string name the name of this button
-- @tparam string orientation direction of the slider
-- @tparam number min the lowest number
-- @tparam number max the highest number
-- @tparam function start_callback either a number or a function to return a number
-- @tparam function callback the function to be called on value_changed function(player,value,percent,element)
-- @treturn table the slider object that was made, to allow a custom error event if wanted
function inputs.add_slider(name,orientation,min,max,start_callback,callback)
local slider = inputs.add{
type='slider',
name=name,
orientation=orientation,
minimum_value=min,
maximum_value=max,
value=start_callback
}
slider.data._start = start_callback
slider.data._callback = callback
slider:on_event('slider',function(event)
local slider = Gui.data['inputs_'..event.element.type][event.element.name]
local player = Game.get_player(event)
local value = event.element.slider_value
local data = slider.data
local percent = value/event.element.get_slider_maximum()
if is_type(data._callback,'function') then
local success, err = pcall(data._callback,player,value,percent,event.element)
if not success then error(err) end
else error('Invalid Callback Condition Format') end
end)
return slider
end
--- Used to define a drop down callback only on value_changed
-- @usage Gui.inputs.add_drop_down('test',{1,2,3},1,function)
-- @tparam string name name of the drop down
-- @param items either a list or a function which returns a list
-- @param index either a number or a function which returns a number
-- @tparam function callback the callback which is called when a new index is selected function(player,selected,items,element)
-- @treturn table the drop-down object that was made, to allow a custom error event if wanted
function inputs.add_drop_down(name,items,index,callback)
local drop_down = inputs.add{
type='drop-down',
name=name,
items=items,
selected_index=index
}
drop_down.data._items = items
drop_down.data._index = index
drop_down.data._callback = callback
drop_down:on_event('selection',function(event)
local drop_down = Gui.data['inputs_'..event.element.type][event.element.name]
local player = Game.get_player(event)
local element = event.element
local items = element.items
local selected = items[element.selected_index]
local callback = drop_down.data._callback
if is_type(callback,'function') then
local success, err = pcall(callback,player,selected,items,element)
if not success then error(err) end
else error('Invalid Callback Condition Format') end
end)
return drop_down
end
-- calling will attempt to add a new input
return setmetatable(inputs,{__call=function(self,...) return self.add(...) end})
-- to see examples look at GuiParts/test.lua

View File

@@ -1,240 +0,0 @@
--- Adds a organiser for left gui ellements which will automaticaly update there information and have open requirements
-- @module ExpGamingCore.Gui.Left
-- @alias left
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This is a submodule of ExpGamingCore.Gui but for ldoc reasons it is under its own module
-- @function _comment
local Game = require('FactorioStdLib.Game')
local Server = require('ExpGamingCore.Server')
local Color = require('FactorioStdLib.Color')
local Role -- this is optional and is hanndled by it being present, it is loaded on init
local mod_gui = require("mod-gui")
local Gui = Gui -- this is to force gui to remain in the ENV
local order_config = order_config
local left = {}
left._prototype = {}
left.hide = Gui.inputs{
name='gui-left-hide',
type='button',
caption='<'
}:on_event('click',function(event)
for _,child in pairs(event.element.parent.children) do
if child.name ~= 'popups' then child.style.visible = false end
end
end)
local global = self_global
-- used for debugging
function left.override_open(state)
global.over_ride_left_can_open = state
end
--- Used to add a left gui frame
-- @usage Gui.left.add{name='foo',caption='Foo',tooltip='just testing',open_on_join=true,can_open=function,draw=function}
-- @usage return_value(player) -- toggles visiblity for that player, if no player then updates for all players
-- @param obj this is what will be made, needs a name and a draw function(root_frame), open_on_join can be used to set the deaful state true/false, can_open is a test to block it from opening but is not needed
-- @return the object that is made, calling the returned value with out a param will update the gui, else will toggle visiblity for that player
function left.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.name,'string') then return end
verbose('Created Left Gui: '..obj.name)
setmetatable(obj,{__index=left._prototype,__call=function(self,player) if player then return self:toggle(player) else return left.update(self.name) end end})
Gui.data('left',obj.name,obj)
Gui.toolbar(obj.name,obj.caption,obj.tooltip,function(event) obj:toggle(event) end)
return obj
end
--- This is used to update all the guis of connected players, good idea to use our thread system as it as nested for loops
-- @usage Gui.left.update()
-- @tparam[opt] string frame this is the name of a frame if you only want to update one
-- @param[opt] players the player to update for, if not given all players are updated, can be one player
function left.update(frame,players)
if not Server or not Server._thread then
local players = is_type(players,'table') and #players > 0 and {unpack(players)} or is_type(players,'table') and {players} or Game.get_player(players) and {Game.get_player(players)} or game.connected_players
for _,player in pairs(players) do
local frames = Gui.data.left or {}
if frame then frames = {[frame]=frames[frame]} or {} end
for name,left in pairs(frames) do
if _left then left:first_open(player) end
end
end
else
local frames = Gui.data.left or {}
if frame then frames = {[frame]=frames[frame]} or {} end
local players = is_type(players,'table') and #players > 0 and {unpack(players)} or is_type(players,'table') and {players} or Game.get_player(players) and {Game.get_player(players)} or game.connected_players
Server.new_thread{
data={players=players,frames=frames}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
Server.new_thread{
data={player=player,frames=thread.data.frames}
}:on_event('resolve',function(thread)
for name,left in pairs(thread.data.frames) do
if left then left:first_open(thread.data.player) end
end
end):queue()
end):open()
end
end
--- Used to open the left gui of every player
-- @usage Gui.left.open('foo')
-- @tparam string left_name this is the gui that you want to open
-- @tparam[opt] LuaPlayer the player to open the gui for
function left.open(left_name,player)
local players = player and {player} or game.connected_players
local _left = Gui.data.left[left_name]
if not _left then return end
if not Server or not Server._thread then
for _,player in pairs(players) do _left:open(player) end
else
Server.new_thread{
data={players=players}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
_left:open(player)
end):open()
end
end
--- Used to close the left gui of every player
-- @usage Gui.left.close('foo')
-- @tparam string left_name this is the gui that you want to close
-- @tparam[opt] LuaPlayer the player to close the gui for
function left.close(left_name,player)
local players = player and {player} or game.connected_players
local _left = Gui.data.left[left_name]
if not _left then return end
if not Server or not Server._thread or player then
for _,player in pairs(players) do _left:close(player) end
else
Server.new_thread{
data={players=players}
}:on_event('tick',function(thread)
if #thread.data.players == 0 then thread:close() return end
local player = table.remove(thread.data.players,1)
_left:close(player)
end):open()
end
end
--- Used to force the gui open for the player
-- @usage left:open(player)
-- @tparam luaPlayer player the player to open the gui for
function left._prototype:open(player)
local player = Game.get_player(player)
if not player then error('Invalid Player') end
local left_flow = mod_gui.get_frame_flow(player)
if not left_flow[self.name] then self:first_open(player) end
left_flow[self.name].style.visible = true
if left_flow['gui-left-hide'] then left_flow['gui-left-hide'].style.visible = true end
end
--- Used to force the gui closed for the player
-- @usage left:open(player)
-- @tparam luaPlayer player the player to close the gui for
function left._prototype:close(player)
local player = Game.get_player(player)
if not player then error('Invalid Player') end
local left_flow = mod_gui.get_frame_flow(player)
if not left_flow[self.name] then self:first_open(player) end
left_flow[self.name].style.visible = false
local count = 0
for _,child in pairs(left_flow.children) do if child.style.visible then count = count+1 end if count > 1 then break end end
if count == 1 and left_flow['gui-left-hide'] then left_flow['gui-left-hide'].style.visible = false end
end
--- When the gui is first made or is updated this function is called, used by the script
-- @usage left:first_open(player) -- returns the frame
-- @tparam LuaPlayer player the player to draw the gui for
-- @treturn LuaFrame the frame made/updated
function left._prototype:first_open(player)
local player = Game.get_player(player)
local left_flow = mod_gui.get_frame_flow(player)
local frame = nil
if left_flow[self.name] then
frame = left_flow[self.name]
frame.clear()
else
if not left_flow['gui-left-hide'] then left.hide(left_flow).style.maximal_width=15 end
frame = left_flow.add{type='frame',name=self.name,style=mod_gui.frame_style,caption=self.caption,direction='vertical'}
frame.style.visible = false
if is_type(self.open_on_join,'boolean') then frame.style.visible = self.open_on_join left_flow['gui-left-hide'].style.visible = true end
end
if is_type(self.draw,'function') then self.draw(frame) else frame.style.visible = false error('No Callback On '..self.name) end
return frame
end
--- Toggles the visiblity of the gui based on some conditions
-- @usage left:toggle(player) -- returns new state
-- @tparam LuaPlayer player the player to toggle the gui for, remember there are condition which need to be met
-- @treturn boolean the new state that the gui is in
function left._prototype:toggle(player)
local player = Game.get_player(player)
local left_flow = mod_gui.get_frame_flow(player)
if not left_flow[self.name] then self:first_open(player) end
local left = left_flow[self.name]
local open = false
if is_type(self.can_open,'function') then
local success, err = pcall(self.can_open,player)
if not success then error(err)
elseif err == true then open = true
elseif global.over_ride_left_can_open then
if is_type(Role,'table') then
if Role.allowed(player,self.name) then open = true
else open = {'ExpGamingCore_Gui.unauthorized'} end
else open = true end
else open = err end
else
if is_type(Role,'table') then
if Role.allowed(player,self.name) then open = true
else open = {'ExpGamingCore_Gui.unauthorized'} end
else open = true end
end
if open == true and left.style.visible ~= true then
left.style.visible = true
left_flow['gui-left-hide'].style.visible = true
else
left.style.visible = false
local count = 0
for _,child in pairs(left_flow.children) do if child.style.visible then count = count+1 end if count > 1 then break end end
if count == 1 and left_flow['gui-left-hide'] then left_flow['gui-left-hide'].style.visible = false end
end
if open == false then player_return({'ExpGamingCore_Gui.cant-open-no-reason'},defines.textcolor.crit,player) player.play_sound{path='utility/cannot_build'}
elseif open ~= true then player_return({'ExpGamingCore_Gui.cant-open',open},defines.textcolor.crit,player) player.play_sound{path='utility/cannot_build'} end
return left.style.visible
end
left.on_player_joined_game = function(event)
-- draws the left guis when a player first joins, fake_event is just because i am lazy
local player = Game.get_player(event)
local frames = Gui.data.left or {}
local left_flow = mod_gui.get_frame_flow(player)
if not left_flow['gui-left-hide'] then left.hide(left_flow).style.maximal_width=15 end
local done = {}
for _,name in pairs(order_config) do
local left = Gui.data.left[name]
if left then
done[name] = true
left:first_open(player)
end
end
for name,left in pairs(frames) do
if not done[name] then left:first_open(player) end
end
end
function left:on_init()
if loaded_modules['ExpGamingCore.Role'] then Role = require('ExpGamingCore.Role') end
end
-- calling will attempt to add a new gui
return setmetatable(left,{__call=function(self,...) return self.add(...) end})

View File

@@ -1,124 +0,0 @@
--- Adds a location for popups which can be dismissed by a player and created from other scripts
-- @module ExpGamingCore.Gui.Popup
-- @alias popup
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This is a submodule of ExpGamingCore.Gui but for ldoc reasons it is under its own module
-- @function _comment
local Game = require('FactorioStdLib.Game')
local mod_gui = require("mod-gui")
local Gui = Gui -- this is to force gui to remain in the ENV
local popup = {}
popup._prototype = {}
function popup.load()
popup._prototype.close = Gui.inputs.add{
type='button',
name='popup-close',
caption='utility/set_bar_slot',
tooltip='Close This Popup'
}:on_event('click',function(event)
local frame = event.element.parent
local parent = frame.parent
if frame and frame.valid then frame.destroy() if #parent.children == 0 then parent.style.visible = false end end
end)
end
--- Used to add a popup gui style
-- @usage Gui.left.add{name='foo',caption='Foo',draw=function}
-- @usage return_value(data,player) -- opens popup for one player use popup.open to open for more than one player
-- @param obj this is what will be made, needs a name and a draw function(root_frame,data)
-- @return the object that is made, calling the returned value will open the popup for that player
function popup.add(obj)
if not is_type(obj,'table') then return end
if not is_type(obj.name,'string') then return end
verbose('Created Popup Gui: '..obj.name)
setmetatable(obj,{__index=popup._prototype,__call=function(self,data,player) local players = player and {player} or nil return popup.open(self.name,data,players) end})
local name = obj.name; obj.name = nil
Gui.data('popup',name,obj)
obj.name = name
return obj
end
-- this is used by the script to find the popup flow
function popup.flow(player)
local player = Game.get_player(player)
if not player then error('Invalid Player',2) end
local flow = mod_gui.get_frame_flow(player).popups
if not flow then flow = mod_gui.get_frame_flow(player).add{name='popups',type='flow',direction='vertical'} flow.style.visible=false end
return flow
end
--- Use to open a popup for these players
-- @usage Gui.popup.open('ban',nil,{player=1,reason='foo'})
-- @tparam string style this is the name you gave to the popup when added
-- @param data this is the data that is sent to the draw function
-- @tparam[opt=game.connected_players] table players the players to open the popup for
function popup.open(style,data,players)
local _popup = Gui.data.popup[style]
local players = players or game.connected_players
local data = data or {}
if not _popup then return end
if not Server or not Server._thread then
for _,player in pairs(players) do
if _popup.left then _popup.left:close(player) end
local flow = popup.flow(player)
flow.style.visible=true
local _frame = flow.add{
type='frame',
direction='horizontal',
style=mod_gui.frame_style
}
local frame = _frame.add{
type='frame',
name='inner_frame',
direction='vertical',
style='image_frame'
}
_popup.close(_frame)
if is_type(_popup.draw,'function') then
local success, err = pcall(_popup.draw,frame,data)
if not success then error(err) end
else error('No Draw On Popup '.._popup.name) end
end
else
Server.new_thread{
data={players=players,popup=_popup,data=data}
}:on_event('tick',function(self)
if #self.data.players == 0 then self:close() return end
local player = table.remove(self.data.players,1)
if self.data.popup.left then self.data.popup.left:close(player) end
local flow = popup.flow(player)
flow.style.visible=true
local _frame = flow.add{
type='frame',
direction='horizontal',
style=mod_gui.frame_style
}
local frame = _frame.add{
type='frame',
name='inner_frame',
direction='vertical',
style='image_frame'
}
self.data.popup.close(_frame)
if is_type(self.data.popup.draw,'function') then
local success, err = pcall(self.data.popup.draw,frame,self.data.data)
if not success then error(err) end
else error('No Draw On Popup '..self.data.popup.name) end
end):open()
end
end
function popup._prototype:add_left(obj)
obj.name = obj.name or self.name
self.left = Gui.left(obj)
end
popup.on_player_joined_game = popup.flow
-- calling will attempt to add a new popup style
return setmetatable(popup,{__call=function(self,...) return self.add(...) end})

View File

@@ -1,91 +0,0 @@
--- Adds a toolbar to the top left of the screen
-- @module ExpGamingCore.Gui.Toolbar
-- @alias toolbar
-- @author Cooldude2606
-- @license https://github.com/explosivegaming/scenario/blob/master/LICENSE
--- This is a submodule of ExpGamingCore.Gui but for ldoc reasons it is under its own module
-- @function _comment
local Game = require('FactorioStdLib.Game')
local Role -- this is optional and is hanndled by it being present, it is loaded on init
local mod_gui = require("mod-gui")
local Gui = Gui -- this is to force gui to remain in the ENV
local order_config = order_config
local toolbar = {}
toolbar.hide = Gui.inputs{
name='gui-toolbar-hide',
type='button',
caption='<'
}:on_event('click',function(event)
if event.element.caption == '<' then
event.element.caption = '>'
for _,child in pairs(event.element.parent.children) do
if child.name ~= event.element.name then child.style.visible = false end
end
else
event.element.caption = '<'
for _,child in pairs(event.element.parent.children) do
if child.name ~= event.element.name then child.style.visible = true end
end
end
end)
--- Add a button to the toolbar, ranks need to be allowed to use these buttons if ranks is preset
-- @usage toolbar.add('foo','Foo','Test',function() game.print('test') end)
-- @tparam string name the name of the button
-- @tparam string caption can be a sprite path or text to show
-- @tparam string tooltip the help to show for the button
-- @tparam function callback the function which is called on_click
-- @treturn table the button object that was made, calling the returned value will draw the toolbar button added
function toolbar.add(name,caption,tooltip,callback)
verbose('Created Toolbar Button: '..name)
local button = Gui.inputs.add{type='button',name=name,caption=caption,tooltip=tooltip}
button:on_event(Gui.inputs.events.click,callback)
Gui.data('toolbar',name,button)
return button
end
--- Draws the toolbar for a certain player
-- @usage toolbar.draw(1)
-- @param player the player to draw the tool bar of
function toolbar.draw(player)
local player = Game.get_player(player)
if not player then return end
local toolbar_frame = mod_gui.get_button_flow(player)
toolbar_frame.clear()
if not Gui.data.toolbar then return end
toolbar.hide(toolbar_frame).style.maximal_width = 15
local done = {}
for _,name in pairs(order_config) do
local button = Gui.data.toolbar[name]
if button then
done[name] = true
if is_type(Role,'table') then
if Role.allowed(player,name) then
button(toolbar_frame)
end
else button(toolbar_frame) end
end
end
for name,button in pairs(Gui.data.toolbar) do
if not done[name] then
if is_type(Role,'table') then
if Role.allowed(player,name) then
button(toolbar_frame)
end
else button(toolbar_frame) end
end
end
end
function toolbar:on_init()
if loaded_modules['ExpGamingCore.Role'] then Role = require('ExpGamingCore.Role') end
end
toolbar.on_role_change = toolbar.draw
toolbar.on_player_joined_game = toolbar.draw
-- calling with only a player will draw the toolbar for that player, more params will attempt to add a button
return setmetatable(toolbar,{__call=function(self,player,extra,...) if extra then return self.add(player,extra,...) else self.draw(player) end end})