Added dropboxs

This commit is contained in:
Cooldude2606
2019-08-30 17:13:22 +01:00
parent 38f0413b31
commit a80d0bf99d
98 changed files with 1651 additions and 124 deletions

View File

@@ -619,4 +619,67 @@ function Common.get_file_path(offset)
return debug.getinfo(offset+2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
end
--[[-- Much faster method for inserting items into an array
@tparam table tbl the table that will have the values added to it
@tparam[opt] number start_index the index at which values will be added, nil means end of the array
@tparam table values the new values that will be added to the table
@treturn table the table that was passed as the first argument
@usage-- Adding 1000 values into the middle of the array
local tbl = {}
local values = {}
for i = 1,1000 do tbl[i] = i values[i] = i end
Common.array_insert(tbl,500,values) -- around 0.4ms
]]
function Common.array_insert(tbl,start_index,values)
if not values then
values = start_index
start_index = nil
end
if start_index then
local starting_length = #tbl
local adding_length = #values
local move_to = start_index+adding_length+1
for offset = 0, starting_length-start_index do
tbl[move_to+offset] = tbl[starting_length+offset]
end
start_index = start_index-1
else
start_index = #tbl
end
for offset, item in ipairs(values) do
tbl[start_index+offset] = item
end
return tbl
end
--[[-- Much faster method for inserting keys into a table
@tparam table tbl the table that will have keys added to it
@tparam[opt] number start_index the index at which values will be added, nil means end of the array, numbered indexs only
@tparam table tbl2 the table that may contain both string and numbered keys
@treturn table the table passed as the first argument
@usage-- Merging two tables
local tbl = {}
local tbl2 = {}
for i = 1,100 do tbl[i] = i tbl['_'..i] = i tbl2[i] = i tbl2['__'..i] = i end
Common.table_insert(tbl,50,tbl2)
]]
function Common.table_insert(tbl,start_index,tbl2)
if not tbl2 then
tbl2 = start_index
start_index = nil
end
Common.array_insert(tbl,start_index,tbl2)
for key, value in pairs(tbl2) do
if not tonumber(key) then
tbl[key] = value
end
end
return tbl
end
return Common

View File

@@ -70,5 +70,6 @@ local Gui = require 'expcore.gui.core'
Gui.require_concept('frame')
Gui.require_concept('button')
Gui.require_concept('checkbox')
Gui.require_concept('dropdown')
return Gui

View File

@@ -0,0 +1,131 @@
--[[-- Core Module - Gui
@module Gui
@alias Gui
]]
local Gui = require 'expcore.gui.core'
local array_insert = ext_require('expcore.common','array_insert')
--[[-- The basic dropdown element
@element dropdown
@param on_selection_change fired when the selected value is changed
@tparam ?string|Conepts.LocalisedString default_selection the option which is selected by default
@tparam boolean use_list_box when true a list box will be used rather than a dropdown menu
@tparam ?nil|table static_items when called with a table the values will be added as items for the dropdown, if called with nil then all items are cleared
@tparam function dynamic_items the given function will be called to return a list of items and optional start index to add items to the dropdown when it is first drawn
]]
Gui.new_concept('dropdown')
:new_event('on_selection_change',defines.events.on_gui_selection_state_changed)
:new_property('default_selection')
:new_property('use_list_box',false)
:new_property('static_items',nil,function(properties,value,start_index)
if not value then
properties.items = {}
end
if type(value) ~= 'table' then
value = {value}
end
local items = properties.items
if not items then
properties.items = value
return
end
array_insert(items,start_index,value)
end)
:new_property('dynamic_items',nil,function(properties,value)
if type(value) ~= 'function' then
error('Dynamic items must be a function')
end
local items = properties.dynamic_items
if not items then
properties.dynamic_items = {value}
return
end
items[#items+1] = value
end)
:define_draw(function(properties,parent,element,new_items)
local items = new_items or {}
array_insert(items,1,properties.items or {})
element = parent.add{
name = properties.name,
type = properties.use_list_box and 'list-box' or 'drop-down',
items = items
}
if properties.dynamic_items then
for _,callback in pairs(properties.dynamic_items) do
local dynamic_items, start_index = callback(element)
Gui.add_dropdown_items(element,start_index,dynamic_items)
end
end
if properties.default_selection then
local default = properties.default_selection
if type(default) == 'function' then
default = default(element)
end
Gui.set_dropdown_value(element,default)
end
return element
end)
--- Dropdowns.
-- functions used with dropdowns
-- @section dropdowns
--[[-- Selects the index of a dropdown with this value
@tparam LuaGuiElement element the dropdown that you want to set the selection for
@tparam ?string|Conepts.LocalisedString value the value that you want selected
@treturn boolean if an item with this value was found
@usage-- Selecting the item with the value 'foo'
Gui.set_dropdown_value(element,'foo')
]]
function Gui.set_dropdown_value(element,value)
for index, item in pairs(element.items) do
if item == value then
element.selected_index = index
return true
end
end
return false
end
--[[-- Gets the selected item value of a dropdown
@tparam LuaGuiElement element the dropdown that you want the selected value of
@treturn ?string|Conepts.LocalisedString the value that is currently selected
@usage-- Getting the selected value
local selected_value = Gui.get_dropdown_value(element)
]]
function Gui.get_dropdown_value(element)
return element.items[element.selected_index]
end
--[[-- Adds the given items into the list of items for this dropdown
@tparam LuaGuiElement element the dropdown that you want to add the items to
@tparam[opt] number start_index the index at which the items will be added, if not given appened to the end
@tparam table new_items the list of new items that you want to add
@treturn table the list of items that the element now has
@usage-- Add the items 'foo' and 'bar' to the end
Gui.add_dropdown_items(element,{'foo','bar'})
@usage-- Add the items 'foo' and 'bar' to the start
Gui.add_dropdown_items(element,1,{'foo','bar'})
]]
function Gui.add_dropdown_items(element,start_index,new_items)
if not new_items then
new_items = start_index
start_index = nil
end
local items = element.items
element.items = array_insert(items,start_index,new_items)
return items
end

View File

@@ -3,10 +3,6 @@
@alias Gui
]]
--- Core.
-- Functions that act as a landing point for the other funtions
-- @section core
local Game = require 'utils.game' -- @dep utils.game
local Prototype = require 'expcore.gui.prototype'
@@ -14,6 +10,10 @@ local Gui = {
concepts = {}
}
--- Concept Control.
-- Functions that act as a landing point for the other funtions
-- @section concept-control
--[[-- Loads a concept from the concepts file, used internally
@tparam string concept the name of the concept to require
@usage-- Load a base concept
@@ -64,7 +64,7 @@ function Gui.new_concept(name)
return Prototype:clone(name)
end
--[[-- Making anew concept based on the properties and drawing of another
--[[-- Make a new concept based on the properties and drawing of another
@tparam string name the name of the concept that you want as the base
@tparam string new_name the name that you want the new concept to have
@usage-- Making a new concept from another, see module usage
@@ -80,6 +80,116 @@ function Gui.clone_concept(name,new_name)
return concept:clone(new_name)
end
--[[-- Used to draw a concept to a parent element
@tparam string name the name of the concept that you want to draw
@tparam LuaGuiElement parent the element that will act as a parent for the new element
@treturn LuaGuiElement the element that was created
@usage-- Drawing a new element
Gui.draw_concept('Button',element)
]]
function Gui.draw_concept(name,parent,...)
local concept = Gui.concepts[name] or error('Gui concept "'..name..'" is not defind',2)
return concept:draw(parent,...)
end
--- Element Control.
-- Functions that aim to making working with gui elements easier
-- @section element-control
--[[-- Gets the player who owns this element
@tparam LuaGuiElement element the element that you want to get the player of
@treturn LuaPlayer the player who owns this element
@usage-- Getting the player of an element
local player = Gui.get_player_from_element(element)
]]
function Gui.get_player_from_element(element)
return Game.get_player_by_index(element.player_index)
end
--[[-- Simple check for if an element is valid
@tparam LuaGuiElement element the element that you want to check is valid
@treturn boolean true if the element is valid
@usage-- Return if not valid
if not Gui.valid(element) then return end
]]
function Gui.valid(element)
return element and element.valid or false
end
--[[-- Destroies and element if it is valid
@tparam LuaGuiElement element the element that you want to destroy
@treturn boolean true if the element was valid and was destoried
@usage-- Destoring an element
Gui.destroy(element)
]]
function Gui.destroy(element)
if element and element.valid then
element.destroy()
return true
end
return false
end
--[[-- Toggles the enabled state of an element
@tparam LuaGuiElement element the element that you want to toggle the enabled state of
@treturn boolean the new enabled state of the element
@usage-- Toggle the enabled state of an element
Gui.toggle_enabled(element)
]]
function Gui.toggle_enabled(element)
if not element or not element.valid then return end
if not element.enabled then
element.enabled = true
return true
else
element.enabled = false
return false
end
end
--[[-- Toggles the visible state of an element
@tparam LuaGuiElement element the element that you want to toggle the visible state of
@treturn boolean the new visible state of the element
@usage-- Toggle the visible state of an element
Gui.toggle_visible(element)
]]
function Gui.toggle_visible(element)
if not element or not element.valid then return end
if not element.visible then
element.visible = true
return true
else
element.visible = false
return false
end
end
--[[-- Sets the padding for a gui element
@tparam LuaGuiElement element the element to set the padding for
@tparam[opt=0] ?number|boolean up the amount of padding on the top, true leaves unchanged
@tparam[opt=0] ?number|boolean down the amount of padding on the bottom, true leaves unchanged
@tparam[opt=0] ?number|boolean left the amount of padding on the left, true leaves unchanged
@tparam[opt=0] ?number|boolean right the amount of padding on the right, true leaves unchanged
@usage-- Remove all padding of an element
Gui.set_padding(element)
@usage-- Remove side padding but keep vertical padding
Gui.set_padding(element,true,true)
@usage-- Remove all padding but set right to 2
Gui.set_padding(element,false,false,false,2)
]]
function Gui.set_padding(element,up,down,left,right)
local style = element.style
style.top_padding = up == true and style.top_padding or up or 0
style.bottom_padding = down == true and style.top_padding or down or 0
style.left_padding = left == true and style.top_padding or left or 0
style.right_padding = right == true and style.top_padding or right or 0
end
--- Store Categories.
-- Functions that are common types of categories
-- @section store-categories
--[[-- A categorize function to be used with add_store, each player has their own category
@tparam LuaGuiElement element the element that will be converted to a string
@treturn string the player's name who owns this element

View File

@@ -634,19 +634,25 @@ end) -- player index 1
return self
end
--[[-- Used to add a both instance and data stores which are linked together, new instances are synced to current value, changing one instance changes them all
--- Concept Combined Instances.
-- Functions that are used to make store concept instances and data
-- @section concept-instances
--[[-- Used to add a both instance and data store which are linked together, new instances are synced to the current value, changing the stored value will change all instances
@tparam[opt] function category_callback when given will act as a way to turn an element into a string to act as a key; keys returned can over lap
@tparam function sync_callback the function which is called to update an instance to match the store
@tparam function sync_callback the function which is called to update an instance to match the store, this is called on all instances when concept.set_data or update_data is used
@treturn GuiConcept to allow chaining of functions
@usage-- Adding a way to sync enabled state bettween all instances, more useful for things that arnt buttons
@usage-- Adding a check box which is a "global setting" synced between all players
local custom_button =
Gui.get_concept('CustomButton')
:define_combined_store(
function(element)
return element.player_index -- The data is stored based on player id
end,
function(element,value)
element.enabled = value -- We will use custom_button.set_data(element,value) to trigger this
Gui.get_concept('checkbox'):clone('my_checkbox')
:set_caption('My Checkbox')
:set_tooltip('Clicking this check box will change it for everyone')
:on_state_change(function(event)
local element = event.element
event.concept.set_data(element,element.state) -- Update the stored data to trigger an update of all other instances
end)
:define_combined_store(function(element,state) -- We could add a category function here if we wanted to
element.state = state or false -- When you sync an instance this is what is called
end)
]]
function Prototype:define_combined_store(category_callback,sync_callback)

View File

@@ -205,4 +205,77 @@ tests.Checkboxs = {
['Game Stored Checkbox'] = game_checkbox,
['Force Stored Checkbox'] = force_checkbox,
['Player Stored Checkbox'] = player_checkbox
}
--[[
Dropdowns
> Static Dropdown -- Simple dropdown with all options being static
> Dynamic Dropdown -- Dropdown which has items based on when it is drawn
> Static Player Stored Dropdown -- Dropdown where the values is synced for each player
> Dynamic Player Stored Dropdown -- Same as above but now with dynamic options
]]
local static_dropdown =
Gui.clone_concept('dropdown',TEST 'static_dropdown')
:set_static_items{'Option 1','Option 2','Option 3'}
:on_selection_change(function(event)
local value = Gui.get_dropdown_value(event.element)
event.player.print('Static dropdown is now: '..value)
end)
local dynamic_dropdown =
Gui.clone_concept('dropdown',TEST 'dynamic_dropdown')
:set_dynamic_items(function(element)
local items = {}
for concept_name,_ in pairs(Gui.concepts) do
if concept_name:len() < 16 then
items[#items+1] = concept_name
end
end
return items
end)
:on_selection_change(function(event)
local value = Gui.get_dropdown_value(event.element)
event.player.print('Dynamic dropdown is now: '..value)
end)
local static_player_dropdown =
Gui.clone_concept('dropdown',TEST 'static_player_dropdown')
:set_static_items{'Option 1','Option 2','Option 3'}
:on_selection_change(function(event)
local element = event.element
local value = Gui.get_dropdown_value(element)
event.concept.set_data(element,value)
event.player.print('Static player stored dropdown is now: '..value)
end)
:define_combined_store(Gui.categorize_by_player,function(element,value)
Gui.set_dropdown_value(element,value)
end)
local dynamic_player_dropdown =
Gui.clone_concept('dropdown',TEST 'dynamic_player_dropdown')
:set_dynamic_items(function(element)
local items = {}
for concept_name,_ in pairs(Gui.concepts) do
if concept_name:len() < 16 then
items[#items+1] = concept_name
end
end
return items
end)
:on_selection_change(function(event)
local element = event.element
local value = Gui.get_dropdown_value(element)
event.concept.set_data(element,value)
event.player.print('Dynamic player dropdown is now: '..value)
end)
:define_combined_store(Gui.categorize_by_player,function(element,value)
Gui.set_dropdown_value(element,value)
end)
tests.Dropdowns = {
['Static Dropdown'] = static_dropdown,
['Dynamic Dropdown'] = dynamic_dropdown,
['Static Player Stored Dropdown'] = static_player_dropdown,
['Dynamic Player Stored Dropdown'] = dynamic_player_dropdown
}