--[[ ICTA Controller =============== Part of the SmartLine mod Copyright (C) 2017-2020 Joachim Stolberg AGPL v3 See LICENSE.txt for more information submenu.lua A sub-menu control to generate a formspec sting for conditions and actions ]]-- local sl = smartline local function index(list, x) for idx, v in ipairs(list) do if v == x then return idx end end return nil end -- generate the choice dependent part of the form local function add_controls_to_table(tbl, kvDefinition, kvSelect) local val = "" local offs = 1.4 if kvDefinition[kvSelect.choice] then local lControls = kvDefinition[kvSelect.choice].formspec for idx,elem in ipairs(lControls) do 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 + 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 + 0.9 end end end return tbl end local function default_data(kvDefinition, kvSelect) local lControls = kvDefinition[kvSelect.choice].formspec for idx,elem in ipairs(lControls) do kvSelect[elem.name] = elem.default end kvSelect.button = kvDefinition[kvSelect.choice].button(kvSelect) return kvSelect end -- Copy field/formspec data to the table kvSelect -- kvDefinition: submenu formspec definition -- kvSelect: form data -- fields: formspec input local function field_to_kvSelect(kvDefinition, kvSelect, fields) local error = false local lControls = kvDefinition[kvSelect.choice].formspec for idx,elem in ipairs(lControls) do if elem.type == "numbers" then if fields[elem.name] then if fields[elem.name]:find("^[%d ]+$") then kvSelect[elem.name] = fields[elem.name] else kvSelect[elem.name] = elem.default error = true end end elseif elem.type == "digits" then -- including positions if fields[elem.name] then if fields[elem.name]:find("^[+%%-,%d]+$") then kvSelect[elem.name] = fields[elem.name] else kvSelect[elem.name] = elem.default error = true end end elseif elem.type == "letters" then if fields[elem.name] then if fields[elem.name]:find("^[+-]?%a+$") then kvSelect[elem.name] = fields[elem.name] else kvSelect[elem.name] = elem.default error = true end end elseif elem.type == "ascii" then if fields[elem.name] then kvSelect[elem.name] = fields[elem.name] end elseif elem.type == "textlist" then if fields[elem.name] ~= nil then kvSelect[elem.name] = fields[elem.name] end end end -- store user input of button text if fields._button_ then kvSelect._button_ = fields._button_ end -- select button text if error then kvSelect.button = "invalid" elseif kvSelect._button_ and kvSelect._button_ ~= "" then kvSelect.button = kvSelect._button_ else kvSelect.button = kvDefinition[kvSelect.choice].button(kvSelect) end return kvSelect end function smartline.submenu_verify(kvDefinition, kvSelect) local error = false local lControls = kvDefinition[kvSelect.choice].formspec for idx,elem in ipairs(lControls) do if elem.type == "numbers" then if not kvSelect[elem.name]:find("^[%d ]+$") then error = true end elseif elem.type == "digits" then -- including positions if not kvSelect[elem.name]:find("^[+%%-,%d]+$") then error = true end elseif elem.type == "letters" then if not kvSelect[elem.name]:find("^[+-]?%a+$") then error = true end elseif elem.type == "ascii" then if kvSelect[elem.name] == "" or kvSelect[elem.name] == nil then error = true end elseif elem.type == "textlist" then if kvSelect[elem.name] == "" or kvSelect[elem.name] == nil then error = true end end end return (error == false) end -- generate a formspec string from the given control definition -- row, col: numbers to identify the control -- title: Title text for the control -- lKeys: list of keywords of selected choices according to fields -- lChoice: list of possible choices for the control -- kvDefinition: definitions of the choice dependent controls -- kvSelect: data of the last selected item {choice, number, value, ...} function smartline.submenu_generate_formspec(row, col, title, lKeys, lChoice, kvDefinition, kvSelect) if kvSelect == nil or next(kvSelect) == nil then kvSelect = {choice = "default"} end local tbl = {"size[8.2,9]".. default.gui_bg.. default.gui_bg_img.. default.gui_slots.. "field[0,0;0,0;_row_;;"..row.."]".. "field[0,0;0,0;_col_;;"..col.."]"} local sChoice = table.concat(lChoice, ",") local idx = index(lKeys, kvSelect.choice) or 1 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_;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) end -- return the selected and configured menu item based on user inputs (fields) function smartline.submenu_eval_input(kvDefinition, lKeys, lChoice, kvSelect, fields) -- determine selected choice if fields.choice then -- load with default values local idx = index(lChoice, fields.choice) or 1 kvSelect = {choice = lKeys[idx]} kvSelect = default_data(kvDefinition, kvSelect) kvSelect = field_to_kvSelect(kvDefinition, kvSelect, fields) else -- add real data kvSelect = field_to_kvSelect(kvDefinition, kvSelect, fields) end return kvSelect end