dragonfire-client-waspsaliva/clientmods/dte/init.lua

2917 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)
local _
_, 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,
})