v1.13.4 SmartLine Controller revised

This commit is contained in:
Joachim Stolberg 2018-09-08 18:17:43 +02:00
parent d764a5d4cc
commit 8300e7bde4
6 changed files with 119 additions and 221 deletions

@ -90,11 +90,11 @@ sl.icta_register_action("print", {
{
type = "label",
name = "lbl",
label = "Hint: Use a '*' character as reference to any\ncondition state",
label = "Use a '*' character as reference to any\ncondition state",
},
},
button = function(data, environ)
return 'print(...)'
return 'print("'..data.text:sub(1,12)..'")'
end,
code = function(data, environ)
local s1 = 'local text = string.gsub("'..(smartline.escape(data.text))..'", "*", env.result[#])'

@ -29,36 +29,36 @@ function smartline.balancer_condition(number1, number2, ratio1, ratio2, owner)
end
smartline.icta_register_condition("ratio", {
title = "Balancer ratio",
title = "balancer ratio",
formspec = {
{
type = "numbers",
name = "number1",
label = "Pusher1",
label = "Pusher1 number",
default = "",
},
{
type = "digits",
name = "ratio1",
label = "Ratio1",
label = "Ratio1 value",
default = "",
},
{
type = "numbers",
name = "number2",
label = "Pusher2",
label = "Pusher2 number",
default = "",
},
{
type = "digits",
name = "ratio2",
label = "Ratio1",
label = "Ratio1 value",
default = "",
},
{
type = "label",
name = "lbl",
label = "Hint: Pusher1:Pusher2 shall have a\nitem counter ratio of Ratio1:Ratio2.",
label = "Hint: Pusher1:Pusher2 shall have an\nitem counter ratio of Ratio1:Ratio2.",
},
},
-- Return two chunks of executable Lua code for the controller, according:
@ -68,17 +68,18 @@ smartline.icta_register_condition("ratio", {
return s:format(data.number1, data.number2, data.ratio1, data.ratio2, environ.owner), '~= nil'
end,
button = function(data, environ)
return "ratio("..(data.ratio1 or "???").."/"..(data.ratio2 or "???")..")"
return "ratio("..smartline.fmt_number(data.number1)..","..
smartline.fmt_number(data.number2)..","..data.ratio1..":"..data.ratio2..')'
end,
})
smartline.icta_register_action("balancer", {
title = "Balancer Control",
title = "balancer action",
formspec = {
{
type = "label",
name = "lbl",
label = "Hint: Stop one Pusher and start\nit again after 'after' seconds.",
label = "Hint: Action part of the balancer rule.",
},
},
button = function(data, environ)
@ -91,28 +92,29 @@ smartline.icta_register_action("balancer", {
})
smartline.icta_register_action("clearcounter", {
title = "Balancer clear counter",
title = "balancer clear counter",
formspec = {
{
type = "numbers",
name = "number1",
label = "Pusher1",
label = "Pusher1 number",
default = "",
},
{
type = "numbers",
name = "number2",
label = "Pusher2",
label = "Pusher2 number",
default = "",
},
{
type = "label",
name = "lbl",
label = "Hint: Clear both Pusher counters.",
label = "Hint: Clear both Pusher counters\ne.g. after controller start.",
},
},
button = function(data, environ)
return 'balancer()'
return 'clear cnt('..smartline.fmt_number(data.number1)..","..
smartline.fmt_number(data.number2)..')'
end,
code = function(data, environ)
local s = [[tubelib.send_message("%s", "%s", nil, "clear_counter", nil)

@ -26,6 +26,14 @@ function sl.operand(s)
end
end
function sl.fmt_number(num)
local mtch = num:match('^(%d+).*')
if mtch and num ~= mtch then
return mtch.."..."
end
return num
end
-- '#' is used as placeholder for rule numbers and has to be escaped
function smartline.escape(s)
s = tostring(s)
@ -33,13 +41,13 @@ function smartline.escape(s)
end
smartline.icta_register_condition("once", {
title = "once",
smartline.icta_register_condition("initial", {
title = "initial",
formspec = {
{
type = "label",
name = "lbl",
label = "Hint: Once after start.",
label = "Condition is true only after\ncontroller start.",
},
},
-- Return two chunks of executable Lua code for the controller, according:
@ -47,7 +55,7 @@ smartline.icta_register_condition("once", {
code = function(data, environ)
return 'env.ticks', '== 1'
end,
button = function(data, environ) return "once" end,
button = function(data, environ) return "Initial after start" end,
})
smartline.icta_register_condition("true", {
@ -56,7 +64,7 @@ smartline.icta_register_condition("true", {
{
type = "label",
name = "lbl",
label = "Hint: Condition is always true.",
label = "Condition is always true.",
},
},
code = function(data, environ)
@ -66,25 +74,26 @@ smartline.icta_register_condition("true", {
})
smartline.icta_register_condition("condition", {
title = "Condition",
title = "condition",
formspec = {
{
type = "textlist",
name = "condition",
label = "the action is executed, if",
choices = "condition 1,condition 2,condition 3,condition 4,condition 5,condition 6,condition 7,condition 8",
label = "condition row number",
choices = "1,2,3,4,5,6,7,8",
default = "",
},
{
type = "textlist",
name = "operand",
label = "condition",
choices = "was true, was not true",
default = "was true",
},
{
type = "label",
name = "lbl",
label = "Hint: Execute two or several actions\nbased on one condition.",
label = "Used to execute two or several\nactions based on one condition.",
},
},
code = function(data, environ)
@ -95,7 +104,7 @@ smartline.icta_register_condition("condition", {
end
return "env.condition["..idx.."]", expected_result
end,
button = function(data, environ) return data.condition or "???" end,
button = function(data, environ) return "cond("..data.condition:sub(-1,-1)..","..data.operand..")" end,
})
smartline.icta_register_condition("input", {
@ -104,7 +113,7 @@ smartline.icta_register_condition("input", {
{
type = "digits",
name = "number",
label = "input from node with number",
label = "node number",
default = "",
},
{
@ -122,11 +131,11 @@ smartline.icta_register_condition("input", {
{
type = "label",
name = "lbl",
label = "Hint: An input is only available,\nif a nodes sends on/of\ncommands to the controller.",
label = "An input is only available,\nif a nodes sends on/off\ncommands to the controller.",
},
},
button = function(data, environ) -- default button label
return 'input('..(data.number or "???")..')'
return 'inp('..sl.fmt_number(data.number)..','..data.operand.." "..data.value..')'
end,
code = function(data, environ)
return 'env.input["'..data.number..'"]',
@ -140,7 +149,7 @@ smartline.icta_register_condition("state", {
{
type = "digits",
name = "number",
label = "state from node with number",
label = "node number",
default = "",
},
{
@ -160,11 +169,12 @@ smartline.icta_register_condition("state", {
{
type = "label",
name = "lbl",
label = "Hint: Read the state from another node.\nWorks for Pusher, Harvester, Quarry,\nand others.",
label = "Read the state from a node.\nWorks for Pusher, Harvester, Quarry,\n"..
"and other similar nodes.",
},
},
button = function(data, environ) -- default button label
return 'state('..(data.number or "???")..')'
return 'sts('..sl.fmt_number(data.number)..","..data.operand..' '..data.value..')'
end,
code = function(data, environ)
return 'tubelib.send_request("'..data.number..'", "state", "")',
@ -178,7 +188,7 @@ smartline.icta_register_condition("fuel", {
{
type = "digits",
name = "number",
label = "fuel state from node with number",
label = "node number",
default = "",
},
{
@ -198,11 +208,12 @@ smartline.icta_register_condition("fuel", {
{
type = "label",
name = "lbl",
label = "Hint: Read the fuel state from another node.\nWorks for Harvester and Quarry",
label = "Read the fuel state from a node.\nWorks for Harvester, Quarry,\n"..
"and other fuel consuming nodes.",
},
},
button = function(data, environ)
return 'fuel('..(data.number or "???")..')'
return 'fuel('..sl.fmt_number(data.number)..","..data.operand..' '..data.value..')'
end,
code = function(data, environ)
return 'tubelib.send_request("'..data.number..'", "fuel", "")',
@ -216,31 +227,29 @@ smartline.icta_register_condition("signaltower", {
{
type = "digits",
name = "number",
label = "state from Signal Tower with number",
label = "Signal Tower number",
default = "",
},
{
type = "textlist",
name = "operand",
label = "",
choices = "is,is not",
default = "is",
},
{
type = "textlist",
name = "value",
label = "",
choices = "off,green,amber,red",
default = "off",
},
{
type = "label",
name = "lbl",
label = "Hint: Read the state from a Signal Tower.",
label = "Read the color state\nfrom a Signal Tower.",
},
},
button = function(data, environ) -- default button label
return 'tower('..(data.number or "???")..')'
return 'tower('..sl.fmt_number(data.number)..","..data.operand..' '..data.value..')'
end,
code = function(data, environ)
return 'tubelib.send_request("'..data.number..'", "state", "")',
@ -254,24 +263,24 @@ smartline.icta_register_action("signaltower", {
{
type = "numbers",
name = "number",
label = "set Signal Tower with number",
label = "Signal Tower number",
default = "",
},
{
type = "textlist",
name = "value",
label = "to color",
label = "lamp color",
choices = "off,green,amber,red",
default = "red",
},
{
type = "label",
name = "lbl",
label = "Hint: Turn on a lamp from a Signal Tower.",
label = "Turn on/off a Signal Tower lamp.",
},
},
button = function(data, environ)
return 'tower('..(data.value or "???")..')'
return 'tower('..sl.fmt_number(data.number)..","..data.value..')'
end,
code = function(data, environ)
local s = 'tubelib.send_message("%s", "%s", nil, "%s", nil)'
@ -280,29 +289,29 @@ smartline.icta_register_action("signaltower", {
})
smartline.icta_register_action("switch", {
title = "node on/off command",
title = "turn node on/off",
formspec = {
{
type = "numbers",
name = "number",
label = "set node with number",
label = "node number(s)",
default = "",
},
{
type = "textlist",
name = "value",
label = "to state",
label = "state",
choices = "on,off",
default = "on",
},
{
type = "label",
name = "lbl",
label = "Hint: Used for pushers, lamps, machines, gates,...",
label = "Used for pushers, lamps, machines, gates,...",
},
},
button = function(data, environ)
return 'turn('..(data.value or "???")..')'
return 'turn('..sl.fmt_number(data.number)..","..data.value..')'
end,
code = function(data, environ)
local s = 'tubelib.send_message("%s", "%s", nil, "%s", nil)'
@ -316,7 +325,7 @@ smartline.icta_register_action("display", {
{
type = "numbers",
name = "number",
label = "output to Display with number",
label = "Display number",
default = "",
},
{
@ -329,13 +338,13 @@ smartline.icta_register_action("display", {
{
type = "ascii",
name = "text",
label = "the following text",
label = "text",
default = "",
},
{
type = "label",
name = "lbl",
label = "Hint: Use a '*' character as reference to any\ncondition state",
label = "Use a '*' character as reference\nto any condition result",
},
},
code = function(data, environ)
@ -345,7 +354,7 @@ smartline.icta_register_action("display", {
return s1.."\n\t"..s2.."\n\t"..s3
end,
button = function(data, environ)
return "display("..(data.number or "???")..")"
return "lcd("..sl.fmt_number(data.number)..","..data.row..',"'..data.text..'")'
end,
})
@ -363,7 +372,7 @@ smartline.icta_register_action("cleardisplay", {
return 'tubelib.send_message("'..data.number..'", "'..environ.owner..'", nil, "clear", nil)'
end,
button = function(data, environ)
return "clear("..(data.number or "???")..")"
return "clear lcd("..sl.fmt_number(data.number)..")"
end,
})
@ -373,20 +382,20 @@ smartline.icta_register_action("chat", {
{
type = "ascii",
name = "text",
label = "send the message",
label = "message",
default = "",
},
{
type = "label",
name = "lbl",
label = "Hint: The chat message is send to the\nController owner, only.",
label = "The chat message is send to the\nController owner, only.",
},
},
code = function(data, environ)
return 'minetest.chat_send_player("'..environ.owner..'", "[SmartLine Controller] '..data.text..'")'
end,
button = function(data, environ)
return "chat(...)"
return 'chat("'..data.text:sub(1,12)..'")'
end,
})
@ -420,56 +429,52 @@ smartline.icta_register_action("door", {
{
type = "textlist",
name = "door_state",
label = "set",
label = "door state",
choices = "open,close",
default = "open",
},
{
type = "label",
name = "lbl1",
label = "For standard doors like the Steel Doors.",
},
{
type = "label",
name = "lbl2",
label = "Hint: Use the Tubelib Programmer to\ndetermine the door position.",
name = "lbl",
label = "For standard doors like the Steel Doors.\n"..
"Use the Tubelib Programmer to\neasily determine a door position.",
},
},
code = function(data, environ)
return 'smartline.icta_door_toggle("'..data.pos..'", "'..environ.owner..'", "'..data.door_state..'")'
end,
button = function(data, environ)
return "door("..(data.door_state or "???")..")"
return 'door("'..data.pos..'",'..data.door_state..")"
end,
})
function smartline.icta_player_detect(number, name)
local state = tubelib.send_request(number, "name", nil)
if (name == "*" and state ~= "") or state == name then
if (name == "*" and state ~= "") or string.find(name, state) then
return state
end
return nil
end
smartline.icta_register_condition("playerdetector", {
title = "Player Detector: name request",
title = "Player Detector name request",
formspec = {
{
type = "digits",
name = "number",
label = "name from player detector with number",
label = "Player Detector number",
default = "",
},
{
type = "ascii",
name = "name",
label = "is",
label = "player name(s) or * for all",
default = "",
},
{
type = "label",
name = "lbl",
label = "Hint: Read and check the name\nfrom a Player Detector.\n Use a '*' character for all player names.",
label = "Read and check the name\nfrom a Player Detector.\n Use a '*' character for all player names.",
},
},
@ -477,6 +482,6 @@ smartline.icta_register_condition("playerdetector", {
return 'smartline.icta_player_detect("'..data.number..'", "'..data.name..'")', "~= nil"
end,
button = function(data, environ)
return "detector()"
return "detector("..sl.fmt_number(data.number)..","..data.name:sub(1,8)..")"
end,
})

@ -44,10 +44,12 @@ local Cache = {}
local FS_DATA = gen_table(smartline.NUM_RULES, {})
local function output(pos, text)
local function output(pos, text, flush_buffer)
local meta = minetest.get_meta(pos)
if not flush_buffer then
text = meta:get_string("output") .. "\n" .. (text or "")
text = text:sub(-500,-1)
end
meta:set_string("output", text)
meta:set_string("formspec", smartline.formspecOutput(meta))
end
@ -336,6 +338,10 @@ local function on_receive_fields(pos, formname, fields, player)
elseif fields.clear then
meta:set_string("output", "<press update>")
meta:set_string("formspec", smartline.formspecOutput(meta))
elseif fields.list then
local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA
local s = smartline.listing(fs_data)
output(pos, s, true)
elseif fields.tab == "1" then
local fs_data = minetest.deserialize(meta:get_string("fs_data")) or FS_DATA
meta:set_string("formspec", smartline.formspecRules(meta, fs_data, sOUTPUT))

@ -38,12 +38,12 @@ Actions are:
The controller executes all rules cyclically.
The cycle time for each rule is configurable
(1..1000 sec).
0 means, the rule will only be called, when
0 means, the rule will only be called, if
the controller received a command from
another node, like buttons.
another node, such as buttons.
Actions can be deleyed. Therefore, the
after value can be set (0..1000 sec).
Actions can be delayed. Therefore, the
'after' value can be set (0..1000 sec).
Edit command examples:
- 'x 1 8' exchange rows 1 with row 8
@ -97,17 +97,27 @@ local function button(data)
end
end
function smartline.listing(fs_data)
local tbl = {}
for idx = 1,smartline.NUM_RULES do
tbl[#tbl+1] = idx.." ("..fs_data[idx].cycle.."s): IF "..button(fs_data[idx].cond)
tbl[#tbl+1] = " THEN "..button(fs_data[idx].actn).." after "..fs_data[idx].after.."s\n"
end
return table.concat(tbl)
end
local function formspec_rules(fs_data)
local tbl = {"field[0,0;0,0;_type_;;main]"..
"label[0.8,0;Cycle/s:]label[2.8,0;IF cond:]label[7,0;THEN action:]label[11.4,0;after/s:]"}
"label[0.4,0;Cycle/s:]label[2.5,0;IF cond:]label[7,0;THEN action:]label[11.5,0;after/s:]"}
for idx = 1,smartline.NUM_RULES do
local ypos = idx * 0.75 - 0.4
tbl[#tbl+1] = "label[0,"..(0.2+ypos)..";"..idx.."]"
tbl[#tbl+1] = "field[0.9,"..(0.3+ypos)..";1.8,1;cycle"..idx..";;"..(fs_data[idx].cycle or "").."]"
tbl[#tbl+1] = "button[2.5,"..ypos..";4.3,1;cond"..idx..";"..button(fs_data[idx].cond).."]"
tbl[#tbl+1] = "button[6.8,"..ypos..";4.3,1;actn"..idx..";"..button(fs_data[idx].actn).."]"
tbl[#tbl+1] = "field[11.4,"..(0.3+ypos)..";1.8,1;after"..idx..";;"..(fs_data[idx].after or "").."]"
tbl[#tbl+1] = "field[0.7,"..(0.3+ypos)..";1.4,1;cycle"..idx..";;"..(fs_data[idx].cycle or "").."]"
tbl[#tbl+1] = "button[1.9,"..ypos..";4.9,1;cond"..idx..";"..minetest.formspec_escape(button(fs_data[idx].cond)).."]"
tbl[#tbl+1] = "button[6.8,"..ypos..";4.9,1;actn"..idx..";"..minetest.formspec_escape(button(fs_data[idx].actn)).."]"
tbl[#tbl+1] = "field[12,"..(0.3+ypos)..";1.4,1;after"..idx..";;"..(fs_data[idx].after or "").."]"
end
return table.concat(tbl)
end
@ -198,6 +208,7 @@ function smartline.formspecOutput(meta)
default.gui_slots..
"tabheader[0,0;tab;rules,outp,notes,help;2;;true]"..
"textarea[0.3,0.2;13,8.3;output;Output:;"..output.."]"..
"button[5.5,7.5;1.8,1;list;List]"..
"button[7.4,7.5;1.8,1;clear;Clear]"..
"button[9.3,7.5;1.8,1;update;Update]"..
"button[11.2,7.5;1.8,1;"..cmnd.."]"
@ -229,132 +240,3 @@ function smartline.formspecHelp(offs)
--"label[0.2,0;test]"..
"scrollbar[12,1;0.5,7;vertical;sb_help;"..offs.."]"
end
--local function my_on_receive_fields(pos, formname, fields, player)
-- local meta = minetest.get_meta(pos)
-- local owner = meta:get_string("owner")
-- local state = meta:get_int("state")
-- if not player or not player:is_player() then
-- return
-- end
-- local fs_data = minetest.deserialize(meta:get_string("fs_data")) or {}
-- local output = ""
-- local readonly = player:get_player_name() ~= owner
-- print("fields", dump(fields))
-- -- FIRST: test if command entered?
-- if fields.ok then
-- if not readonly then
-- output = edit_command(fs_data, fields.cmnd)
-- smartline.stop_controller(pos, fs_data)
-- meta:set_string("formspec", formspec_main(tubelib.STOPPED, fs_data, output))
-- meta:set_string("fs_data", minetest.serialize(fs_data))
-- end
-- -- SECOND: eval none edit events (events based in __type__)?
-- elseif fields.help then
-- meta:set_string("formspec", formspec_help(1))
---- elseif fields.state then
---- meta:set_string("formspec", formspec_state(meta, fs_data))
---- elseif fields.update then
---- meta:set_string("formspec", formspec_state(meta, fs_data))
-- elseif fields._cancel_ then
-- fs_data = minetest.deserialize(meta:get_string("fs_old"))
-- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
-- elseif fields.close then
-- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
---- elseif fields.sb_help then
---- local evt = minetest.explode_scrollbar_event(fields.sb_help)
---- if evt.type == "CHG" then
---- meta:set_string("formspec", formspec_help(evt.value))
---- end
---- elseif fields.button then
---- if not readonly then
---- local number = meta:get_string("number")
---- local state = meta:get_int("state")
---- if state == tubelib.RUNNING then
---- smartline.stop_controller(pos, fs_data)
---- meta:set_string("formspec", formspec_main(tubelib.STOPPED, fs_data, sOUTPUT))
---- else
---- formspec2runtime_rule(number, owner, fs_data)
---- start_controller(pos, number, fs_data)
---- meta:set_string("formspec", formspec_main(tubelib.RUNNING, fs_data, sOUTPUT))
---- end
---- end
---- -- THIRD: evaluate edit events from sub-menus
-- elseif fields._col_ == "cond" then
-- local row = tonumber(fields._row_ or 1)
-- fs_data["cond"..row] = smartline.cond_eval_input(fs_data["cond"..row], fields)
-- meta:set_string("formspec", smartline.cond_formspec(row, fs_data["cond"..row]))
-- meta:set_string("fs_data", minetest.serialize(fs_data))
-- elseif fields._type_ == "main" then
-- fs_data = eval_formspec_main(meta, fs_data, fields, readonly)
-- meta:set_string("fs_data", minetest.serialize(fs_data))
---- elseif fields._type_ == "label" then
---- fs_data = eval_formspec_label(meta, fs_data, fields, readonly)
---- meta:set_string("fs_data", minetest.serialize(fs_data))
---- elseif fields._type_ == "cond" then
---- fs_data = eval_formspec_cond(meta, fs_data, fields, readonly)
---- meta:set_string("fs_data", minetest.serialize(fs_data))
---- elseif fields._type_ == "oprnd" then
---- fs_data = eval_formspec_oprnd(meta, fs_data, fields, readonly)
---- meta:set_string("fs_data", minetest.serialize(fs_data))
---- elseif fields._type_ == "actn" then
---- fs_data = eval_formspec_actn(meta, fs_data, fields, readonly)
---- meta:set_string("fs_data", minetest.serialize(fs_data))
---- elseif fields._type_ == "help" then
---- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
---- elseif fields._type_ == "state" then
---- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
-- end
-- -- FOURTH: back to main menu
-- if fields._exit_ then
-- meta:set_string("formspec", formspec_main(state, fs_data, sOUTPUT))
-- end
--end
--function smartline.on_receive_fields(pos, formname, fields, player)
-- local meta = minetest.get_meta(pos)
-- local owner = meta:get_string("owner")
-- if not player or not player:is_player() then
-- return
-- end
-- local readonly = player:get_player_name() ~= owner
-- print("fields", dump(fields))
-- if fields.cancel == nil then
-- if fields.rules then
-- --meta:set_string("rules", fields.rules)
-- meta:set_string("formspec", smartline.formspecRules(meta))
-- elseif fields.notes then
-- meta:set_string("notes", fields.notes)
-- meta:set_string("formspec", formspecNotes(meta))
-- end
-- end
-- if fields.update then
-- meta:set_string("formspec", formspecOutput(meta))
-- elseif fields.clear then
-- meta:set_string("output", "<press update>")
-- meta:set_string("formspec", formspecOutput(meta))
-- elseif fields.tab == "1" then
-- meta:set_string("formspec", smartline.formspecRules(meta))
-- elseif fields.tab == "2" then
-- meta:set_string("formspec", formspecOutput(meta))
-- elseif fields.tab == "3" then
-- meta:set_string("formspec", formspecNotes(meta))
-- elseif fields.tab == "4" then
-- meta:set_string("formspec", formspecHelp(1))
-- elseif fields.start == "Start" then
-- start_controller(pos)
-- minetest.log("action", player:get_player_name() ..
-- " starts the sl_controller at ".. minetest.pos_to_string(pos))
-- elseif fields.stop == "Stop" then
-- stop_controller(pos)
-- end
--end

@ -31,20 +31,23 @@ local function add_controls_to_table(tbl, kvDefinition, kvSelect)
if kvDefinition[kvSelect.choice] then
local lControls = kvDefinition[kvSelect.choice].formspec
for idx,elem in ipairs(lControls) do
if elem.label and elem.label ~= "" then
tbl[#tbl+1] = "label[0,"..offs..";"..elem.label.."]"
if elem.type == "label" then
tbl[#tbl+1] = "label[0,"..offs..";Description:\n"..elem.label.."]"
offs = offs + 0.4
elseif elem.label and elem.label ~= "" then
tbl[#tbl+1] = "label[0,"..offs..";"..elem.label..":]"
offs = offs + 0.4
end
if elem.type == "numbers" or elem.type == "digits" or elem.type == "letters"
or elem.type == "ascii" then
val = kvSelect[elem.name] or elem.default
tbl[#tbl+1] = "field[0.3,"..(offs+0.2)..";8,1;"..elem.name..";;"..val.."]"
offs = offs + 1
offs = offs + 0.9
elseif elem.type == "textlist" then
local l = elem.choices:split(",")
val = index(l, kvSelect[elem.name]) or elem.default
tbl[#tbl+1] = "dropdown[0.0,"..(offs)..";8.5,1.4;"..elem.name..";"..elem.choices..";"..val.."]"
offs = offs + 1
offs = offs + 0.9
end
end
end
@ -161,9 +164,9 @@ function smartline.submenu_generate_formspec(row, col, title, lKeys, lChoice, kv
kvSelect = {choice = "default"}
end
local tbl = {"size[8.2,9]"..
--default.gui_bg.. TODO
--default.gui_bg_img..
--default.gui_slots..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"field[0,0;0,0;_row_;;"..row.."]"..
"field[0,0;0,0;_col_;;"..col.."]"}
@ -172,7 +175,7 @@ function smartline.submenu_generate_formspec(row, col, title, lKeys, lChoice, kv
tbl[#tbl+1] = "label[0,0;"..title..":]"
tbl[#tbl+1] = "dropdown[0,0.5;8.5,1;choice;"..sChoice..";"..idx.."]"
tbl = add_controls_to_table(tbl, kvDefinition, kvSelect)
tbl[#tbl+1] = "field[0.2,8.7;4,1;_button_;Button text;"..(kvSelect._button_ or "").."]"
tbl[#tbl+1] = "field[0.2,8.7;4,1;_button_;Alternative button text;"..(kvSelect._button_ or "").."]"
tbl[#tbl+1] = "button[4,8.4;2,1;_cancel_;cancel]"
tbl[#tbl+1] = "button[6,8.4;2,1;_exit_;ok]"
return table.concat(tbl)