2551ddbf1d
This commit contains changes best credited to flyc0r <flyc0r@localhost.localdomain>, although the changes were separated out from waspsaliva's original initial commit rev. 0e9e1f352, which added the files from DFC work tree, and squashed in numerous additions by flyc0r and collaborators. That commit log: commit 0e9e1f3528c3d2fa1f1e9a79d4a00576be8552f5 Author: flyc0r <flyc0r@localhost.localdomain> Date: Sun Oct 4 03:37:08 2020 +0200 init This rebase had the effect of griefing the git history xD, so for example `git blame` of DFC and even upstream Minetest sources appear to be originally authored by `flyc0r` in that commit. To fix this, I will recommit only the changes onto the appropriate commit in DFC, and recreate the following git history (incl. merges). After this, the git history will be at least visually the same as the original Waspsaliva, even if commit sha1sums have changed. AFAICT, the closest commit from DFC was af085acbd. That commit was found simply by running `git diff wsc-master <some_DFC_rev>`, and locating the commit with the smallest number of differences. This commit was then created as follows: # Check out the DFC base commit git checkout af085acbd # Check out the *files* from WSC's initial commit git checkout 0e9e1f352 -- . # Make sure everything is added and commit the changes git add -A git commit
2916 lines
130 KiB
Lua
2916 lines
130 KiB
Lua
local data = { -- window size
|
|
width = 15,
|
|
height = 10,
|
|
|
|
}
|
|
local form_esc = minetest.formspec_escape -- shorten the function
|
|
|
|
local modstorage = core.get_mod_storage()
|
|
|
|
|
|
local function create_tabs(selected)
|
|
return "tabheader[0,0;_option_tabs_;" ..
|
|
" LUA EDITOR ,FORMSPEC EDITOR, LUA CONSOLE , FILES , STARTUP , FUNCTIONS , HELP ;"..selected..";;]"
|
|
end
|
|
|
|
local function copy_table(table)
|
|
local new = {}
|
|
for i, v in pairs(table) do
|
|
if type(v) == "table" then
|
|
v = copy_table(v)
|
|
end
|
|
new[i] = v
|
|
end
|
|
return new
|
|
end
|
|
|
|
|
|
----------
|
|
-- LOAD AND DEFINE STUFF - global stuff is accissible from the UI
|
|
----------
|
|
|
|
local split = function (str, splitter) -- a function to split a string into a list. "\" before the splitter makes it ignore it (usefull for minetests formspecs)
|
|
local result = {""}
|
|
for i=1, str:len() do
|
|
char = string.sub(str, i, i)
|
|
if char == splitter and string.sub(str, i-1, i-1) ~= "\\" then
|
|
table.insert(result, "")
|
|
else
|
|
result[#result] = result[#result]..char
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
|
|
local output = {} -- the output for errors, prints, etc
|
|
|
|
local saved_file = modstorage:get_string("_lua_saved") -- remember what file is currently being edited
|
|
if saved_file == "" then
|
|
saved_file = false -- if the file had no save name (it was still saved)
|
|
end
|
|
|
|
|
|
local lua_startup = split(modstorage:get_string("_lua_startup"), ",") -- the list of scripts to run at startup
|
|
|
|
local lua_files = split(modstorage:get_string("_lua_files_list"), ",") -- the list of names of all saved files
|
|
|
|
local ui_files = split(modstorage:get_string("_UI_files_list"), ",") -- UI files list
|
|
|
|
local reg_funcs = {formspec_input={}, chatcommands={}, on_connect={}, joinplayer={}, sending_chat_message={}, recieving_chat_message={}}
|
|
|
|
|
|
local selected_files = {0, 0}
|
|
|
|
|
|
--minetest.register_on_connect(function() -- some functions don't work after startup. this tries to replace them
|
|
|
|
minetest.get_mod_storage = function()
|
|
return modstorage
|
|
end
|
|
|
|
core.get_mod_storage = function()
|
|
return modstorage
|
|
end
|
|
|
|
-- show formspec
|
|
|
|
--end) -- add whatever functions don't work after startup to here (if possible)
|
|
|
|
|
|
----------
|
|
-- FUNCTIONS FOR UI
|
|
----------
|
|
|
|
function print(...) -- replace print to output into the UI. (doesn't refresh untill the script has ended)
|
|
params = {...}
|
|
if #params == 1 then
|
|
local str = params[1]
|
|
if type(str) ~= "string" then
|
|
str = dump(str)
|
|
end
|
|
table.insert(output, "")
|
|
for i=1, str:len() do
|
|
char = string.sub(str, i, i)
|
|
if char == "\n" then
|
|
table.insert(output, "") -- split multiple lines over multiple lines. without this, text with line breaks would not display properly
|
|
else
|
|
output[#output] = output[#output]..char
|
|
end
|
|
end
|
|
else
|
|
for i, v in pairs(params) do
|
|
print(v)
|
|
end
|
|
end
|
|
end
|
|
|
|
function safe(func) -- run a function without crashing the game. All errors are displayed in the UI.
|
|
f = function(...) -- This can be used for functions being registered with minetest, like "minetest.register_chat_command()"
|
|
status, out = pcall(func, ...)
|
|
if status then
|
|
return out
|
|
else
|
|
table.insert(output, "#ff0000Error: "..out)
|
|
minetest.debug("Error (func): "..out)
|
|
return nil
|
|
end
|
|
end
|
|
return f
|
|
end
|
|
|
|
|
|
----------
|
|
-- CODE EXECUTION
|
|
----------
|
|
|
|
local function run(code, name) -- run a script
|
|
if name == nil then
|
|
name = saved_file
|
|
end
|
|
status, err = pcall(loadstring(code)) -- run
|
|
if status then
|
|
if saved_file == false then
|
|
table.insert(output, "#00ff00finished") -- display that the script ran without errors
|
|
else
|
|
table.insert(output, "#00ff00"..name..": finished") -- display which script, if it was saved
|
|
end
|
|
else
|
|
if err == "attempt to call a nil value" then
|
|
err = "Syntax Error"
|
|
end
|
|
if saved_file == false then
|
|
table.insert(output, "#ff0000Error: "..err) -- display errors
|
|
minetest.log("Error (unsaved): "..err)
|
|
else
|
|
table.insert(output, "#ff0000"..name..": Error: "..err)
|
|
minetest.log("Error ("..name.."): "..err)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_startup() -- ran on startup. Runs all scripts registered for startup
|
|
for i, v in pairs(lua_startup) do
|
|
if v ~= "" then
|
|
run(modstorage:get_string("_lua_file_"..v, v), v) -- errors still get displayed in the UI
|
|
end
|
|
end
|
|
end
|
|
|
|
on_startup()
|
|
|
|
|
|
----------
|
|
-- FILE READING AND SAVING
|
|
----------
|
|
|
|
local function load_lua() -- returns the contents of the file currently being edited
|
|
if saved_file == false then
|
|
return modstorage:get_string("_lua_temp") -- unsaved files are remembered (get saved on UI reloads - when clicking on buttons)
|
|
else
|
|
return modstorage:get_string("_lua_file_"..saved_file)
|
|
end
|
|
end
|
|
|
|
local function save_lua(code) -- save a file
|
|
if saved_file == false then
|
|
modstorage:set_string("_lua_temp", code)
|
|
else
|
|
modstorage:set_string("_lua_file_"..saved_file, code)
|
|
end
|
|
end
|
|
|
|
|
|
----------
|
|
-- FORM DEFINITIONS
|
|
----------
|
|
|
|
|
|
local function startup_form() -- the formspec for adding or removing files for startup
|
|
local startup_str = ""
|
|
for i, v in pairs(lua_startup) do
|
|
if i ~= 1 then startup_str = startup_str.."," end
|
|
startup_str = startup_str .. form_esc(v)
|
|
end
|
|
local files_str = ""
|
|
for i, v in pairs(lua_files) do
|
|
if i ~= 1 then files_str = files_str.."," end
|
|
files_str = files_str .. form_esc(v)
|
|
end
|
|
|
|
local form = ""..
|
|
"size["..data.width..","..data.height.."]" ..
|
|
"label[0,0.1;Startup Items:]"..
|
|
"label["..data.width/2 ..",0.1;File List:]"..
|
|
"textlist[0,0.5;"..data.width/2-0.1 ..","..data.height-1 ..";starts;"..startup_str.."]"..
|
|
"textlist["..data.width/2 ..",0.5;"..data.width/2-0.1 ..","..data.height-1 ..";chooser;"..files_str.."]"..
|
|
"label[0," .. data.height-0.3 .. ";double click items to add or remove from startup]"..
|
|
|
|
"" .. create_tabs(5)
|
|
return form
|
|
end
|
|
|
|
|
|
local function lua_editor() -- the main formspec for editing
|
|
|
|
local output_str = "" -- convert the output to a string
|
|
for i, v in pairs(output) do
|
|
if output_str:len() > 0 then output_str = output_str .. "," end
|
|
output_str = output_str .. form_esc(v)
|
|
end
|
|
|
|
local code = form_esc(load_lua())
|
|
|
|
-- create the form
|
|
local form = ""..
|
|
"size["..data.width..","..data.height.."]" ..
|
|
"textarea[0.3,0.1;"..data.width ..","..data.height-3 ..";editor;Lua editor;"..code.."]"..
|
|
"button[0," .. data.height-3.5 .. ";1,0;run;RUN]"..
|
|
"button[1," .. data.height-3.5 .. ";1,0;clear;CLEAR]"..
|
|
"button[2," .. data.height-3.5 .. ";1,0;save;SAVE]"..
|
|
"textlist[0,"..data.height-3 ..";"..data.width-0.2 ..","..data.height-7 ..";output;"..output_str..";".. #output .."]"..
|
|
|
|
"" .. create_tabs(1)
|
|
return form
|
|
end
|
|
|
|
|
|
local function file_viewer() -- created with the formspec editor!
|
|
local lua_files_item_str = ""
|
|
for i, item in pairs(lua_files) do
|
|
if i ~= 1 then lua_files_item_str = lua_files_item_str.."," end
|
|
lua_files_item_str = lua_files_item_str .. form_esc(item)
|
|
end
|
|
|
|
local ui_select_item_str = ""
|
|
for i, item in pairs(ui_files) do
|
|
if i ~= 1 then ui_select_item_str = ui_select_item_str.."," end
|
|
ui_select_item_str = ui_select_item_str .. form_esc(item)
|
|
end
|
|
|
|
local form = "" ..
|
|
"size["..data.width..","..data.height.."]" ..
|
|
"textlist[-0.2,0.2;"..data.width/2.02- -0.2 ..","..data.height- 1 ..";lua_select;"..lua_files_item_str.."]" ..
|
|
"label[-0.2,-0.2;LUA FILES]" ..
|
|
"field[0.1,"..data.height- 0.2 ..";3,1;new_lua;NEW;]" ..
|
|
"field_close_on_enter[new_lua;false]" ..
|
|
"button[2.6,"..data.height- 0.5 ..";0.5,1;add_lua;+]" ..
|
|
"textlist["..data.width/1.97 ..",0.2;"..data.width- 0-(data.width/1.97) ..","..data.height- 1 ..";ui_select;"..ui_select_item_str.."]" ..
|
|
"label["..data.width/1.96 ..",-0.2;FORMSPEC FILES]" ..
|
|
"field["..data.width- 2.8 ..","..data.height- 0.2 ..";3,1;new_ui;NEW;]" ..
|
|
"field_close_on_enter[new_ui;false]" ..
|
|
"button["..data.width- 0.3 ..","..data.height- 0.5 ..";0.5,1;add_ui;+]" ..
|
|
"label["..data.width/2.4 ..","..data.height- 0.8 ..";Double click a file to open it]" ..
|
|
"button[3.1,"..data.height- 0.5 ..";1.1,1;del_lua;DELETE]" ..
|
|
"button["..data.width- 4.2 ..","..data.height- 0.5 ..";1.1,1;del_ui;DELETE]" ..
|
|
"" .. create_tabs(4)
|
|
|
|
return form
|
|
end
|
|
|
|
|
|
----------
|
|
-- FUNCTIONALITY
|
|
----------
|
|
|
|
minetest.register_on_formspec_input(function(formname, fields)
|
|
|
|
-- EDITING PAGE
|
|
----------
|
|
if formname == "lua:editor" then
|
|
if fields.run then --[RUN] button
|
|
save_lua(fields.editor)
|
|
run(fields.editor)
|
|
|
|
minetest.show_formspec("lua:editor", lua_editor())
|
|
|
|
elseif fields.save then --[SAVE] button
|
|
if saved_file == false then
|
|
modstorage:set_string("_lua_temp", fields.editor)
|
|
else
|
|
modstorage:set_string("_lua_file_"..saved_file, fields.editor)
|
|
end
|
|
|
|
elseif fields.clear then --[CLEAR] button
|
|
output = {}
|
|
save_lua(fields.editor)
|
|
minetest.show_formspec("lua:editor", lua_editor())
|
|
end
|
|
|
|
-- STARTUP EDITOR
|
|
----------
|
|
elseif formname == "lua:startup" then -- double click a file to remove it from the list
|
|
if fields.starts then
|
|
local select = {["type"] = string.sub(fields.starts, 1, 3), ["row"] = tonumber(string.sub(fields.starts, 5, 5))}
|
|
if select.type == "DCL" then
|
|
table.remove(lua_startup, select.row)
|
|
local startup_str = ""
|
|
for i, v in pairs(lua_startup) do
|
|
if v ~= "" then
|
|
startup_str = startup_str..v..","
|
|
end
|
|
end
|
|
modstorage:set_string("_lua_startup", startup_str)
|
|
minetest.show_formspec("lua:startup", startup_form())
|
|
end
|
|
|
|
elseif fields.chooser then -- double click a file to add it to the list
|
|
local select = {["type"] = string.sub(fields.chooser, 1, 3), ["row"] = tonumber(string.sub(fields.chooser, 5, 5))}
|
|
if select.type == "DCL" then
|
|
table.insert(lua_startup, lua_files[select.row])
|
|
local startup_str = ""
|
|
for i, v in pairs(lua_startup) do
|
|
if v ~= "" then
|
|
startup_str = startup_str..v..","
|
|
end
|
|
end
|
|
modstorage:set_string("_lua_startup", startup_str)
|
|
minetest.show_formspec("lua:startup", startup_form())
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
|
|
|
|
|
|
---------- ----------
|
|
-- PASTE FORMSPEC EDITOR HERE --
|
|
---------- ----------
|
|
|
|
|
|
|
|
---------- ----------
|
|
-- FORMSPEC EDITOR START --
|
|
---------- ----------
|
|
|
|
local widg_list = {"Button", "DropDown", "CheckBox", "Slider", "Tabs", "TextList", "Table", "Field", "TextArea", "InvList", "Label", "Image", "Box", "Tooltip", "Container"} -- all widget options
|
|
|
|
local widgets = nil -- stores all widget data for the current file
|
|
|
|
local selected_widget = 1 -- the widget/tab currently being edited
|
|
|
|
local new_widg_tab = false -- so the new widget tab can be displayed without moving the selection
|
|
|
|
local main_ui_form -- make this function global to the rest of the program
|
|
|
|
|
|
local current_ui_file = modstorage:get_string("_GUI_editor_selected_file") -- file name of last edited file
|
|
if current_ui_file == "" then -- for first ever load
|
|
current_ui_file = "new"
|
|
modstorage:set_string("_GUI_editor_selected_file", current_ui_file)
|
|
modstorage:set_string("_GUI_editor_file_"..current_ui_file, dump({{type="Display", name="", width=5, height=5, width_param=false, height_param=false, left=0.5, top=0.5,
|
|
position=false, background=false, colour="#000000aa", fullscreen=false, colour_tab=false,
|
|
col={col=false, bg_normal="#f0fa", bg_hover="#f0fa", set_border=false, border="#f0fa", set_tool=false, tool_bg="#f0fa", tool_font="#f0fa"}}}))
|
|
end
|
|
|
|
local function reload_ui() -- update the display, and save the file
|
|
modstorage:set_string("_GUI_editor_file_"..current_ui_file, dump(widgets))
|
|
minetest.show_formspec("ui_editor:main", main_ui_form())
|
|
end
|
|
|
|
local function load_UI(name) -- open/create a ui file
|
|
current_ui_file = name
|
|
modstorage:set_string("_GUI_editor_selected_file", current_ui_file)
|
|
_, widgets = pcall(loadstring("return "..modstorage:get_string("_GUI_editor_file_"..current_ui_file)))
|
|
if widgets == nil then
|
|
widgets = {{type="Display", name="", width=5, height=5, width_param=false, height_param=false, left=0.5, top=0.5,
|
|
position=false, background=false, colour="#000000aa", fullscreen=false, colour_tab=false,
|
|
col={col=false, bg_normal="#f0fa", bg_hover="#f0fa", set_border=false, border="#f0fa", set_tool=false, tool_bg="#f0fa", tool_font="#f0fa"}}}
|
|
end
|
|
end
|
|
load_UI(current_ui_file)
|
|
|
|
--widgets = {{type="Display", name="", width=5, height=5, width_param=false, height_param=false, left=0.5, top=0.5, position=false, background=false, colour="#000000aa", fullscreen=false, colour_tab=false, col={col=false, bg_normal="#f0fa", bg_hover="#f0fa", set_border=false, border="#f0fa", set_tool=false, tool_bg="#f0fa", tool_font="#f0fa"}} }
|
|
|
|
----------
|
|
-- UI DISPLAY
|
|
----------
|
|
|
|
-- generates the preview of the UI being edited
|
|
local function generate_ui()
|
|
local width = data.width-5 -- the size that is needed for the final formspec size, so large formspecs can be previewed
|
|
local height = data.height
|
|
|
|
-- data for calculating positions
|
|
local left = {0.1}
|
|
local top = {0.1}
|
|
local fwidth = {1}
|
|
local fheight = {1}
|
|
|
|
local form = ""
|
|
local boxes = "" -- because I can't add to form in get_rect() function
|
|
|
|
local depth = 1 -- container depth
|
|
|
|
-- calculates the positions of widgets, and creates the position syntax from a widget def
|
|
local function get_rect(widget, real, full)
|
|
|
|
local wleft = 0 -- widget top (etc)
|
|
if widget.left_type == "R-" then -- right is value from right side
|
|
wleft = left[depth]+fwidth[depth]-widget.left
|
|
elseif widget.left_type == "W/" then -- right is width/value from left side
|
|
wleft = left[depth]+fwidth[depth]/widget.left
|
|
else -- right is value from left side
|
|
wleft = left[depth]+widget.left
|
|
end
|
|
if full then -- container only takes whole numbers as positions.
|
|
wleft = math.floor(wleft-left[depth])+left[depth]
|
|
end
|
|
|
|
local wtop = 0
|
|
if widget.top_type == "B-" then -- value from bottom
|
|
wtop = top[depth]+fheight[depth]-widget.top
|
|
elseif widget.top_type == "H/" then -- height/value from top
|
|
wtop = top[depth]+(fheight[deformpth]/widget.top)
|
|
else -- value from top
|
|
wtop = top[depth]+widget.top
|
|
end
|
|
if full then
|
|
wtop = math.floor(wtop-top[depth])+top[depth]
|
|
end
|
|
|
|
if widget.right == nil then -- for widgets with no size option
|
|
return wleft..","..wtop..";"
|
|
|
|
else
|
|
local wright = 0
|
|
if widget.right_type == "R-" then
|
|
wright = left[depth]+fwidth[depth]-widget.right-wleft
|
|
elseif widget.right_type == "W/" then
|
|
wright = left[depth]+fwidth[depth]/widget.right-wleft
|
|
elseif widget.right_type == "R" then -- relative to left
|
|
wright = widget.right
|
|
else
|
|
wright = left[depth]+widget.right-wleft
|
|
end
|
|
|
|
local wbottom = 0
|
|
if widget.bottom_type == "B-" then
|
|
wbottom = top[depth]+fheight[depth]-widget.bottom-wtop
|
|
elseif widget.bottom_type == "H/" then
|
|
wbottom = top[depth]+fheight[depth]/widget.bottom-wtop
|
|
elseif widget.bottom_type == "R" then
|
|
wbottom = widget.bottom
|
|
else
|
|
wbottom = top[depth]+widget.bottom-wtop
|
|
end
|
|
|
|
if wleft+wright > width then -- stops widgets covering the controlls
|
|
boxes = boxes.."box["..width ..","..wtop ..";"..wleft+wright-width..","..wbottom..";#ff0000]" -- shows where it would go
|
|
wright = width-wleft
|
|
end
|
|
|
|
if real then
|
|
return {left=wleft, top=wtop, width=wright, height=wbottom} -- table uses the calculated values for other things
|
|
end
|
|
return wleft..","..wtop..";"..wright..","..wbottom..";"
|
|
end
|
|
end
|
|
|
|
-- iterate all widgets
|
|
for i, v in pairs(widgets) do
|
|
|
|
if v.type == "Display" then -- defines the size
|
|
if v.width < data.width-5.2 then
|
|
left = {math.floor(((data.width-5)/2 - v.width/2)*10)/10} -- place the form in the center
|
|
else
|
|
width = math.floor((v.width+0.2)*10)/10 -- resize for large forms
|
|
end
|
|
if v.height < data.height-0.2 then -- ^
|
|
top = {data.height/2 - v.height/2}
|
|
else
|
|
height = v.height+0.2
|
|
end
|
|
fwidth = {v.width}
|
|
fheight = {v.height}
|
|
form = form ..
|
|
-- "box["..left[1]..","..top[1]..";"..v.width..","..v.height..";#000000]" -- this adds it to the form
|
|
"box["..left[1]-0.28 ..","..top[1]-0.3 ..";"..v.width+0.38 ..",".. 0.32 ..";#000000]" ..
|
|
"box["..left[1]-0.28 ..","..top[1]+v.height..";"..v.width+0.38 ..",".. 0.4 ..";#000000]" ..
|
|
"box["..left[1]-0.28 ..","..top[1]..";".. 0.3 ..","..v.height..";#000000]" ..
|
|
"box["..left[1]+v.width..","..top[1]..";".. 0.1 ..","..v.height..";#000000]"
|
|
|
|
if v.background then
|
|
form = form .. "bgcolor["..v.colour..";"..tostring(v.fullscreen).."]"
|
|
end
|
|
if v.col.col then
|
|
form = form.."listcolors["..v.col.bg_normal..";"..v.col.bg_hover
|
|
if v.col.set_border then
|
|
form = form..";"..v.col.border
|
|
if v.col.set_tool then
|
|
form = form..";"..v.col.tool_bg..";"..v.col.tool_font
|
|
end
|
|
end
|
|
form = form.."]"
|
|
end
|
|
|
|
|
|
elseif v.type == "Button" then
|
|
if v.image then -- image option
|
|
if v.item and not v.exit then
|
|
form = form .. "item_image_button["..get_rect(v)..form_esc(v.texture)..";"..i.."_none;"..form_esc(v.label).."]"
|
|
else
|
|
form = form .. "image_button["..get_rect(v)..form_esc(v.texture)..";"..i.."_none;"..form_esc(v.label).."]"
|
|
end
|
|
else
|
|
form = form .. "button["..get_rect(v)..i.."_none;"..form_esc(v.label).."]"
|
|
end
|
|
|
|
elseif v.type == "Field" then
|
|
if v.password then -- password option
|
|
form = form .. "pwdfield["..get_rect(v)..i.."_none;"..form_esc(v.label).."]"
|
|
else
|
|
form = form .. "field["..get_rect(v)..i.."_none;"..form_esc(v.label)..";"..form_esc(v.default).."]"
|
|
end
|
|
form = form .. "field_close_on_enter["..i.."_none;false]"
|
|
|
|
elseif v.type == "TextArea" then
|
|
form = form .. "textarea["..get_rect(v)..i.."_none;"..form_esc(v.label)..";"..form_esc(v.default).."]"
|
|
|
|
elseif v.type == "Label" then
|
|
if v.vertical then -- vertical option
|
|
form = form .. "vertlabel["..get_rect(v)..form_esc(v.label).."]"
|
|
else
|
|
form = form .. "label["..get_rect(v)..form_esc(v.label).."]"
|
|
end
|
|
|
|
elseif v.type == "TextList" then
|
|
local item_str = "" -- convert the list to a sting
|
|
for i, item in pairs(v.items) do
|
|
item_str = item_str .. form_esc(item)..","
|
|
end
|
|
if v.transparent then -- transparent option
|
|
form = form .. "textlist["..get_rect(v)..i.."_none;"..item_str..";1;True]"
|
|
else
|
|
form = form .. "textlist["..get_rect(v)..i.."_none;"..item_str.."]"
|
|
end
|
|
|
|
elseif v.type == "DropDown" then
|
|
local item_str = "" -- convert the list to a string
|
|
for i, item in pairs(v.items) do
|
|
item_str = item_str .. form_esc(item)..","
|
|
end
|
|
form = form .. "dropdown["..get_rect(v)..i.."_none;"..item_str..";"..v.select_id.."]"
|
|
|
|
elseif v.type == "CheckBox" then
|
|
form = form .. "checkbox["..get_rect(v)..i.."_none;"..v.label..";"..tostring(v.checked).."]"
|
|
|
|
elseif v.type == "Box" then -- a coloured square
|
|
form = form .. "box["..get_rect(v)..form_esc(v.colour).."]"
|
|
|
|
elseif v.type == "Image" then
|
|
if v.item then
|
|
form = form .. "item_image["..get_rect(v)..form_esc(v.image).."]"
|
|
elseif v.background then
|
|
if v.fill then
|
|
form = form .. "background["..left[1]-0.18 ..","..top[1]-0.22 ..";"..fwidth[1]+0.37 ..","..fheight[1]+0.7 ..";"..form_esc(v.image).."]"
|
|
else
|
|
form = form .. "background["..get_rect(v)..form_esc(v.image).."]"
|
|
end
|
|
else
|
|
form = form .. "image["..get_rect(v)..form_esc(v.image).."]"
|
|
end
|
|
|
|
elseif v.type == "Slider" then
|
|
orientation = "horizontal"
|
|
if v.vertical then
|
|
orientation = "vertical"
|
|
end
|
|
form = form .. "scrollbar["..get_rect(v)..orientation..";"..i.."_none;"..v.value.."]"
|
|
|
|
elseif v.type == "InvList" then
|
|
local extras = {["player:"]=1, ["nodemeta:"]=1, ["detached:"]=1} -- locations that need extra info (v.data)
|
|
if extras[v.location] then
|
|
form = form .. "list["..v.location..form_esc(v.data)..";"..form_esc(v.name)..";"..get_rect(v)..v.start.."]"
|
|
if v.ring then -- items can be shift clicked between ring items
|
|
form = form .. "listring["..v.location..form_esc(v.data)..";"..form_esc(v.name).."]"
|
|
end
|
|
else
|
|
form = form .. "list["..v.location..";"..form_esc(v.name)..";"..get_rect(v)..v.start.."]"
|
|
if v.ring then
|
|
form = form .. "listring["..v.location..";"..form_esc(v.name).."]"
|
|
end
|
|
end
|
|
|
|
elseif v.type == "Table" then
|
|
local cell_str = ""
|
|
local column_str = ""
|
|
|
|
local most_items = 0 -- the amount of rows needed = the most items in a column
|
|
for i, c in pairs(v.columns) do
|
|
if #c.items > most_items then -- get max length
|
|
most_items = #c.items
|
|
end
|
|
|
|
if i > 1 then
|
|
column_str = column_str..";"
|
|
end
|
|
column_str = column_str .. c.type -- add column types
|
|
if c.type == "image" then -- add list of available images
|
|
for n, t in pairs(c.images) do
|
|
column_str = column_str..","..n .."="..form_esc(t)
|
|
end
|
|
elseif c.type == "color" and c.distance ~= "infinite" then -- add distance that coloures affect
|
|
column_str = column_str..",span="..c.distance
|
|
end
|
|
end
|
|
for i=1, most_items do -- create a list from all column's lists
|
|
for n, c in pairs(v.columns) do -- create a row from column's items
|
|
if n > 1 or i > 1 then
|
|
cell_str = cell_str..","
|
|
end
|
|
local item = c.items[i]
|
|
if item == nil then -- blank item if this column doesn't exend as far
|
|
item = ""
|
|
end
|
|
cell_str = cell_str..form_esc(item)
|
|
end
|
|
end
|
|
if column_str:len() > 0 then
|
|
form = form .. "tablecolumns["..column_str.."]"
|
|
end
|
|
form = form .. "table["..get_rect(v)..i.."_none;"..cell_str..";-1]"
|
|
|
|
elseif v.type == "Tooltip" then
|
|
for n, w in pairs(widgets) do
|
|
if w.name == v.name and w.type ~= "Tooltip" then
|
|
if v.colours then
|
|
form = form .. "tooltip["..n.."_none;"..v.text..";"..v.bg..";"..v.fg.."]"
|
|
else
|
|
form = form .. "tooltip["..n.."_none;"..v.text.."]"
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif v.type == "Container - Start" then
|
|
local rect = get_rect(v, true, true)
|
|
left[depth+1] = rect.left -- register the new area
|
|
top[depth+1] = rect.top
|
|
fwidth[depth+1] = rect.width
|
|
fheight[depth+1] = rect.height
|
|
depth = depth+1
|
|
elseif v.type == "Container - End" then
|
|
depth = depth-1 -- go back to the parent area
|
|
|
|
elseif v.type == "Tabs" then
|
|
local capt_str = ""
|
|
for i, capt in pairs(v.captions) do
|
|
if i > 1 then capt_str = capt_str.."," end
|
|
capt_str = capt_str .. form_esc(capt)
|
|
end
|
|
form = form .. "tabheader["..get_rect(v)..i.."_none;"..capt_str..";"..v.tab..";"..tostring(v.transparent)..";"..tostring(v.border).."]"
|
|
|
|
end
|
|
end
|
|
|
|
return form..boxes, width+5, height
|
|
end
|
|
|
|
|
|
----------
|
|
-- Compiling
|
|
----------
|
|
|
|
-- generates a function to create the UI, with parameters
|
|
local function generate_function()
|
|
local form_esc = function(str) -- escape symbols need to be escaped
|
|
return string.gsub(minetest.formspec_escape(str), "\\", "\\\\") -- which have to be escaped...
|
|
end
|
|
|
|
local parameters = {} -- these store info which will be put together at the end
|
|
local before_str = ""
|
|
local display = {}
|
|
local form = ""
|
|
local table_items = false
|
|
|
|
local function name(v) -- converts the name into something that can be used in parameters
|
|
n = v.name
|
|
|
|
if v.type == "InvList" then -- the name of inv lists is used differently
|
|
n = v.location.."_"..v.name
|
|
end
|
|
|
|
local new = ""
|
|
|
|
chars = "abcdefghijklmnopqrstuvwxyz"
|
|
chars = chars..string.upper(chars)
|
|
for i=1, #n do
|
|
local c = n:sub(i,i)
|
|
if string.find(chars, c, 1, true) or (string.find("1234567890", c, 1, true) and i ~= 1) then -- numbers only allowed after first char
|
|
new = new..c
|
|
else
|
|
new = new.."_"
|
|
end
|
|
end
|
|
return new
|
|
end
|
|
|
|
local width = {widgets[1].width}
|
|
if widgets[1].width_param then -- if size defined from parameters
|
|
width = {"width"}
|
|
end
|
|
local height = {widgets[1].height}
|
|
if widgets[1].height_param then
|
|
height = {"height"}
|
|
end
|
|
local dep = 1 -- depth into containers
|
|
|
|
-- returns a string containing the position and size of a widget, or (hopefully) the most efficient calculation
|
|
local function get_rect(widget, real, l, t)
|
|
local fwidth = width[dep]
|
|
local fheight = height[dep]
|
|
|
|
local wleft = "0"
|
|
if type(fwidth) == "string" or l then -- if the area width (window or continer) will be changed with a parameter
|
|
local l_ = l -- if the left of the widget comes from a parameter
|
|
if l_ == nil then
|
|
l_ = widget.left
|
|
end
|
|
if widget.left_type == "R-" then -- different position types
|
|
wleft = fwidth..'- '..l_
|
|
elseif widget.left_type == "W/" then
|
|
wleft = fwidth..'/'..l_
|
|
else
|
|
wleft = l_
|
|
end
|
|
if type(wleft) == "string" and not real then
|
|
wleft = '"..'..wleft..' .."'
|
|
end
|
|
else
|
|
if widget.left_type == "R-" then -- calculation made now if nothing comes from a parameter
|
|
wleft = fwidth-widget.left
|
|
elseif widget.left_type == "W/" then
|
|
wleft = fwidth/widget.left
|
|
else
|
|
wleft = widget.left
|
|
end
|
|
end
|
|
|
|
local wtop = "0" --top
|
|
if type(fheight) == "string" or t then
|
|
local t_ = t
|
|
if t_ == nil then
|
|
t_ = widget.top
|
|
end
|
|
if widget.top_type == "B-" then
|
|
wtop = fheight..'- '..t_
|
|
elseif widget.left_type == "H/" then
|
|
wtop = fheight..'/'..t_
|
|
else
|
|
wtop = t_
|
|
end
|
|
if type(wtop) == "string" and not real then
|
|
wtop = '"..'..wtop..' .."'
|
|
end
|
|
else
|
|
if widget.top_type == "B-" then
|
|
wtop = fheight-widget.top
|
|
elseif widget.left_type == "H/" then
|
|
wtop = fheight/widget.top
|
|
else
|
|
wtop = widget.top
|
|
end
|
|
end
|
|
|
|
if widget.right == nil then -- for widgets with no size option
|
|
return wleft..","..wtop
|
|
|
|
else
|
|
local wright = 0
|
|
if type(fwidth) == "string" then -- if the width is changed by a parameter
|
|
local l_ = l
|
|
if l_ == nil then
|
|
l_ = widget.left
|
|
end
|
|
-- goes through all right types, and for eacg, goes through all left types to get the best calculation.
|
|
if widget.right_type == "R-" then -- (I know there is a better way of doing this)
|
|
if widget.left_type == "R-" then
|
|
wright = fwidth..'- '..widget.right..'-('..fwidth..'- '..l_..')'
|
|
elseif widget.left_type == "W/" then
|
|
wright = fwidth..'- '..widget.right..'-('..fwidth..'/'..l_..')'
|
|
elseif type(l_) == "string" then
|
|
wright = fwidth..'- '..widget.right.."- "..l_
|
|
else
|
|
wright = fwidth..'- '..widget.right+l_
|
|
end
|
|
elseif widget.right_type == "W/" then
|
|
if widget.left_type == "R-" then
|
|
wright = fwidth..'/'..widget.right..'-('..fwidth..'- '..l_..')'
|
|
elseif widget.left_type == "W/" then
|
|
wright = fwidth..'/'..widget.right..'-('..fwidth..'/'..l_..')'
|
|
else
|
|
wright = fwidth..'/'..widget.right.."- "..l_
|
|
end
|
|
elseif widget.right_type == "R" then
|
|
wright = widget.right
|
|
else
|
|
if widget.left_type == "R-" then
|
|
wright = widget.right..'-('..fwidth..'- '..l_..')'
|
|
elseif widget.left_type == "W/" then
|
|
wright = widget.right..'-('..fwidth..'/'..l_..')'
|
|
elseif type(l) == "string" then
|
|
wright = widget.right.."- "..l_
|
|
else
|
|
wright = widget.right-l_
|
|
end
|
|
end
|
|
if type(wright) == "string" and not real then
|
|
wright = '"..'..wright..' .."'
|
|
end
|
|
elseif l then -- if there is a parameter for the left, but not the width
|
|
if widget.right_type == "R-" then
|
|
if widget.left_type == "R-" then
|
|
wright = fwidth-widget.right..'-('..fwidth..'- '..l..')'
|
|
elseif widget.left_type == "W/" then
|
|
wright = fwidth-widget.right..'-('..fwidth..'/'..l..')'
|
|
else
|
|
wright = fwidth-widget.right.."- "..l
|
|
end
|
|
elseif widget.right_type == "W/" then
|
|
if widget.left_type == "R-" then
|
|
wright = fwidth..'/'..widget.right..'-('..fwidth..'- '..l..')'
|
|
elseif widget.left_type == "W/" then
|
|
wright = fwidth..'/'..widget.right..'-('..fwidth..'/'..l..')'
|
|
else
|
|
wright = fwidth..'/'..widget.right.."- "..l
|
|
end
|
|
elseif widget.right_type == "R" then
|
|
wright = widget.right
|
|
else
|
|
if widget.left_type == "R-" then
|
|
wright = widget.right..'-('..fwidth..'- '..l..')'
|
|
elseif widget.left_type == "W/" then
|
|
wright = widget.right..'-('..fwidth..'/'..l..')'
|
|
else
|
|
wright = widget.right.."- "..l
|
|
end
|
|
end
|
|
if type(wright) == "string" and not real then
|
|
wright = '"..'..wright..' .."'
|
|
end
|
|
else -- if all values are known now
|
|
if widget.right_type == "R-" then
|
|
wright = fwidth-widget.right-wleft
|
|
elseif widget.right_type == "W/" then
|
|
wright = fwidth/widget.right-wleft
|
|
elseif widget.right_type == "R" then
|
|
wright = widget.right
|
|
else
|
|
wright = widget.right-wleft
|
|
end
|
|
end
|
|
|
|
local wbottom = 0 -- similar for bottom
|
|
if type(fheight) == "string" then
|
|
local t_ = t
|
|
if t_ == nil then -- if widget's top comes from a parameter (container)
|
|
t_ = widget.top
|
|
end
|
|
if widget.bottom_type == "B-" then
|
|
if widget.top_type == "B-" then
|
|
wbottom = fheight..'- '..widget.bottom..'-('..fheight..'- '..t_..')'
|
|
elseif widget.left_type == "W/" then
|
|
wbottom = fheight..'- '..widget.bottom..'-('..fheight..'/'..t_..')'
|
|
elseif type(t_) == "string" then
|
|
wbottom = fheight..'- '..widget.bottom.."- "..t_
|
|
else
|
|
wbottom = fheight..'- '..widget.bottom+t_
|
|
end
|
|
elseif widget.bottom_type == "H/" then
|
|
if widget.top_type == "B-" then
|
|
wbottom = fheight..'/'..widget.bottom..'-('..fheight..'- '..t_..')'
|
|
elseif widget.left_type == "W/" then
|
|
wbottom = fheight..'/'..widget.bottom..'-('..fheight..'/'..t_..')'
|
|
else
|
|
wbottom = fheight..'/'..widget.bottom.."- "..t_
|
|
end
|
|
elseif widget.bottom_type == "R" then
|
|
wbottom = widget.bottom
|
|
else
|
|
if widget.top_type == "B-" then
|
|
wbottom = widget.bottom..'-('..fheight..'- '..t_..')'
|
|
elseif widget.left_type == "W/" then
|
|
wbottom = widget.bottom..'-('..fheight..'/'..t_..')'
|
|
elseif type(t_) == "string" then
|
|
wbottom = widget.bottom.."- "..t_
|
|
else
|
|
wbottom = widget.bottom-t_
|
|
end
|
|
end
|
|
if type(wbottom) == "string" and not real then
|
|
wbottom = '"..'..wbottom..' .."'
|
|
end
|
|
elseif t then
|
|
if widget.bottom_type == "B-" then
|
|
if widget.top_type == "B-" then
|
|
wbottom = fheight-widget.bottom-fheight..'- '..t
|
|
elseif widget.left_type == "W/" then
|
|
wbottom = fheight-widget.bottom-fheight..'/'..t
|
|
else
|
|
wbottom = fheight-widget.bottom.."+"..t
|
|
end
|
|
elseif widget.bottom_type == "H/" then
|
|
if widget.top_type == "B-" then
|
|
wbottom = fheight/widget.bottom-fheight..'- '..t
|
|
elseif widget.left_type == "W/" then
|
|
wbottom = fheight/widget.bottom-fheight..'/'..t
|
|
else
|
|
wbottom = fheight/widget.bottom.."- "..t
|
|
end
|
|
elseif widget.bottom_type == "R" then
|
|
wbottom = widget.bottom
|
|
else
|
|
if widget.top_type == "B-" then
|
|
wbottom = widget.bottom-fheight..'- '..t
|
|
elseif widget.left_type == "W/" then
|
|
wbottom = widget.bottom-fheight..'/'..t
|
|
elseif type(t) == "string" then
|
|
wbottom = widget.bottom.."- "..t
|
|
else
|
|
wbottom = widget.bottom-t
|
|
end
|
|
end
|
|
if type(wbottom) == "string" and not real then
|
|
wbottom = '"..'..wbottom..' .."'
|
|
end
|
|
else
|
|
if widget.bottom_type == "B-" then
|
|
wbottom = fheight-widget.bottom-wtop
|
|
elseif widget.bottom_type == "H/" then
|
|
wbottom = fheight/widget.bottom-wtop
|
|
elseif widget.bottom_type == "R" then
|
|
wbottom = widget.bottom
|
|
else
|
|
wbottom = widget.bottom-wtop
|
|
end
|
|
end
|
|
|
|
if real then
|
|
return {left=wleft, top=wtop, width=wright, height=wbottom} -- container needs the values seperate
|
|
end
|
|
return wleft..","..wtop..";"..wright..","..wbottom
|
|
end
|
|
end
|
|
|
|
|
|
local w, h = 0, 0
|
|
|
|
-- go through all the widgets, and add their code
|
|
for i, v in pairs(widgets) do
|
|
|
|
if v.type == "Display" then
|
|
local w, h
|
|
if v.width_param then -- things like this are for parameters
|
|
table.insert(parameters, "width")
|
|
w = '"..width.."'
|
|
else
|
|
w = tostring(v.width)
|
|
end
|
|
if v.height_param then
|
|
table.insert(parameters, "height")
|
|
h = '"..height.."'
|
|
else
|
|
h = tostring(v.height)
|
|
end
|
|
table.insert(display, '"size['..w..','..h..']"')
|
|
if v.position then -- for non-default position
|
|
table.insert(display, '"position['..v.left..','..v.top..']"')
|
|
end
|
|
if v.background then
|
|
table.insert(display, '"bgcolor['..v.colour..';'..tostring(v.fullscreen)..']"')
|
|
end
|
|
if v.col.col then
|
|
local cols = '"listcolors['..v.col.bg_normal..";"..v.col.bg_hover
|
|
if v.col.set_border then
|
|
cols = cols..";"..v.col.border
|
|
if v.col.set_tool then
|
|
cols = cols..";"..v.col.tool_bg..";"..v.col.tool_font
|
|
end
|
|
end
|
|
cols = cols..']"'
|
|
table.insert(display, cols)
|
|
end
|
|
|
|
|
|
elseif v.type == "Button" then
|
|
if v.image then
|
|
local tex = ""
|
|
if v.image_param then -- image texture param
|
|
table.insert(parameters, name(v).."_image")
|
|
tex = '"..'..name(v)..'_image.."'
|
|
else
|
|
tex = form_esc(v.texture)
|
|
end
|
|
if v.item and not v.exit then -- quit on click
|
|
table.insert(display, '"item_image_button['..get_rect(v)..';'..tex..';'..form_esc(v.name)..';'..form_esc(v.label)..']"')
|
|
else
|
|
if v.exit then -- quit on click - image
|
|
table.insert(display, '"image_button_exit['..get_rect(v)..';'..tex..';'..form_esc(v.name)..';'..form_esc(v.label)..']"')
|
|
else -- normal image
|
|
table.insert(display, '"image_button['..get_rect(v)..';'..tex..';'..form_esc(v.name)..';'..form_esc(v.label)..']"')
|
|
end
|
|
end
|
|
else
|
|
if v.exit then -- quit on click
|
|
table.insert(display, '"button_exit['..get_rect(v)..';'..form_esc(v.name)..';'..form_esc(v.label)..']"')
|
|
else -- basic button
|
|
table.insert(display, '"button['..get_rect(v)..';'..form_esc(v.name)..';'..form_esc(v.label)..']"')
|
|
end
|
|
end
|
|
|
|
elseif v.type == "Field" then
|
|
if v.password then -- password field
|
|
table.insert(display, '"pwdfield['..get_rect(v)..';'..form_esc(v.name)..';'..form_esc(v.label)..']"')
|
|
else
|
|
local default = ""
|
|
if v.default_param then -- default param
|
|
table.insert(parameters, name(v).."_default")
|
|
default = '"..minetest.formspec_escape('..name(v)..'_default).."'
|
|
else
|
|
default = form_esc(v.default)
|
|
end
|
|
table.insert(display, '"field['..get_rect(v)..';'..form_esc(v.name)..';'..form_esc(v.label)..';'..default..']"')
|
|
end
|
|
if v.enter_close == false then
|
|
table.insert(display, '"field_close_on_enter['..form_esc(v.name)..';false]"')
|
|
end
|
|
|
|
elseif v.type == "TextArea" then
|
|
local default = ""
|
|
if v.default_param then
|
|
table.insert(parameters, name(v).."_default")
|
|
default = '"..minetest.formspec_escape('..name(v)..'_default).."'
|
|
else
|
|
default = form_esc(v.default)
|
|
end
|
|
table.insert(display, '"textarea['..get_rect(v)..';'..form_esc(v.name)..';'..form_esc(v.label)..';'..form_esc(default)..']"')
|
|
|
|
elseif v.type == "Label" then
|
|
local label = form_esc(v.label)
|
|
if v.label_param then
|
|
table.insert(parameters, name(v).."_label")
|
|
label = '"..minetest.formspec_escape('..name(v)..'_label).."'
|
|
end
|
|
if v.vertical then -- vertical label
|
|
table.insert(display, '"vertlabel['..get_rect(v)..';'..label..']"')
|
|
else
|
|
table.insert(display, '"label['..get_rect(v)..';'..label..']"')
|
|
end
|
|
|
|
elseif v.type == "TextList" then
|
|
local items = ""
|
|
if v.items_param then
|
|
table.insert(parameters, name(v).."_items")
|
|
before_str = before_str.. -- add code for converting the list from a parameter to a string
|
|
' local '..name(v)..'_item_str = ""\n' ..
|
|
' for i, item in pairs('..name(v)..'_items) do\n' ..
|
|
' if i ~= 1 then '..name(v)..'_item_str = '..name(v)..'_item_str.."," end\n' ..
|
|
' '..name(v)..'_item_str = '..name(v)..'_item_str .. minetest.formspec_escape(item)\n' ..
|
|
' end\n\n'
|
|
items = '"..'..name(v)..'_item_str.."'
|
|
else
|
|
items = ""
|
|
for i, item in pairs(v.items) do
|
|
if i ~= 1 then items = items.."," end
|
|
items = items .. form_esc(item)
|
|
end
|
|
end
|
|
if v.item_id_param or v.transparent then
|
|
if v.item_id_param then -- selected item parameter
|
|
table.insert(parameters, name(v).."_selected_item")
|
|
table.insert(display, '"textlist['.. get_rect(v)..';'..form_esc(v.name)..';'..items..';"..'..name(v)..'_selected_item..";'..tostring(v.transparent)..']"')
|
|
else
|
|
table.insert(display, '"textlist['..get_rect(v)..';'..form_esc(v.name)..';'..items..';1;'..tostring(v.transparent)..']"')
|
|
end
|
|
else
|
|
table.insert(display, '"textlist['..get_rect(v)..';'..form_esc(v.name)..';'..items..']"')
|
|
end
|
|
|
|
elseif v.type == "DropDown" then
|
|
local items = ""
|
|
if v.items_param then
|
|
table.insert(parameters, name(v).."_items")
|
|
before_str = before_str.. -- add code for converting the list from a parameter to a string
|
|
' local '..name(v)..'_item_str = ""\n' ..
|
|
' for i, item in pairs('..name(v)..'_items) do\n' ..
|
|
' if i ~= 1 then '..name(v)..'_item_str = '..name(v)..'_item_str.."," end\n' ..
|
|
' '..name(v)..'_item_str = '..name(v)..'_item_str .. minetest.formspec_escape(item)\n' ..
|
|
' end\n\n'
|
|
items = '"..'..name(v)..'_item_str.."'
|
|
else
|
|
items = ""
|
|
for i, item in pairs(v.items) do
|
|
if i ~= 1 then items = items.."," end
|
|
items = items .. form_esc(item)
|
|
end
|
|
end
|
|
local item_id = ""
|
|
if v.item_id_param then -- selected item parameter
|
|
table.insert(parameters, name(v).."_selected_item")
|
|
item_id = '"..'..name(v)..'_selected_item.."'
|
|
else
|
|
item_id = tostring(v.select_id)
|
|
end
|
|
table.insert(display, '"dropdown['..get_rect(v)..';'..form_esc(v.name)..';'..items..';'..item_id..']"')
|
|
|
|
elseif v.type == "CheckBox" then
|
|
local checked = tostring(v.checked)
|
|
if v.checked_param then
|
|
table.insert(parameters, name(v).."_checked")
|
|
checked = '"..tostring('..name(v)..'_checked).."'
|
|
end
|
|
table.insert(display, '"checkbox['..get_rect(v)..';'..form_esc(v.name)..";"..form_esc(v.label)..';'..checked..']"')
|
|
|
|
elseif v.type == "Box" then
|
|
local colour = form_esc(v.colour)
|
|
if v.colour_param then
|
|
table.insert(parameters, name(v).."_colour")
|
|
colour = '"..'..name(v)..'_colour.."'
|
|
end
|
|
table.insert(display, '"box['..get_rect(v)..';'..colour..']"')
|
|
|
|
elseif v.type == "Image" then
|
|
local image = form_esc(v.image)
|
|
if v.image_param then -- texture
|
|
table.insert(parameters, name(v).."_image")
|
|
image = '"..'..name(v)..'_image.."'
|
|
end
|
|
if v.item then
|
|
table.insert(display, '"item_image['..get_rect(v)..';'..image..']"')
|
|
elseif v.background then
|
|
table.insert(display, '"background['..get_rect(v)..';'..image..';'..tostring(v.fill)..']"')
|
|
else
|
|
table.insert(display, '"image['..get_rect(v)..';'..image..']"')
|
|
end
|
|
|
|
elseif v.type == "Slider" then
|
|
local value = form_esc(v.value)
|
|
if v.value_param then
|
|
table.insert(parameters, name(v).."_value")
|
|
value = '"..'..name(v)..'_value.."'
|
|
end
|
|
local orientation = "horizontal"
|
|
if v.vertical then
|
|
orientation = "vertical"
|
|
end
|
|
table.insert(display, '"scrollbar['..get_rect(v)..';'..orientation..";"..form_esc(v.name)..";"..value..']"')
|
|
|
|
elseif v.type == "InvList" then
|
|
local extras = {["player:"]=1, ["nodemeta:"]=1, ["detached:"]=1}
|
|
local data = ""
|
|
if v.data_param then -- extra location data needed in some locations
|
|
table.insert(parameters, name(v).."_data")
|
|
data = '"..minetest.formspec_escape('..name(v)..'_data).."'
|
|
elseif extras[v.location] then
|
|
data = form_esc(v.data)
|
|
end
|
|
local start = v.start
|
|
if v.page_param then
|
|
table.insert(parameters, name(v).."_start_idx")
|
|
start = '"..'..name(v)..'_start_idx.."'
|
|
end
|
|
table.insert(display, '"list['..v.location..data..';'..form_esc(v.name)..';'..get_rect(v)..';'..start..']"')
|
|
if v.ring then -- shift clicking between item lists
|
|
table.insert(display, '"listring['..v.location..data..';'..form_esc(v.name)..']"')
|
|
end
|
|
|
|
elseif v.type == "Table" then
|
|
local cell_str = ""
|
|
local column_str = ""
|
|
|
|
local item_param = false
|
|
local most_items = 0
|
|
for i, c in pairs(v.columns) do
|
|
if #c.items > most_items then -- find how many columns are needed
|
|
most_items = #c.items
|
|
end
|
|
if c.items_param then -- find out if any parameters are needed
|
|
item_param = true
|
|
end
|
|
|
|
if i > 1 then -- create a column string
|
|
column_str = column_str..";"
|
|
end
|
|
column_str = column_str .. c.type
|
|
if c.type == "image" then -- add list of images
|
|
for n, t in pairs(c.images) do
|
|
column_str = column_str..","..n .."="..t
|
|
end
|
|
elseif c.type == "color" and c.distance ~= "infinite" then -- and distance affected by colour
|
|
column_str = column_str..",span="..c.distance
|
|
end
|
|
end
|
|
|
|
if not item_param then -- calculate item list if none come from parameters
|
|
for i=1, most_items do
|
|
for n, c in pairs(v.columns) do
|
|
if n > 1 or i > 1 then
|
|
cell_str = cell_str..","
|
|
end
|
|
local item = c.items[i]
|
|
if item == nil then
|
|
item = ""
|
|
end
|
|
cell_str = cell_str..item
|
|
end
|
|
end
|
|
else -- or add the code to convert the items from the parameters into a string
|
|
local items = " local "..name(v).."_cells = {"
|
|
for i, c in pairs(v.columns) do
|
|
if c.items_param then
|
|
table.insert(parameters, name(v).."_col_"..i.."_items")
|
|
items = items.."\n ["..i.."]="..name(v).."_col_"..i.."_items,"
|
|
else
|
|
local item_str = "{" -- create a string table with the items
|
|
for n, item in pairs(c.items) do
|
|
item_str = item_str..'"'..item..'", '
|
|
end
|
|
item_str = item_str.."}"
|
|
items = items.."\n ["..i.."]="..item_str..","
|
|
end
|
|
end
|
|
items = items.."\n }\n"
|
|
|
|
table_items = true -- this makes it add the function onto the start of the function
|
|
before_str = before_str..items ..
|
|
' local '..name(v)..'_cell_str = table_item_str('..name(v)..'_cells)\n\n'
|
|
|
|
cell_str = '"..'..name(v)..'_cell_str.."'
|
|
end
|
|
|
|
if column_str:len() > 0 then -- tablecolumns without columns gives an error
|
|
table.insert(display, '"tablecolumns['..column_str..']"')
|
|
end
|
|
|
|
local selected = ""
|
|
if v.select_param then -- selected item parameter
|
|
table.insert(parameters, name(v).."_selected_item")
|
|
selected = '"..'..name(v)..'_selected_item.."'
|
|
end
|
|
table.insert(display, '"table['..get_rect(v)..";"..form_esc(v.name)..';'..cell_str..';'..selected..']"')
|
|
|
|
elseif v.type == "Tooltip" then
|
|
if v.colours then
|
|
table.insert(display, '"tooltip['..form_esc(v.name)..';'..form_esc(v.text)..';'..form_esc(v.bg)..';'..form_esc(v.fg)..']"')
|
|
else
|
|
table.insert(display, '"tooltip['..form_esc(v.name)..';'..form_esc(v.text)..']"')
|
|
end
|
|
|
|
elseif v.type == "Container - Start" then -- container has 2 sections
|
|
local l = v.left
|
|
if v.left_param then -- the only widget which can hve position parameters
|
|
table.insert(parameters, name(v).."_left")
|
|
l = name(v)..'_left'
|
|
end
|
|
local t = v.top
|
|
if v.top_param then
|
|
table.insert(parameters, name(v).."_top")
|
|
t = name(v)..'_top'
|
|
end
|
|
local rect = get_rect(v, true, l, t) -- the area is returned as a table this time
|
|
dep = dep+1
|
|
if type(rect.width) == "string" then -- if it is a calculation, and not the calculated value
|
|
width[dep] = "("..rect.width..")"
|
|
else
|
|
width[dep] = rect.width
|
|
end
|
|
if type(rect.height) == "string" then
|
|
height[dep] = "("..rect.height..")"
|
|
else
|
|
height[dep] = rect.height
|
|
end
|
|
if type(rect.left) == "string" then
|
|
rect.left = '"..'..rect.left..' .."'
|
|
end
|
|
if type(rect.top) == "string" then
|
|
rect.top = '"..'..rect.top..' .."'
|
|
end
|
|
table.insert(display, '"container['..rect.left..','..rect.top..']"')
|
|
elseif v.type == "Container - End" then -- only exits the table
|
|
dep = dep-1
|
|
table.insert(display, '"container_end[]"')
|
|
|
|
elseif v.type == "Tabs" then
|
|
local capt_str = ""
|
|
for i, capt in pairs(v.captions) do
|
|
if i > 1 then capt_str = capt_str.."," end
|
|
capt_str = capt_str .. form_esc(capt)
|
|
end
|
|
table.insert(display, '"tabheader['..get_rect(v)..';'..form_esc(v.name)..';'..capt_str..';'..v.tab..';'.. tostring(v.transparent)..';'..tostring(v.border)..']"')
|
|
|
|
end
|
|
end
|
|
|
|
if table_items then -- the function generating a string from a list of column items
|
|
before_str = '' .. -- added if a table uses parameters
|
|
' local function table_item_str(cells)\n' ..
|
|
' local most_items = 0\n' ..
|
|
' for i, v in pairs(cells) do\n' ..
|
|
' if #v > most_items then\n' ..
|
|
' most_items = #v\n' ..
|
|
' end\n' ..
|
|
' end\n' ..
|
|
' local cell_str = ""\n' ..
|
|
' for i=1, most_items do\n' ..
|
|
' for n=1, #cells do\n' ..
|
|
' if n > 1 or i > 1 then ' ..
|
|
'cell_str = cell_str.."," ' ..
|
|
'end\n' ..
|
|
' local item = cells[n][i]\n' ..
|
|
' if item == nil then ' ..
|
|
'item = "" ' ..
|
|
'end\n' ..
|
|
' cell_str = cell_str..minetest.formspec_escape(item)\n' ..
|
|
' end\n' ..
|
|
' end\n' ..
|
|
' return cell_str\n' ..
|
|
' end\n\n' ..
|
|
before_str
|
|
end
|
|
|
|
param_str = "" -- creates the parameter string --> "param1, param2, paramN"
|
|
for i, v in pairs(parameters) do
|
|
if i ~= 1 then
|
|
param_str = param_str .. ", "
|
|
end
|
|
param_str = param_str .. v
|
|
end
|
|
|
|
-- puts the first part of the function together
|
|
form = form .. "function generate_form("..param_str..")\n" .. before_str .. '\n local form = "" ..\n'
|
|
|
|
for i, v in pairs(display) do -- adds the widget strings
|
|
form = form .. " "..v.." ..\n"
|
|
end
|
|
|
|
form = form .. ' ""\n\n return form\nend' -- completes it
|
|
|
|
return form
|
|
end
|
|
|
|
-- generates a string for a static UI
|
|
local function generate_string()
|
|
local form_esc = function(str) -- escape symbols need to be escaped with escaped escape symbols ;p
|
|
return string.gsub(minetest.formspec_escape(str), "\\", "\\\\")
|
|
end
|
|
|
|
local fwidth = {0}
|
|
local fheight = {0}
|
|
local dep = 1
|
|
|
|
local function get_rect(widget, real) -- can't be bothered commenting this. see function on line 73, it is basically the same...
|
|
local wleft = 0
|
|
if widget.left_type == "R-" then
|
|
wleft = fwidth[dep]-widget.left
|
|
elseif widget.left_type == "W/" then
|
|
wleft = fwidth[dep]/widget.left
|
|
else
|
|
wleft = widget.left
|
|
end
|
|
|
|
local wtop = 0
|
|
if widget.top_type == "B-" then
|
|
wtop = fheight[dep]-widget.top
|
|
elseif widget.left_type == "H/" then
|
|
wtop = fheight[dep]/widget.top
|
|
else
|
|
wtop = widget.top
|
|
end
|
|
|
|
if widget.right == nil then -- for widgets with no size option
|
|
return wleft..","..wtop..";"
|
|
|
|
else
|
|
local wright = 0
|
|
if widget.right_type == "R-" then
|
|
wright = fwidth[dep]-widget.right-wleft
|
|
elseif widget.right_type == "W/" then
|
|
wright = fwidth[dep]/widget.right-wleft
|
|
elseif widget.right_type == "R" then
|
|
wright = widget.right
|
|
else
|
|
wright = widget.right-wleft
|
|
end
|
|
|
|
local wbottom = 0
|
|
if widget.bottom_type == "B-" then
|
|
wbottom = fheight[dep]-widget.bottom-wtop
|
|
elseif widget.bottom_type == "H/" then
|
|
wbottom = fheight[dep]/widget.bottom-wtop
|
|
elseif widget.bottom_type == "R" then
|
|
wbottom = widget.bottom
|
|
else
|
|
wbottom = widget.bottom-wtop
|
|
end
|
|
|
|
if real then
|
|
return {left=wleft, top=wtop, width=wright, height=wbottom}
|
|
end
|
|
return wleft..","..wtop..";"..wright..","..wbottom..";"
|
|
end
|
|
end
|
|
|
|
local output = ""
|
|
|
|
for i, v in pairs(widgets) do -- go through all the widgets and create their strings
|
|
|
|
if v.type == "Display" then
|
|
fwidth = {v.width}
|
|
fheight = {v.height}
|
|
output = output .. "\"size["..v.width..","..v.height.."]\" ..\n"
|
|
if v.position then
|
|
output = output .. "\"position["..v.left..","..v.top.."]\" ..\n"
|
|
end
|
|
if v.background then
|
|
output = output .. "\"bgcolor["..v.colour..";"..tostring(v.fullscreen).."]\" ..\n"
|
|
end
|
|
if v.col.col then
|
|
output = output.."\"listcolors["..v.col.bg_normal..";"..v.col.bg_hover
|
|
if v.col.set_border then
|
|
output = output..";"..v.col.border
|
|
if v.col.set_tool then
|
|
output = output..";"..v.col.tool_bg..";"..v.col.tool_font
|
|
end
|
|
end
|
|
output = output.."]\" ..\n"
|
|
end
|
|
|
|
elseif v.type == "Button" then
|
|
if v.image then
|
|
local ending = get_rect(v)..form_esc(v.texture)..";"..form_esc(v.name)..";"..form_esc(v.label).."]\" ..\n"
|
|
if v.item and not v.exit then
|
|
output = output .. "\"item_image_button["..ending
|
|
else
|
|
if v.exit then
|
|
output = output .. "\"image_button_exit["..ending
|
|
else
|
|
output = output .. "\"image_button["..ending
|
|
end
|
|
end
|
|
else
|
|
if v.exit then
|
|
output = output .. "\"button_exit["..get_rect(v)..form_esc(v.name)..";"..form_esc(v.label).."]\" ..\n"
|
|
else
|
|
output = output .. "\"button["..get_rect(v)..form_esc(v.name)..";"..form_esc(v.label).."]\" ..\n"
|
|
end
|
|
end
|
|
|
|
elseif v.type == "Field" then
|
|
if v.password then
|
|
output = output .. "\"pwdfield["..get_rect(v)..form_esc(v.name)..";"..form_esc(v.label).."]\" ..\n"
|
|
else
|
|
output = output .. "\"field["..get_rect(v)..form_esc(v.name)..";"..form_esc(v.label)..";"..form_esc(v.default).."]\" ..\n"
|
|
end
|
|
if v.enter_close == false then
|
|
output = output .. "\"field_close_on_enter["..form_esc(v.name)..";false]\" ..\n"
|
|
end
|
|
|
|
elseif v.type == "TextArea" then
|
|
output = output .. "\"textarea["..get_rect(v)..form_esc(v.name)..";"..form_esc(v.label)..";"..form_esc(v.default).."]\" ..\n"
|
|
|
|
elseif v.type == "Label" then
|
|
if v.vertical then
|
|
output = output .. "\"vertlabel["..get_rect(v)..form_esc(v.label).."]\" ..\n"
|
|
else
|
|
output = output .. "\"label["..get_rect(v)..form_esc(v.label).."]\" ..\n"
|
|
end
|
|
|
|
elseif v.type == "TextList" then
|
|
local item_str = ""
|
|
for i, item in pairs(v.items) do
|
|
item_str = item_str .. form_esc(item)..","
|
|
end
|
|
if not v.transparent then
|
|
output = output .. "\"textlist["..get_rect(v)..form_esc(v.name)..";"..item_str:sub(0,-2).."]\" ..\n"
|
|
else
|
|
output = output .. "\"textlist["..get_rect(v)..form_esc(v.name)..";"..item_str:sub(0,-2)..";1;true]\" ..\n"
|
|
end
|
|
|
|
elseif v.type == "DropDown" then
|
|
local item_str = ""
|
|
for i, item in pairs(v.items) do
|
|
item_str = item_str .. form_esc(item)..","
|
|
end
|
|
output = output .. "\"dropdown["..get_rect(v)..form_esc(v.name)..";"..item_str:sub(0,-2)..";"..v.select_id.."]\" ..\n"
|
|
|
|
elseif v.type == "CheckBox" then
|
|
output = output .. "\"checkbox["..get_rect(v)..form_esc(v.name)..";"..form_esc(v.label)..";"..tostring(v.checked).."]\" ..\n"
|
|
|
|
elseif v.type == "Box" then
|
|
output = output .. "\"box["..get_rect(v)..form_esc(v.colour).."]\" ..\n"
|
|
|
|
elseif v.type == "Image" then
|
|
if v.item then
|
|
output = output .. "\"item_image["..get_rect(v)..form_esc(v.image).."]\" ..\n"
|
|
elseif v.background then
|
|
output = output .. "\"background["..get_rect(v)..form_esc(v.image)..";"..tostring(v.fill).."]\" ..\n"
|
|
else
|
|
output = output .. "\"image["..get_rect(v)..form_esc(v.image).."]\" ..\n"
|
|
end
|
|
|
|
elseif v.type == "Slider" then
|
|
orientation = "horizontal"
|
|
if v.vertical then
|
|
orientation = "vertical"
|
|
end
|
|
output = output .. "\"scrollbar["..get_rect(v)..orientation..";"..form_esc(v.name)..";"..v.value.."]\" ..\n"
|
|
|
|
elseif v.type == "InvList" then
|
|
local extras = {["player:"]=1, ["nodemeta:"]=1, ["detached:"]=1}
|
|
if extras[v.location] then
|
|
output = output .. "\"list["..v.location..form_esc(v.data)..";"..form_esc(v.name)..";"..get_rect(v)..v.start.."]\" ..\n"
|
|
if v.ring then
|
|
output = output .. "\"listring["..v.location..form_esc(v.data)..";"..form_esc(v.name).."]\" ..\n"
|
|
end
|
|
else
|
|
output = output .. "\"list["..v.location..";"..form_esc(v.name)..";"..get_rect(v)..v.start.."]\" ..\n"
|
|
if v.ring then
|
|
output = output .. "\"listring["..v.location..";"..form_esc(v.name).."]\" ..\n"
|
|
end
|
|
end
|
|
|
|
elseif v.type == "Table" then
|
|
local cell_str = ""
|
|
local column_str = ""
|
|
|
|
-- this converts the column's individual item lists into a string
|
|
local most_items = 0
|
|
for i, c in pairs(v.columns) do
|
|
if #c.items > most_items then
|
|
most_items = #c.items -- gets the largest size
|
|
end
|
|
|
|
if i > 1 then
|
|
column_str = column_str..";"
|
|
end
|
|
column_str = column_str .. c.type -- creates the column list
|
|
-- adds column parameters \/
|
|
if c.type == "image" then
|
|
for n, t in pairs(c.images) do
|
|
column_str = column_str..","..n .."="..t
|
|
end
|
|
elseif c.type == "color" and c.distance ~= "infinite" then
|
|
column_str = column_str..",span="..c.distance
|
|
end
|
|
end
|
|
for i=1, most_items do -- adds all the items together
|
|
for n, c in pairs(v.columns) do
|
|
if n > 1 or i > 1 then
|
|
cell_str = cell_str..","
|
|
end
|
|
local item = c.items[i]
|
|
if item == nil then -- columns with less items get blank items to make them the same length
|
|
item = ""
|
|
end
|
|
cell_str = cell_str..item
|
|
end
|
|
end
|
|
if column_str:len() > 0 then
|
|
output = output .. "\"tablecolumns["..column_str.."]\" ..\n"
|
|
end
|
|
output = output .. "\"table["..get_rect(v)..form_esc(v.name)..";"..cell_str..";]\" ..\n"
|
|
|
|
elseif v.type == "Tooltip" then
|
|
if v.colours then
|
|
output = output .. "\"tooltip["..form_esc(v.name)..";"..form_esc(v.text)..";"..form_esc(v.bg)..";"..form_esc(v.fg).."]\" ..\n"
|
|
else
|
|
output = output .. "\"tooltip["..form_esc(v.name)..";"..form_esc(v.text).."]\" ..\n"
|
|
end
|
|
|
|
|
|
elseif v.type == "Container - Start" then
|
|
local rect = get_rect(v, true)
|
|
fwidth[dep+1] = rect.width -- set the width and height that widgets in the container use
|
|
fheight[dep+1] = rect.height
|
|
dep = dep+1
|
|
output = output .. "\"container["..rect.left..","..rect.top.."]\" ..\n"
|
|
elseif v.type == "Container - End" then
|
|
dep = dep-1 -- close container
|
|
output = output .. "\"container_end[]\" ..\n"
|
|
|
|
elseif v.type == "Tabs" then
|
|
local capt_str = ""
|
|
for i, capt in pairs(v.captions) do
|
|
if i > 1 then capt_str = capt_str.."," end
|
|
capt_str = capt_str .. form_esc(capt)
|
|
end
|
|
output = output .. "\"tabheader["..get_rect(v)..form_esc(v.name)..";"..capt_str..";"..v.tab..";"..tostring(v.transparent)..";"..tostring(v.border).."]\" ..\n"
|
|
end
|
|
end
|
|
return output .. '""'
|
|
end
|
|
|
|
----------
|
|
-- UI Editors
|
|
----------
|
|
|
|
-- creates a position chooser with << and >> buttons, text box, and position type (if needed)
|
|
local function ui_position(name, value, left, top, typ, typ_id)
|
|
name = form_esc(name)
|
|
local form = ""..
|
|
"label["..left+0.1 ..","..top-0.3 ..";"..name.."]" ..
|
|
"button["..left+0.1 ..","..top..";1,1;"..name.."_size_down;<<]" ..
|
|
"field["..left+1.3 ..","..top+0.3 ..";1,1;"..name.."_size;;"..form_esc(value).."]" ..
|
|
"field_close_on_enter["..name.."_size;false]" ..
|
|
"button["..left+1.9 ..","..top..";1,1;"..name.."_size_up;>>]"
|
|
local typ_ids = {["L+"]=1, ["T+"]=1, ["R-"]=2, ["B-"]=2, ["W/"]=3, ["H/"]=3, ["R"]=4}
|
|
if typ == "LEFT" then -- left and right sides use this type
|
|
if name == "RIGHT" then -- but right has a relative option (I should make it right type, but I decided much later to include it)
|
|
form = form .."dropdown["..left+3 ..","..top+0.1 ..";1.1,1;"..name.."_type;LEFT +,RIGHT -,WIDTH /,RELATIVE;"..typ_ids[typ_id].."]"
|
|
else
|
|
form = form .. "dropdown["..left+3 ..","..top+0.1 ..";1.1,1;"..name.."_type;LEFT +,RIGHT -,WIDTH /;"..typ_ids[typ_id].."]"
|
|
end
|
|
elseif typ == "TOP" then
|
|
if name == "BOTTOM" then
|
|
form = form.."dropdown["..left+3 ..","..top+0.1 ..";1.1,1;"..name.."_type;TOP +,BOTTOM -,HEIGHT /,RELATIVE;"..typ_ids[typ_id].."]"
|
|
else
|
|
form = form .. "dropdown["..left+3 ..","..top+0.1 ..";1.1,1;"..name.."_type;TOP +,BOTTOM -,HEIGHT /;"..typ_ids[typ_id].."]"
|
|
end
|
|
end
|
|
return form
|
|
end
|
|
|
|
-- handles position ui functionality
|
|
local function handle_position_changes(id, fields, range)
|
|
local pos_names = {"width", "height", "left", "top", "right", "bottom", "value"} -- the only names it will check
|
|
for i, v in pairs(pos_names) do
|
|
if fields[string.upper(v).."_size_down"] then -- down button
|
|
if range and range[v] then
|
|
widgets[id][v] = widgets[id][v] - range[v]/10 -- slider uses a different step
|
|
else
|
|
widgets[id][v] = widgets[id][v] - 0.1
|
|
end
|
|
if widgets[id][v] < 0.0001 and widgets[id][v] > -0.0001 then widgets[id][v] = 0 end -- weird number behaviour
|
|
elseif fields[string.upper(v).."_size_up"] then -- up button
|
|
if range and range[v] then
|
|
widgets[id][v] = widgets[id][v] + range[v]/10
|
|
else
|
|
widgets[id][v] = widgets[id][v] + 0.1
|
|
end
|
|
if widgets[id][v] < 0.0001 and widgets[id][v] > -0.0001 then widgets[id][v] = 0 end -- weird number behaviour
|
|
elseif fields.key_enter_field == string.upper(v).."_size" then -- size edit box/displayer
|
|
local value = tonumber(fields[string.upper(v).."_size"])
|
|
if value ~= nil then
|
|
widgets[id][v] = value
|
|
end
|
|
elseif fields[string.upper(v).."_type"] then -- type selector
|
|
local typ_trans = {["LEFT +"]="L+", ["RIGHT -"]="R-", ["WIDTH /"]="W/", ["TOP +"]="T+", ["BOTTOM -"]="B-", ["HEIGHT /"]="H/", ["RELATIVE"]="R"}
|
|
widgets[id][v.."_type"] = typ_trans[fields[string.upper(v).."_type"]]
|
|
end
|
|
if range then -- sometimes the number must be within a range
|
|
if range[v] then
|
|
if widgets[id][v] < 0 then
|
|
widgets[id][v] = 0
|
|
elseif widgets[id][v] > range[v] then
|
|
widgets[id][v] = range[v]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- creates a field to edit name or other attributes, and a parameter checkbox (if needed)
|
|
local function ui_field(name, value, left, top, param)
|
|
name = form_esc(name)
|
|
local field = "" ..
|
|
"field["..left+0.2 ..","..top..";2.8,1;"..name.."_input_box;"..name..";"..form_esc(value).."]" ..
|
|
"field_close_on_enter["..name.."_input_box;false]"
|
|
if param ~= nil then
|
|
field = field .. "checkbox["..left+2.8 ..","..top-0.3 ..";"..name.."_param_box;parameter;"..tostring(param).."]"
|
|
end
|
|
return field
|
|
end
|
|
|
|
-- handles field functionality
|
|
local function handle_field_changes(names, id, fields)
|
|
for i, v in pairs(names) do -- names are supplied this time, so only nececary ones are checked
|
|
if fields.key_enter_field == string.upper(v).."_input_box" then
|
|
widgets[id][v] = fields[string.upper(v).."_input_box"]
|
|
elseif fields[string.upper(v).."_param_box"] then
|
|
widgets[id][v.."_param"] = fields[string.upper(v).."_param_box"] == "true"
|
|
end
|
|
end
|
|
end
|
|
|
|
----------
|
|
-- individual widget definitions
|
|
|
|
-- functions for widget's custom editing UIs at the side
|
|
local widget_editor_uis = {
|
|
Display = { -- type can be seen here, etc, extra tabs (options, new widget) are at the end
|
|
ui = function(id, left, top, width) -- function for creating the form
|
|
local form = "label["..left+1.7 ..","..top ..";- DISPLAY -]"
|
|
|
|
if not widgets[id].colour_tab then
|
|
form = form ..
|
|
"button["..left+width-3 ..","..top+6.7 ..";3.1,1;col_page;INVENTORY COLOURS >]" ..
|
|
ui_position("WIDTH", widgets[id].width, left, top+0.7) ..
|
|
ui_position("HEIGHT", widgets[id].height, left, top+1.7) ..
|
|
"checkbox["..left+3 ..","..top+0.7 ..";WIDTH_param_box;parameter;"..tostring(widgets[id].width_param).."]" ..
|
|
"checkbox["..left+3 ..","..top+1.7 ..";HEIGHT_param_box;parameter;"..tostring(widgets[id].height_param).."]"
|
|
|
|
if widgets[id].position then -- this part only gets displayed if the position checkbox is checked
|
|
form = form ..
|
|
ui_position("LEFT", widgets[id].left, left, top+2.7) ..
|
|
ui_position("TOP", widgets[id].top, left, top+3.7) ..
|
|
"checkbox["..left+0.1 ..","..top+4.3 ..";pos_box;position;true]" ..
|
|
"checkbox["..left+2 ..","..top+4.3 ..";back_box;background;"..tostring(widgets[id].background).."]"
|
|
if widgets[id].background then
|
|
form = form..
|
|
ui_field("COLOUR", widgets[id].colour, left+0.2, top+5.5) ..
|
|
"checkbox["..left+3 ..","..top+5.2 ..";full;fullscreen;"..tostring(widgets[id].fullscreen).."]"
|
|
end
|
|
else
|
|
form = form .. "checkbox["..left+0.1 ..","..top+2.3 ..";pos_box;position;false]" ..
|
|
"checkbox["..left+2 ..","..top+2.3 ..";back_box;background;"..tostring(widgets[id].background).."]"
|
|
if widgets[id].background then
|
|
form = form..
|
|
ui_field("COLOUR", widgets[id].colour, left+0.2, top+3.5) ..
|
|
"checkbox["..left+3 ..","..top+3.2 ..";full;fullscreen;"..tostring(widgets[id].fullscreen).."]"
|
|
end
|
|
end
|
|
else
|
|
form = form ..
|
|
"checkbox["..left+0.1 ..","..top+0.3 ..";do_col;COLOURS;"..tostring(widgets[id].col.col).."]" ..
|
|
"button["..left+width-1.2 ..","..top+6.7 ..";1.3,1;dat_page;BACK <]"
|
|
|
|
if widgets[id].col.col then
|
|
form = form ..
|
|
"field["..left+0.4 ..","..top+1.5 ..";2.8,1;bg_main;BACKGROUND;"..widgets[id].col.bg_normal.."]" ..
|
|
"field_close_on_enter[bg_main;false]" ..
|
|
"field["..left+0.4 ..","..top+2.5 ..";2.8,1;bg_hover;HOVER BACKGROUND;"..widgets[id].col.bg_hover.."]" ..
|
|
"field_close_on_enter[bg_hover;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+2.8 ..";do_border;BORDER;"..tostring(widgets[id].col.set_border).."]"
|
|
|
|
if widgets[id].col.set_border then
|
|
form = form ..
|
|
"field["..left+0.4 ..","..top+4 ..";2.8,1;border;BORDER;"..widgets[id].col.border.."]" ..
|
|
"field_close_on_enter[border;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+4.3 ..";do_tool;TOOLTIP;"..tostring(widgets[id].col.set_tool).."]"
|
|
if widgets[id].col.set_tool then
|
|
form = form ..
|
|
"field["..left+0.4 ..","..top+5.5 ..";2.8,1;bg_tool;BACKGROUND;"..widgets[id].col.tool_bg.."]" ..
|
|
"field_close_on_enter[bg_tool;false]" ..
|
|
"field["..left+0.4 ..","..top+6.5 ..";2.8,1;tool_text;TEXT;"..widgets[id].col.tool_font.."]" ..
|
|
"field_close_on_enter[tool_text;false]"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return form
|
|
end,
|
|
func = function(id, fields) -- function for handling the form
|
|
handle_position_changes(id, fields, {left=1, top=1})
|
|
handle_field_changes({"colour"}, id, fields)
|
|
if fields.WIDTH_param_box then
|
|
widgets[id].width_param = fields.WIDTH_param_box == "true"
|
|
elseif fields.HEIGHT_param_box then
|
|
widgets[id].height_param = fields.HEIGHT_param_box == "true"
|
|
|
|
elseif fields.pos_box then
|
|
widgets[id].position = fields.pos_box == "true"
|
|
elseif fields.back_box then
|
|
widgets[id].background = fields.back_box == "true"
|
|
elseif fields.full then
|
|
widgets[id].fullscreen = fields.full == "true"
|
|
|
|
elseif fields.col_page then -- colour tab
|
|
widgets[id].colour_tab = true
|
|
elseif fields.dat_page then
|
|
widgets[id].colour_tab = false
|
|
|
|
elseif fields.do_col then
|
|
widgets[id].col.col = fields.do_col == "true"
|
|
elseif fields.do_border then
|
|
widgets[id].col.set_border = fields.do_border == "true"
|
|
elseif fields.do_tool then
|
|
widgets[id].col.set_tool = fields.do_tool == "true"
|
|
|
|
elseif fields.key_enter_field == "bg_main" then
|
|
widgets[id].col.bg_normal = fields.bg_main
|
|
elseif fields.key_enter_field == "bg_hover" then
|
|
widgets[id].col.bg_hover = fields.bg_hover
|
|
elseif fields.key_enter_field == "border" then
|
|
widgets[id].col.border = fields.border
|
|
elseif fields.key_enter_field == "bg_tool" then
|
|
widgets[id].col.tool_bg = fields.bg_tool
|
|
elseif fields.key_enter_field == "tool_text" then
|
|
widgets[id].col.tool_font = fields.tool_text
|
|
end
|
|
|
|
reload_ui() -- refresh the display and save the file
|
|
end
|
|
},
|
|
|
|
Button = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- BUTTON -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+0.7) .. -- all have a name box
|
|
ui_position("LEFT", widgets[id].left, left, top+1.4, "LEFT", widgets[id].left_type) .. -- and an area or position
|
|
ui_position("TOP", widgets[id].top, left, top+2.4, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.4, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.4, "TOP", widgets[id].bottom_type) ..
|
|
ui_field("LABEL", widgets[id].label, left+0.2, top+5.7) .. -- then extra things
|
|
""
|
|
if widgets[id].image then
|
|
form = form ..
|
|
ui_field("TEXTURE", widgets[id].texture, left+0.2, top+6.7) ..
|
|
"checkbox["..left+3 ..","..top+6.4 ..";image_param_box;parameter;"..tostring(widgets[id].image_param).."]" ..
|
|
"checkbox["..left+1.8 ..","..top+7 ..";image_box;image;true]" ..
|
|
"checkbox["..left+0.1 ..","..top+7 ..";close_box;exit form;"..tostring(widgets[id].exit).."]"
|
|
if not widgets[id].exit then
|
|
form = form .. "checkbox["..left+3 ..","..top+7 ..";item_box;item;"..tostring(widgets[id].item).."]"
|
|
end
|
|
else
|
|
form = form .. "checkbox["..left+1.8 ..","..top+6 ..";image_box;image;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+6 ..";close_box;exit form;"..tostring(widgets[id].exit).."]"
|
|
end
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "label", "texture"}, id, fields)
|
|
if fields.image_box then
|
|
widgets[id].image = fields.image_box == "true"
|
|
|
|
elseif fields.image_param_box then
|
|
widgets[id].image_param = fields.image_param_box == "true"
|
|
|
|
elseif fields.item_box then
|
|
widgets[id].item = fields.item_box == "true"
|
|
|
|
elseif fields.close_box then
|
|
widgets[id].exit = fields.close_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Field = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- FIELD -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_field("LABEL", widgets[id].label, left+0.2, top+5) ..
|
|
""
|
|
if widgets[id].password then
|
|
form = form.."checkbox["..left+0.1 ..","..top+5.3 ..";password_box;password;true]" ..
|
|
"checkbox["..left+0.1 ..","..top+5.7 ..";enter_close_box;close form on enter;"..tostring(widgets[id].enter_close).."]"
|
|
else
|
|
form = form..
|
|
ui_field("DEFAULT", widgets[id].default, left+0.2, top+6, widgets[id].default_param) ..
|
|
"checkbox["..left+0.1 ..","..top+6.3 ..";password_box;password;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+6.7 ..";enter_close_box;close form on enter;"..tostring(widgets[id].enter_close).."]"
|
|
end
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "label", "default"}, id, fields)
|
|
if fields.password_box then
|
|
widgets[id].password = fields.password_box == "true"
|
|
|
|
elseif fields.enter_close_box then
|
|
widgets[id].enter_close = fields.enter_close_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
TextArea = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- TextArea -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.7, "TOP", widgets[id].bottom_type) ..
|
|
ui_field("LABEL", widgets[id].label, left+0.2, top+6) ..
|
|
ui_field("DEFAULT", widgets[id].default, left+0.2, top+7, widgets[id].default_param) ..
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "label", "default"}, id, fields)
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Label = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+2 ..","..top ..";- Label -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_field("LABEL", widgets[id].label, left+0.2, top+4, widgets[id].label_param) ..
|
|
"checkbox["..left+0.1 ..","..top+4.3 ..";vert_box;vertical;"..tostring(widgets[id].vertical).."]"
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "label"}, id, fields)
|
|
if fields.vert_box then
|
|
widgets[id].vertical = fields.vert_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
TextList = {
|
|
ui = function(id, left, top, width)
|
|
|
|
local item_str = ""
|
|
for i, v in pairs(widgets[id].items) do
|
|
item_str = item_str .. form_esc(v) .. ","
|
|
end
|
|
|
|
local form = "label["..left+1.8 ..","..top ..";- TextList -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.7, "TOP", widgets[id].bottom_type) ..
|
|
"label["..left+0.1 ..","..top+5.4 ..";ITEMS]" ..
|
|
"textlist["..left+0.1 ..","..top+5.75 ..";2.6,0.7;item_list;"..item_str.."]" ..
|
|
"field["..left+3.3 ..","..top+6 ..";1.8,1;item_input;;]" ..
|
|
"field_close_on_enter[item_input;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+6.3 ..";items_param_box;items parameter;"..tostring(widgets[id].items_param).."]" ..
|
|
"checkbox["..left+0.1 ..","..top+6.7 ..";item_id_param_box;selected item id parameter;"..tostring(widgets[id].item_id_param).."]" ..
|
|
"checkbox["..left+3 ..","..top+6.7 ..";transparent_box;transparent;"..tostring(widgets[id].transparent).."]" ..
|
|
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name"}, id, fields)
|
|
if fields.item_list then -- common (lazy) way I make editable lists
|
|
if string.sub(fields.item_list, 1, 3) == "DCL" then -- remove
|
|
table.remove(widgets[id].items, tonumber(string.sub(fields.item_list, 5)))
|
|
end
|
|
elseif fields.key_enter_field == "item_input" then -- add
|
|
table.insert(widgets[id].items, fields.item_input)
|
|
|
|
elseif fields.items_param_box then
|
|
widgets[id].items_param = fields.items_param_box == "true"
|
|
|
|
elseif fields.item_id_param_box then
|
|
widgets[id].item_id_param = fields.item_id_param_box == "true"
|
|
|
|
elseif fields.transparent_box then
|
|
widgets[id].transparent = fields.transparent_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
DropDown = {
|
|
ui = function(id, left, top, width)
|
|
|
|
local item_str = ""
|
|
for i, v in pairs(widgets[id].items) do
|
|
item_str = item_str .. form_esc(v) .. ","
|
|
end
|
|
|
|
local form = "label["..left+1.8 ..","..top ..";- DropDown -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
"label["..left+0.1 ..","..top+4.4 ..";ITEMS]" ..
|
|
"label["..left+1.8 ..","..top+4.4 ..";selected: "..widgets[id].select_id.."]" ..
|
|
"textlist["..left+0.1 ..","..top+4.75 ..";2.6,0.7;item_list;"..item_str.."]" ..
|
|
"field["..left+3.3 ..","..top+5 ..";1.8,1;item_input;;]" ..
|
|
"field_close_on_enter[item_input;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+5.3 ..";items_param_box;items parameter;"..tostring(widgets[id].items_param).."]" ..
|
|
"checkbox["..left+0.1 ..","..top+5.7 ..";item_id_param_box;selected item id parameter;"..tostring(widgets[id].item_id_param).."]" ..
|
|
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name"}, id, fields)
|
|
if fields.item_list then
|
|
if string.sub(fields.item_list, 1, 3) == "DCL" then
|
|
table.remove(widgets[id].items, tonumber(string.sub(fields.item_list, 5)))
|
|
else
|
|
widgets[id].select_id = tonumber(string.sub(fields.item_list, 5))
|
|
end
|
|
elseif fields.key_enter_field == "item_input" then
|
|
table.insert(widgets[id].items, fields.item_input)
|
|
|
|
elseif fields.items_param_box then
|
|
widgets[id].items_param = fields.items_param_box == "true"
|
|
|
|
elseif fields.item_id_param_box then
|
|
widgets[id].item_id_param = fields.item_id_param_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
CheckBox = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+2 ..","..top ..";- Label -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_field("LABEL", widgets[id].label, left+0.2, top+4) ..
|
|
"checkbox["..left+0.1 ..","..top+4.3 ..";checked_box;checked;"..tostring(widgets[id].checked).."]" ..
|
|
"checkbox["..left+0.1 ..","..top+4.7 ..";checked_param_box;checked parameter;"..tostring(widgets[id].checked_param).."]"
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "label"}, id, fields)
|
|
if fields.checked_box then
|
|
widgets[id].checked = fields.checked_box == "true"
|
|
|
|
elseif fields.checked_param_box then
|
|
widgets[id].checked_param = fields.checked_param_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Box = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- Box -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.7, "TOP", widgets[id].bottom_type) ..
|
|
ui_field("COLOUR", widgets[id].colour, left+0.2, top+6, widgets[id].colour_param) ..
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "colour"}, id, fields)
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Image = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- Image -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.7, "TOP", widgets[id].bottom_type) ..
|
|
ui_field("IMAGE", widgets[id].image, left+0.2, top+6, widgets[id].image_param) ..
|
|
"checkbox["..left+0.1 ..","..top+6.3 ..";item_box;item;"..tostring(widgets[id].item).."]" ..
|
|
""
|
|
|
|
if not widgets[id].item then
|
|
form = form .. "checkbox["..left+1.5 ..","..top+6.3 ..";back_box;background;"..tostring(widgets[id].background).."]"
|
|
if widgets[id].background then
|
|
form = form .. "checkbox["..left+1.5 ..","..top+6.7 ..";fill_box;fill;"..tostring(widgets[id].fill).."]"
|
|
end
|
|
end
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name", "image"}, id, fields)
|
|
if fields.item_box then
|
|
widgets[id].item = fields.item_box == "true"
|
|
elseif fields.back_box then
|
|
widgets[id].background = fields.back_box == "true"
|
|
elseif fields.fill_box then
|
|
widgets[id].fill = fields.fill_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Slider = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- Slider -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.7, "TOP", widgets[id].bottom_type) ..
|
|
ui_position("VALUE", widgets[id].value, left, top+5.7) ..
|
|
"checkbox["..left+3 ..","..top+5.7 ..";value_param_box;parameter;"..tostring(widgets[id].value_param).."]" ..
|
|
"dropdown["..left+0.1 ..","..top+6.7 ..";2,1;orientation;horizontal,vertical;"..(widgets[id].vertical and 2 or 1).."]" ..
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields, {value=1000})
|
|
handle_field_changes({"name"}, id, fields)
|
|
if fields.value_param_box then
|
|
widgets[id].value_param = fields.value_param_box == "true"
|
|
elseif fields.orientation then
|
|
local new = fields.orientation == "vertical"
|
|
if widgets[id].vertical ~= new then -- swaps the width and height to make it nicer to edit
|
|
widgets[id].vertical = new
|
|
widgets[id].right, widgets[id].bottom = widgets[id].bottom, widgets[id].right
|
|
end
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
InvList = {
|
|
ui = function(id, left, top, width)
|
|
local location_values = {context=1, current_player=2, ["player:"]=3, ["nodemeta:"]=4, ["detached:"]=5}
|
|
local form = "label["..left+1.4 ..","..top ..";- Inventory List -]" ..
|
|
ui_position("LEFT", widgets[id].left, left, top+0.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+1.7, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+2.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+3.7, "TOP", widgets[id].bottom_type) ..
|
|
"label["..left+0.1 ..","..top+4.4 ..";LOCATION]" ..
|
|
"dropdown["..left+0.1 ..","..top+4.75 ..";2.8;location_select;context,current_player,player:,nodemeta:,detached:;" .. location_values[widgets[id].location].."]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+6) ..
|
|
"field["..left+0.4 ..","..top+7 ..";1,1;start;START;"..widgets[id].start.."]" ..
|
|
"field_close_on_enter[start;false]" ..
|
|
"checkbox["..left+1.5 ..","..top+6.7 ..";start_box;param;"..tostring(widgets[id].start_param).."]" ..
|
|
"checkbox["..left+3 ..","..top+5.9 ..";ring_box;ring;"..tostring(widgets[id].ring).."]"
|
|
|
|
|
|
local extras = {["player:"]=1, ["nodemeta:"]=1, ["detached:"]=1} -- these locations need extra data
|
|
if extras[widgets[id].location] then
|
|
form = form .. "field["..left+3.3 ..","..top+5 ..";1.7,1;data;DATA;"..form_esc(widgets[id].data).."]" ..
|
|
"field_close_on_enter[data;false]" ..
|
|
"checkbox["..left+3 ..","..top+5.5 ..";data_box;data param;"..tostring(widgets[id].data_param).."]"
|
|
end
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name"}, id, fields)
|
|
if fields.ring_box then
|
|
widgets[id].ring= fields.ring_box == "true"
|
|
elseif fields.start_box then
|
|
widgets[id].start_param = fields.start_box == "true"
|
|
elseif fields.data_box then
|
|
widgets[id].data_param = fields.data_box == "true"
|
|
elseif fields.key_enter_field == "data" then
|
|
widgets[id].data = fields.data
|
|
elseif fields.key_enter_field == "start" then
|
|
widgets[id].start = tonumber(fields.start)
|
|
if widgets[id].start == nil then
|
|
widgets[id].start = 0
|
|
end
|
|
|
|
elseif fields.location_select then
|
|
widgets[id].location = fields.location_select
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Tooltip = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.7 ..","..top ..";- Tooltip -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_field("TEXT", widgets[id].text, left+0.2, top+2) ..
|
|
""
|
|
|
|
if widgets[id].colours then
|
|
form = form .. "field["..left+0.4 ..","..top+3 ..";2.8,1;bg;BACKGROUND;"..form_esc(widgets[id].bg).."]" ..
|
|
"field_close_on_enter[bg;false]" ..
|
|
"field["..left+0.4 ..","..top+4 ..";2.8,1;fg;TEXT COLOUR;"..form_esc(widgets[id].fg).."]" ..
|
|
"field_close_on_enter[fg;false]" ..
|
|
"checkbox["..left+0.12 ..","..top+4.4 ..";col_box;colours;true]"
|
|
else
|
|
form = form .. "checkbox["..left+0.12 ..","..top+2.4 ..";col_box;colours;false]"
|
|
end
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_field_changes({"name", "text"}, id, fields)
|
|
|
|
if fields.key_enter_field == "bg" then
|
|
widgets[id].bg = fields.bg
|
|
elseif fields.key_enter_field == "fg" then
|
|
widgets[id].fg = fields.fg
|
|
elseif fields.col_box then
|
|
widgets[id].colours = fields.col_box == "true"
|
|
end
|
|
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Table = {
|
|
ui = function(id, left, top, width)
|
|
local column_str = ""
|
|
for i, v in pairs(widgets[id].columns) do
|
|
column_str = column_str..","..i..": "..v.type
|
|
end
|
|
local form = "label["..left+1.8 ..","..top ..";- Table -]" ..
|
|
"textlist["..left+0.1 ..","..top+0.4 ..";2.5,1.5;column_select;#ffff00DATA,#ffff00- columns: "..column_str..";"..widgets[id].selected_column+2 ..";]" ..
|
|
"button["..left+2.7 ..","..top+0.3 ..";0.5,1;column_up;/\\\\]" ..
|
|
"button["..left+2.7 ..","..top+1.15 ..";0.5,1;column_down;\\\\/]" ..
|
|
"button["..left+3.1 ..","..top+0.3 ..";0.8,1;column_add;+]" ..
|
|
"button["..left+3.1 ..","..top+1.15 ..";0.8,1;column_remove;-]"
|
|
|
|
if widgets[id].selected_column == -1 then -- the data tab (size, name, etc)
|
|
form = form .. ui_field("NAME", widgets[id].name, left+0.2, top+2.5) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+3.2, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+4.2, "TOP", widgets[id].top_type) ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+5.2, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+6.2, "TOP", widgets[id].bottom_type) ..
|
|
"checkbox["..left+0.1 ..","..top+6.9 ..";select_param_box;selected item param;"..tostring(widgets[id].select_param).."]"
|
|
|
|
elseif widgets[id].selected_column > 0 then -- item controller
|
|
local c = widgets[id].columns[widgets[id].selected_column]
|
|
typ_convt = {text=1, image=2, color=3, indent=4, tree=5}
|
|
local items_str = ""
|
|
for i, v in pairs(c.items) do
|
|
items_str = items_str..i..": "..v..","
|
|
end
|
|
form = form .. "label["..left+0.1 ..","..top+1.9 ..";TYPE]" ..
|
|
"dropdown["..left+0.1 ..","..top+2.3 ..";2.7,1;column_type;text,image,color,indent,tree;"..typ_convt[c.type].."]" ..
|
|
"label["..left+0.1 ..","..top+2.9 ..";ITEMS]" ..
|
|
"textlist["..left+0.1 ..","..top+3.3 ..";2.5,1.5;item_lst;"..items_str..";".. c.selected_item..";]" ..
|
|
"button["..left+2.7 ..","..top+3.2 ..";0.5,1;item_up;/\\\\]" ..
|
|
"button["..left+2.7 ..","..top+4.05 ..";0.5,1;item_down;\\\\/]" ..
|
|
"button["..left+3.1 ..","..top+3.2 ..";0.8,1;item_add;+]" ..
|
|
"button["..left+3.1 ..","..top+4.05 ..";0.8,1;item_remove;-]" ..
|
|
"checkbox["..left+2.7 ..","..top+4.6 ..";item_param_box;items parameter;"..tostring(c.items_param).."]"
|
|
|
|
if #c.items > 0 then -- item editor
|
|
form = form .. "field["..left+0.4 ..","..top+5.4 ..";2.5,1;item_edit;ITEM;"..c.items[c.selected_item].."]" ..
|
|
"field_close_on_enter[item_edit;false]"
|
|
|
|
-- some column types need extra stuff
|
|
if c.type == "image" then -- image
|
|
local img_str = ""
|
|
for i, v in pairs(c.images) do
|
|
img_str = img_str..i ..": "..v..","
|
|
end
|
|
form = form .. "label["..left+0.1 ..","..top+5.8 ..";IMAGES]" ..
|
|
"textlist["..left+0.1 ..","..top+6.2 ..";2.5,1.4;image_lst;"..img_str.."]" ..
|
|
"field["..left+3 ..","..top+6.4 ..";2,1;image_add;;]" ..
|
|
"field_close_on_enter[image_add;false]"
|
|
elseif c.type == "color" then -- colour
|
|
form = form .. "field["..left+0.4 ..","..top+6.4 ..";2.5,1;colour_len;DISTANCE;"..c.distance.."]" ..
|
|
"field_close_on_enter[colour_len;false]"
|
|
end
|
|
end
|
|
end
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
-- basic stuff
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name"}, id, fields)
|
|
local number_usrs = {indent=1, tree=1, image=1}
|
|
local c = widgets[id].columns[widgets[id].selected_column]
|
|
|
|
-- column selector and editor
|
|
if fields.column_select then
|
|
widgets[id].selected_column = tonumber(string.sub(fields.column_select, 5))-2
|
|
elseif fields.column_add then -- column def
|
|
table.insert(widgets[id].columns, {type="text", items={}, images={}, selected_item=1, items_param=false, distance="infinite"})
|
|
widgets[id].selected_column = #widgets[id].columns
|
|
elseif fields.column_remove and widgets[id].selected_column > 0 then
|
|
table.remove(widgets[id].columns, widgets[id].selected_column)
|
|
widgets[id].selected_column = widgets[id].selected_column-1
|
|
elseif fields.column_down and widgets[id].selected_column < #widgets[id].columns and widgets[id].selected_column > 0 then
|
|
table.insert(widgets[id].columns, widgets[id].selected_column+1, table.remove(widgets[id].columns, widgets[id].selected_column))
|
|
widgets[id].selected_column = widgets[id].selected_column+1
|
|
elseif fields.column_up and widgets[id].selected_column > 1 then
|
|
table.insert(widgets[id].columns, widgets[id].selected_column-1, table.remove(widgets[id].columns, widgets[id].selected_column))
|
|
widgets[id].selected_column = widgets[id].selected_column-1
|
|
|
|
elseif fields.select_param_box then
|
|
widgets[id].select_param = fields.select_param_box == "true"
|
|
|
|
-- item editor
|
|
elseif fields.item_lst then
|
|
c.selected_item = tonumber(string.sub(fields.item_lst, 5))
|
|
if c.selected_item > #c.items then
|
|
c.selected_item = #c.items
|
|
end
|
|
elseif fields.item_add then
|
|
if number_usrs[c.type] then
|
|
table.insert(c.items, 0)
|
|
else
|
|
table.insert(c.items, "-")
|
|
end
|
|
c.selected_item = #c.items
|
|
elseif fields.item_remove then
|
|
table.remove(c.items, c.selected_item)
|
|
if c.selected_item > 1 then
|
|
c.selected_item = c.selected_item-1
|
|
end
|
|
elseif fields.item_down and c.selected_item < #c.items then
|
|
table.insert(c.items, c.selected_item+1, table.remove(c.items, c.selected_item))
|
|
c.selected_item = c.selected_item+1
|
|
elseif fields.item_up and c.selected_item > 1 then
|
|
table.insert(c.items, c.selected_item-1, table.remove(c.items, c.selected_item))
|
|
c.selected_item = c.selected_item-1
|
|
|
|
elseif fields.item_param_box then
|
|
c.items_param = fields.item_param_box == "true"
|
|
|
|
elseif fields.key_enter_field == "item_edit" then
|
|
c.items[c.selected_item] = fields.item_edit
|
|
if number_usrs[c.type] then
|
|
c.items[c.selected_item] = tonumber(fields.item_edit)
|
|
if c.items[c.selected_item] == nil then
|
|
c.items[c.selected_item] = 0
|
|
end
|
|
c.items[c.selected_item] = math.floor(c.items[c.selected_item])
|
|
end
|
|
|
|
-- extra things for column types
|
|
elseif fields.key_enter_field == "image_add" then
|
|
table.insert(c.images, fields.image_add)
|
|
elseif fields.image_lst and string.sub(fields.image_lst, 1, 3) == "DCL" then
|
|
table.remove(c.images, tonumber(string.sub(fields.image_lst, 5)))
|
|
|
|
elseif fields.colour_len then
|
|
c.distance = tonumber(fields.colour_len)
|
|
if c.distance == nil or c.distance <= 0 then
|
|
c.distance = "infinite"
|
|
else
|
|
c.distance = math.floor(c.distance)
|
|
end
|
|
|
|
elseif fields.column_type then
|
|
c.type = fields.column_type
|
|
if number_usrs[c.type] then
|
|
for i, v in pairs(c.items) do
|
|
c.items[i] = tonumber(v)
|
|
if c.items[i] == nil then
|
|
c.items[i] = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
["Container - Start"] = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- Container -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
"label["..left+3.8 ..","..top+1.4 ..";parameter]" ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
"checkbox["..left+4.2 ..","..top+1.7 ..";left_param_box;;"..tostring(widgets[id].left_param).."]" ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
"checkbox["..left+4.2 ..","..top+2.7 ..";top_param_box;;"..tostring(widgets[id].top_param).."]" ..
|
|
ui_position("RIGHT", widgets[id].right, left, top+3.7, "LEFT", widgets[id].right_type) ..
|
|
ui_position("BOTTOM", widgets[id].bottom, left, top+4.7, "TOP", widgets[id].bottom_type) ..
|
|
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name"}, id, fields)
|
|
|
|
if fields.left_param_box then
|
|
widgets[id].left_param = fields.left_param_box == "true"
|
|
|
|
elseif fields.top_param_box then
|
|
widgets[id].top_param = fields.top_param_box == "true"
|
|
end
|
|
|
|
reload_ui()
|
|
end,
|
|
del = function(id)
|
|
table.remove(widgets, id)
|
|
local depth = 0
|
|
while id <= #widgets and depth > -1 do -- find which container end belongs to this container and delete it too
|
|
if widgets[id].type == "Container - Start" then
|
|
depth = depth+1
|
|
elseif widgets[id].type == "Container - End" then
|
|
if depth == 0 then
|
|
table.remove(widgets, id)
|
|
end
|
|
depth = depth-1
|
|
end
|
|
id = id+1
|
|
end
|
|
end
|
|
},
|
|
|
|
["Container - End"] = {
|
|
ui = function(id, left, top, width)
|
|
local name = ""
|
|
local depth = 0
|
|
local pos = id-1
|
|
while pos > 0 and depth > -1 do -- find which container start belongs to this container and display it's name
|
|
if widgets[pos].type == "Container - Start" then
|
|
if depth == 0 then
|
|
name = widgets[pos].name
|
|
end
|
|
depth = depth-1
|
|
elseif widgets[pos].type == "Container - End" then
|
|
depth = depth+1
|
|
end
|
|
pos = pos-1
|
|
end
|
|
local form = "label["..left+0.1 ..","..top+1 ..";- End of Container \""..form_esc(name).."\" -]" ..
|
|
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
-- ehem?
|
|
end
|
|
},
|
|
|
|
Tabs = {
|
|
ui =function(id, left, top, width)
|
|
local item_str = ""
|
|
for i, v in pairs(widgets[id].captions) do
|
|
item_str = item_str .. form_esc(v) .. ","
|
|
end
|
|
|
|
local form = "label["..left+1.9 ..","..top ..";- Tabs -]" ..
|
|
ui_field("NAME", widgets[id].name, left+0.2, top+1) ..
|
|
ui_position("LEFT", widgets[id].left, left, top+1.7, "LEFT", widgets[id].left_type) ..
|
|
ui_position("TOP", widgets[id].top, left, top+2.7, "TOP", widgets[id].top_type) ..
|
|
"label["..left+0.1 ..","..top+3.4 ..";TABS]" ..
|
|
"label["..left+1.8 ..","..top+3.4 ..";selected: "..widgets[id].tab.."]" ..
|
|
"textlist["..left+0.1 ..","..top+3.75 ..";2.6,0.7;item_list;"..item_str.."]" ..
|
|
"field["..left+3.3 ..","..top+4 ..";1.8,1;item_input;;]" ..
|
|
"field_close_on_enter[item_input;false]" ..
|
|
"checkbox["..left+0.1 ..","..top+4.3 ..";transparent_box;transparent;"..tostring(widgets[id].transparent).."]" ..
|
|
"checkbox["..left+0.1 ..","..top+4.7 ..";border_box;border;"..tostring(widgets[id].border).."]" ..
|
|
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
handle_position_changes(id, fields)
|
|
handle_field_changes({"name"}, id, fields)
|
|
if fields.item_list then
|
|
if string.sub(fields.item_list, 1, 3) == "DCL" then
|
|
table.remove(widgets[id].captions, tonumber(string.sub(fields.item_list, 5)))
|
|
else
|
|
widgets[id].tab = tonumber(string.sub(fields.item_list, 5))
|
|
end
|
|
elseif fields.key_enter_field == "item_input" then
|
|
table.insert(widgets[id].captions, fields.item_input)
|
|
|
|
elseif fields.transparent_box then
|
|
widgets[id].transparent = fields.transparent_box == "true"
|
|
|
|
elseif fields.border_box then
|
|
widgets[id].border = fields.border_box == "true"
|
|
end
|
|
reload_ui()
|
|
end
|
|
},
|
|
|
|
Options = {
|
|
ui = function(id, left, top, width)
|
|
local form = "label["..left+1.8 ..","..top ..";- Options -]" ..
|
|
"button["..left+0.1 ..","..top+1 ..";2,1;func_create;generate function]" ..
|
|
"button["..left+2.1 ..","..top+1 ..";2,1;string_create;generate string]" ..
|
|
""
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
if fields.string_create then -- display the formspec to output the generated string (and generate it)
|
|
minetest.show_formspec("ui_editor:output",
|
|
"size[10,8]" ..
|
|
"textarea[1,1;9,7;_;Generated Code;"..form_esc(generate_string()).."]" ..
|
|
"button[8.8,0;1,1;back;back]")
|
|
elseif fields.func_create then -- display the (same) formspec to output the generated function (and generate it)
|
|
minetest.show_formspec("ui_editor:output",
|
|
"size[10,8]" ..
|
|
"textarea[1,1;9,7;_;Generated Code;"..form_esc(generate_function()).."]" ..
|
|
"button[8.8,0;1,1;back;back]")
|
|
end
|
|
end
|
|
},
|
|
|
|
New = {
|
|
ui = function(id, left, top, width)
|
|
local widg_str = "" -- convert the list of widget types to a string
|
|
for i, v in pairs(widg_list) do
|
|
widg_str = widg_str..v..","
|
|
end
|
|
local form = "label["..left+1.6 ..","..top ..";- NEW WIDGET -]" ..
|
|
"textlist["..left+0.1 ..","..top+0.4 ..";"..width-0.2 ..",6;new_widg_selector;"..widg_str.."]"
|
|
|
|
return form
|
|
end,
|
|
func = function(id, fields)
|
|
if fields.new_widg_selector then
|
|
if string.sub(fields.new_widg_selector, 1, 3) == "DCL" then
|
|
local name = widg_list[tonumber(string.sub(fields.new_widg_selector, 5))]
|
|
selected_widget = #widgets +1
|
|
|
|
-- widget defaults --
|
|
-- create widgets with the correct and default data
|
|
if name == "Button" then
|
|
table.insert(widgets, {type="Button", name="New Button", label="New", image=false, image_param=false, texture="default_cloud.png", item=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=1, bottom_type="R"})
|
|
|
|
elseif name == "Field" then
|
|
table.insert(widgets,
|
|
{type="Field", name="New Field", label="", default="", default_param=false, password=false, enter_close=true,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=1, bottom_type="R"})
|
|
|
|
elseif name == "TextArea" then
|
|
table.insert(widgets, {type="TextArea", name="New TextArea", label="", default="", default_param=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=2, bottom_type="T+"})
|
|
|
|
elseif name == "Label" then
|
|
table.insert(widgets, {type="Label", name="New Label", label="New Label", label_param=false, vertical=false,
|
|
left=1, left_type="L+", top=1, top_type="T+"})
|
|
|
|
elseif name == "TextList" then
|
|
table.insert(widgets,
|
|
{type="TextList", name="New TextList", items={}, items_param=false, item_id_param=false, transparent=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=2, bottom_type="T+"})
|
|
|
|
elseif name == "DropDown" then
|
|
table.insert(widgets,
|
|
{type="DropDown", name="New DropDown", items={}, items_param=false, item_id_param=false, select_id=1,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=1, bottom_type="R"})
|
|
|
|
elseif name == "CheckBox" then
|
|
table.insert(widgets, {type="CheckBox", name="New CheckBox", label="New CheckBox", checked=false, checked_param=false,
|
|
left=1, left_type="L+", top=1, top_type="T+"})
|
|
|
|
elseif name == "Box" then
|
|
table.insert(widgets, {type="Box", name="New Box", colour="#ffffff", colour_param=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=2, bottom_type="T+"})
|
|
|
|
elseif name == "Image" then
|
|
table.insert(widgets, {type="Image", name="New Image", image="default_cloud.png", image_param=false, item=false,
|
|
background=false, fill=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=2, bottom_type="T+"})
|
|
|
|
elseif name == "Slider" then
|
|
table.insert(widgets, {type="Slider", name="New Slider", vertical=false, value=0, value_param=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="R", bottom=0.3, bottom_type="R"})
|
|
|
|
elseif name == "Table" then
|
|
table.insert(widgets, {selected_column=-1, type="Table", name="New Table", selected_param=false, columns = {},
|
|
select_param=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=2, bottom_type="T+"})
|
|
|
|
elseif name == "InvList" then
|
|
table.insert(widgets, {type="InvList", name="main", location="current_player", start_param=false, data="",
|
|
data_param=false, ring=false, colour_tab=false, start=0,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=2, right_type="L+", bottom=2, bottom_type="T+"})
|
|
|
|
elseif name == "Tooltip" then
|
|
table.insert(widgets, {type="Tooltip", name="widget", text="New Tooltip", colours=false, bg="#00cc00", fg="#000000"})
|
|
|
|
elseif name == "Container" then
|
|
table.insert(widgets, {type="Container - Start", name="New container", left_param=false, top_param=false,
|
|
left=1, left_type="L+", top=1, top_type="T+", right=4, right_type="L+", bottom=4, bottom_type="T+"})
|
|
table.insert(widgets, {type="Container - End", name=""})
|
|
|
|
elseif name == "Tabs" then
|
|
table.insert(widgets, {type="Tabs", name="New Tabs", captions={}, tab=1, transparent=false, border=false,
|
|
left=0, left_type="L+", top=0, top_type="T+"})
|
|
end
|
|
|
|
new_widg_tab = false
|
|
reload_ui()
|
|
end
|
|
end
|
|
end
|
|
},
|
|
|
|
}
|
|
|
|
|
|
----------
|
|
-- GENERAL
|
|
----------
|
|
|
|
-- handles formspec input, or sends to correct places
|
|
minetest.register_on_formspec_input(function(formname, fields)
|
|
if formname == "ui_editor:main" then
|
|
if fields.widg_select then -- select a widget
|
|
selected_widget = tonumber(string.sub(fields.widg_select, 5))-4
|
|
new_widg_tab = false
|
|
minetest.show_formspec("ui_editor:main", main_ui_form())
|
|
|
|
elseif fields.widg_mov_up then -- move a widget up
|
|
if selected_widget > 2 then
|
|
if widgets[selected_widget].type == "Container - End" and widgets[selected_widget-1].type == "Container - Start" then
|
|
local pos = selected_widget-2 -- containers must always make sence. each start must have an end after it,
|
|
local count = 0 -- -- so they can't move past eachother in some cases
|
|
while pos > 0 do
|
|
if widgets[pos].type == "Container - End" then
|
|
count = count-1
|
|
elseif widgets[pos].type == "Container - Start" then
|
|
count = count+1
|
|
end
|
|
pos = pos-1
|
|
end
|
|
if count <= 0 then return true end
|
|
end
|
|
table.insert(widgets, selected_widget-1, table.remove(widgets, selected_widget)) -- move it
|
|
selected_widget = selected_widget-1
|
|
new_widg_tab = false
|
|
reload_ui()
|
|
end
|
|
|
|
elseif fields.widg_mov_dwn then --move a widget down
|
|
if selected_widget < #widgets and selected_widget > 1 then
|
|
if widgets[selected_widget].type == "Container - Start" and widgets[selected_widget+1].type == "Container - End" then
|
|
local pos = selected_widget+2 -- containers must have an end after them (and can't share an end)
|
|
local count = 0
|
|
while pos <= #widgets do
|
|
if widgets[pos].type == "Container - End" then
|
|
count = count+1
|
|
elseif widgets[pos].type == "Container - Start" then
|
|
count = count-1
|
|
end
|
|
pos = pos+1
|
|
end
|
|
if count <= 0 then return true end
|
|
end
|
|
table.insert(widgets, selected_widget+1, table.remove(widgets, selected_widget))
|
|
selected_widget = selected_widget+1
|
|
new_widg_tab = false
|
|
reload_ui()
|
|
end
|
|
|
|
elseif fields.widg_duplicate then -- duplicate a widget
|
|
table.insert(widgets, copy_table(widgets[selected_widget]))
|
|
new_widg_tab = false
|
|
reload_ui()
|
|
|
|
elseif fields.widg_new then -- switch to the NEW WIDGET tab
|
|
new_widg_tab = not new_widg_tab
|
|
reload_ui()
|
|
|
|
elseif fields.widg_delete then -- delete a widget
|
|
if widgets[selected_widget].type == "Container - Start" then
|
|
widget_editor_uis["Container - Start"].del(selected_widget)
|
|
else
|
|
table.remove(widgets, selected_widget)
|
|
end
|
|
selected_widget = selected_widget-1
|
|
new_widg_tab = false
|
|
reload_ui()
|
|
|
|
elseif fields.quit == nil then -- send update to widget editors
|
|
if selected_widget == -2 or new_widg_tab then
|
|
widget_editor_uis["New"].func(selected_widget, fields)
|
|
elseif selected_widget > 0 then
|
|
widget_editor_uis[widgets[selected_widget].type].func(selected_widget, fields)
|
|
new_widg_tab = false
|
|
elseif selected_widget == -3 then
|
|
widget_editor_uis["Options"].func(selected_widget, fields)
|
|
new_widg_tab = false
|
|
end
|
|
end
|
|
|
|
elseif formname == "ui_editor:output" then -- the display for outputting generated code
|
|
if fields.back then
|
|
reload_ui()
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- loads the correct widget editor
|
|
local function widget_editor(left, height)
|
|
local form = "box["..left+0.1 ..",2.2;4.8,"..height-2.3 ..";#000000]"
|
|
if selected_widget == -1 or selected_widget == 0 or (selected_widget > 1 and widgets[selected_widget] == nil) then
|
|
selected_widget = -2 -- blank items in the list can be used for adding new widgets
|
|
end
|
|
if selected_widget == -2 or new_widg_tab then -- the new widget tab can be displayed without moving the selection
|
|
form = form .. widget_editor_uis["New"].ui(selected_widget, left+0.1, 2.2, 4.8)
|
|
elseif selected_widget > 0 then -- load correct editor for current selected widget
|
|
form = form .. widget_editor_uis[widgets[selected_widget].type].ui(selected_widget, left+0.1, 2.2, 4.8)
|
|
elseif selected_widget == -3 then
|
|
form = form .. widget_editor_uis["Options"].ui(selected_widget, left+0.1, 2.2, 4.8)
|
|
end
|
|
return form
|
|
end
|
|
|
|
-- creates the widget selector
|
|
local function widget_chooser(left)
|
|
local widget_str = "OPTIONS,NEW WIDGET,,.....," -- options at the top of the list
|
|
local depth = 0
|
|
for i, v in pairs(widgets) do
|
|
if v.type == "Container - End" then -- the order of end and start are because they do not need indenting
|
|
depth = depth-1
|
|
end
|
|
widget_str = widget_str .. string.rep("- ", depth) .. form_esc(v.type .. ": " .. v.name) .. ","
|
|
if v.type == "Container - Start" then -- container contents gets indented
|
|
depth = depth+1
|
|
end
|
|
end
|
|
|
|
local form = ""..
|
|
|
|
"textlist["..left+0.1 ..",0.1;3.4,2;widg_select;"..widget_str..";"..selected_widget+4 .."]" ..
|
|
"button["..left+3.6 ..",0.1;0.5,1;widg_mov_up;"..form_esc("/\\").."]" ..
|
|
"button["..left+3.6 ..",1.2;0.5,1;widg_mov_dwn;"..form_esc("\\/").."]"
|
|
|
|
if selected_widget > 1 and selected_widget <= #widgets and widgets[selected_widget].type ~= "Container - End" then
|
|
form = form .. "button["..left+4 ..",0;1,1;widg_duplicate;DUPLICATE]" ..
|
|
"button["..left+4 ..",0.7;1,1;widg_delete;DELETE]" ..
|
|
"button["..left+4 ..",1.4;1,1;widg_new;NEW]"
|
|
end
|
|
|
|
return form
|
|
end
|
|
|
|
-- puts the whole formspec together
|
|
main_ui_form = function ()
|
|
local ui, width, height = generate_ui() -- the preview
|
|
|
|
local w_selector = widget_chooser(width-5) -- the widget selector
|
|
|
|
local w_editor = widget_editor(width-5, height) -- the widget editor
|
|
|
|
local form = "".. -- add everything together
|
|
"size["..width..","..height.."]" ..
|
|
"box["..width-5 ..",0;5,"..height..";#ffffff]" ..
|
|
ui .. w_selector .. w_editor .. create_tabs(2) -- add the global tabs
|
|
|
|
return form
|
|
end
|
|
|
|
|
|
---------- ----------
|
|
-- END FORM EDITOR --
|
|
---------- ----------
|
|
|
|
|
|
|
|
---------- ----------
|
|
-- PASTE FORMSPEC EDITOR HERE --
|
|
---------- ----------
|
|
|
|
|
|
|
|
|
|
----------
|
|
-- UI FUNCTIONALITY
|
|
----------
|
|
|
|
minetest.register_on_formspec_input(function(formname, fields)
|
|
-- FILE VIEWER
|
|
----------
|
|
if formname == "files:viewer" then
|
|
if fields.del_lua then
|
|
name = lua_files[selected_files[1] ]
|
|
table.remove(lua_files, selected_files[1])
|
|
files_str = ""
|
|
for i, v in pairs(lua_files) do
|
|
if v ~= "" then
|
|
files_str = files_str..v.."," -- remove the file from the list
|
|
end
|
|
end
|
|
|
|
if name == saved_file then -- clear the editing area if the file was loaded
|
|
saved_file = false
|
|
modstorage:set_string("_lua_saved", "")
|
|
save_lua("")
|
|
end
|
|
|
|
modstorage:set_string("_lua_files_list", files_str)
|
|
minetest.show_formspec("files:viewer", file_viewer())
|
|
|
|
elseif fields.del_ui then
|
|
name = ui_files[selected_files[2] ]
|
|
table.remove(ui_files, selected_files[2])
|
|
files_str = ""
|
|
for i, v in pairs(ui_files) do
|
|
if v ~= "" then
|
|
files_str = files_str..v.."," -- remove the file from the list
|
|
end
|
|
end
|
|
|
|
if name == current_ui_file then -- clear the editing area if the file was loaded
|
|
load_UI("new")
|
|
end
|
|
|
|
modstorage:set_string("_UI_files_list", files_str)
|
|
minetest.show_formspec("files:viewer", file_viewer())
|
|
|
|
elseif fields.lua_select then -- click on a file to select it, double click to open it
|
|
local index = tonumber(string.sub(fields.lua_select, 5))
|
|
if string.sub(fields.lua_select, 1, 3) == "DCL" then
|
|
saved_file = lua_files[index]
|
|
|
|
modstorage:set_string("_lua_saved", saved_file)
|
|
minetest.show_formspec("lua:editor", lua_editor())
|
|
else
|
|
selected_files[1] = index
|
|
minetest.show_formspec("files:viewer", file_viewer())
|
|
end
|
|
|
|
elseif fields.ui_select then -- click on a file to select it, double click to open it
|
|
local index = tonumber(string.sub(fields.ui_select, 5))
|
|
if string.sub(fields.ui_select, 1, 3) == "DCL" then
|
|
load_UI(ui_files[index])
|
|
reload_ui()
|
|
else
|
|
selected_files[2] = index
|
|
minetest.show_formspec("files:viewer", file_viewer())
|
|
end
|
|
|
|
elseif fields.key_enter_field == "new_lua" or fields.add_lua then
|
|
local exist = false
|
|
for i, v in pairs(lua_files) do
|
|
if v == fields.new_lua then
|
|
exist = true
|
|
selected_files[1] = i
|
|
end
|
|
end
|
|
if not exist then
|
|
table.insert(lua_files, fields.new_lua)
|
|
selected_files[1] = #lua_files
|
|
|
|
files_str = ""
|
|
for i, v in pairs(lua_files) do
|
|
if v ~= "" then
|
|
files_str = files_str..v..","
|
|
end
|
|
end
|
|
modstorage:set_string("_lua_files_list", files_str)
|
|
saved_file = fields.new_lua
|
|
minetest.show_formspec("lua:editor", lua_editor())
|
|
end
|
|
|
|
elseif fields.key_enter_field == "new_ui" or fields.add_ui then
|
|
local exist = false
|
|
for i, v in pairs(ui_files) do
|
|
if v == fields.new_ui then
|
|
exist = true
|
|
selected_files[2] = i
|
|
end
|
|
end
|
|
if not exist then
|
|
table.insert(ui_files, fields.new_ui)
|
|
selected_files[2] = #ui_files
|
|
|
|
files_str = ""
|
|
for i, v in pairs(ui_files) do
|
|
if v ~= "" then
|
|
files_str = files_str..v..","
|
|
end
|
|
end
|
|
modstorage:set_string("_UI_files_list", files_str)
|
|
load_UI(fields.new_ui)
|
|
reload_ui()
|
|
end
|
|
end
|
|
end
|
|
|
|
if fields._option_tabs_ then
|
|
if fields._option_tabs_ == "1" then
|
|
minetest.show_formspec("lua:editor", lua_editor())
|
|
elseif fields._option_tabs_ == "2" then
|
|
reload_ui()
|
|
elseif fields._option_tabs_ == "4" then
|
|
minetest.show_formspec("files:viewer", file_viewer())
|
|
elseif fields._option_tabs_ == "5" then
|
|
minetest.show_formspec("lua:startup", startup_form())
|
|
else
|
|
minetest.show_formspec("lua:unknown",
|
|
"size["..data.width..","..data.height.."]label[1,1;COMING SOON]"..create_tabs(fields._option_tabs_))
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
----------
|
|
-- REGISTER COMMAND
|
|
----------
|
|
core.register_chatcommand("dte", { -- register the chat command
|
|
description = core.gettext("open a lua IDE"),
|
|
func = function(parameter)
|
|
minetest.show_formspec("lua:editor", lua_editor())
|
|
end,
|
|
})
|