mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-29 12:16:37 +09:00
Added dropboxs
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
131
expcore/gui/concepts/dropdown.lua
Normal file
131
expcore/gui/concepts/dropdown.lua
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user