--[[ SmartLine ========= Part of the SmartLine mod Copyright (C) 2017-2020 Joachim Stolberg AGPL v3 See LICENSE.txt for more information formspec.lua: controller formspecs ]]-- smartline.NUM_RULES = 8 local SIZE = "size[13,8]" local sHELP = [[SmartLine Controller Help Control other nodes by means of rules like: IF THEN These rules allow to execute actions based on conditions. Examples for conditions are: - the Player Detector detects a player - a button is pressed - a node state is fault, blocked, standby,... Actions are: - switch on/off tubelib nodes, like lamps, machines - send chat messages to the owner - output a text message to the display 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, if the controller received a command from another node, such as buttons. 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 - 'c 1 2' copy row 1 to 2 - 'd 3' delete row 3 The 'outp' tab is for debugging outputs via 'print' The 'notes' tab for your notes. The controller needs battery power to work. The battery pack has to be placed near the controller (1 node distance). The needed battery power is directly dependent on the CPU time the controller consumes. For more information, see: goo.gl/fF5ap6 ]] -- to simplify the search for a pressed main form button (condition/action) local lButtonKeys = {} for idx = 1,smartline.NUM_RULES do lButtonKeys[#lButtonKeys+1] = "cond"..idx lButtonKeys[#lButtonKeys+1] = "actn"..idx end local function buttons(s) return "button_exit[7.4,7.5;1.8,1;cancel;Cancel]".. "button[9.3,7.5;1.8,1;save;Save]".. "button[11.2,7.5;1.8,1;"..s.."]" end function smartline.formspecError(meta) local running = meta:get_int("state") == tubelib.RUNNING local cmnd = running and "stop;Stop" or "start;Start" local init = meta:get_string("init") init = minetest.formspec_escape(init) return "size[4,3]".. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "label[0,0;No Battery?]".. "button[1,2;1.8,1;start;Start]" end local function button(data) if data then return data.button else return "..." 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.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.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 function smartline.store_main_form_data(meta, fields) local fs_data = minetest.deserialize(meta:get_string("fs_data")) for idx = 1,smartline.NUM_RULES do fs_data[idx].cycle = fields["cycle"..idx] or "" fs_data[idx].after = fields["after"..idx] or "0" end meta:set_string("fs_data", minetest.serialize(fs_data)) end function smartline.main_form_button_pressed(fields) for _,key in ipairs(lButtonKeys) do if fields[key] then return key end end return nil end function smartline.formspecSubMenu(meta, key) local fs_data = minetest.deserialize(meta:get_string("fs_data")) if key:sub(1,4) == "cond" then local row = tonumber(key:sub(5,5)) return smartline.cond_formspec(row, fs_data[row].cond) else local row = tonumber(key:sub(5,5)) return smartline.actn_formspec(row, fs_data[row].actn) end end function smartline.formspec_button_update(meta, fields) local fs_data = minetest.deserialize(meta:get_string("fs_data")) local row = tonumber(fields._row_ or 1) if fields._col_ == "cond" then fs_data[row].cond = smartline.cond_eval_input(fs_data[row].cond, fields) elseif fields._col_ == "actn" then fs_data[row].actn = smartline.actn_eval_input(fs_data[row].actn, fields) end meta:set_string("fs_data", minetest.serialize(fs_data)) end function smartline.cond_formspec_update(meta, fields) local fs_data = minetest.deserialize(meta:get_string("fs_data")) local row = tonumber(fields._row_ or 1) fs_data[row].cond = smartline.cond_eval_input(fs_data[row].cond, fields) meta:set_string("formspec", smartline.cond_formspec(row, fs_data[row].cond)) meta:set_string("fs_data", minetest.serialize(fs_data)) end function smartline.actn_formspec_update(meta, fields) local fs_data = minetest.deserialize(meta:get_string("fs_data")) local row = tonumber(fields._row_ or 1) fs_data[row].actn = smartline.actn_eval_input(fs_data[row].actn, fields) meta:set_string("formspec", smartline.actn_formspec(row, fs_data[row].actn)) meta:set_string("fs_data", minetest.serialize(fs_data)) end function smartline.formspecRules(meta, fs_data, output) local running = meta:get_int("state") == tubelib.RUNNING local cmnd = running and "stop;Stop" or "start;Start" local init = meta:get_string("init") init = minetest.formspec_escape(init) return SIZE.. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "tabheader[0,0;tab;rules,outp,notes,help;1;;true]".. formspec_rules(fs_data).. "label[0.2,7.0;"..output.."]".. "field[0.3,7.8;4,1;cmnd;;]".. "button[4.0,7.5;1.5,1;go;GO]".. buttons(cmnd) end function smartline.formspecOutput(meta) local running = meta:get_int("state") == tubelib.RUNNING local cmnd = running and "stop;Stop" or "start;Start" local output = meta:get_string("output") output = minetest.formspec_escape(output) return SIZE.. default.gui_bg.. default.gui_bg_img.. 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.."]" end function smartline.formspecNotes(meta) local running = meta:get_int("state") == tubelib.RUNNING local cmnd = running and "stop;Stop" or "start;Start" local notes = meta:get_string("notes") or "" if notes == "" then notes = "" end notes = minetest.formspec_escape(notes) return SIZE.. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "tabheader[0,0;tab;rules,outp,notes,help;3;;true]".. "textarea[0.3,0.2;13,8.3;notes;Notepad:;"..notes.."]".. buttons(cmnd) end function smartline.formspecHelp(offs) return SIZE.. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "tabheader[0,0;tab;rules,outp,notes,help;4;;true]".. "field[0,0;0,0;_type_;;help]".. "label[0,"..(-offs/50)..";"..sHELP.."]".. --"label[0.2,0;test]".. "scrollbar[12,1;0.5,7;vertical;sb_help;"..offs.."]" end